可能是全網第一個適配iOS靈動島的Toast庫-JFPopup

語言: CN / TW / HK

我報名參加金石計劃1期挑戰——瓜分10萬獎池,這是我的第2篇文章,點擊查看活動詳情

前言

我去年的一篇文章詳細的介紹了我編寫的一套Swift彈窗組件庫一個優雅的Swift彈窗組件-JFPopup。裏面適配了一套ToastView,恰逢今年蘋果iPhone14 Pro以上系列新出了一套靈動島的交互風格,所以就意外想到能否把ToastView也適配進去靈動島,所以此文就應運而生。我上篇文章已經很詳細的介紹了JFPopup具體用法,這篇文章主要講解適配靈動島的心路歷程。

具體效果:

用法

雖然我上篇文章已經介紹了一遍,這裏我還是再寫一下。另外靈動島Toast默認適配iPhone14 Pro以上機型,無需另外操作,若不是靈動島機型,則是默認居中,還支持top及bottom。更多詳細參數請看一個優雅的Swift彈窗組件-JFPopup

Toast:

```

//默認僅文案

JFPopupView.popup.toast(hit: "默認toast,支持靈動島")

//帶logo ,內置success or fail

JFPopupView.popup.toast(hit: "支付成功", icon: .success)

JFPopupView.popup.toast(hit: "支付失敗", icon: .fail)

//自定義logo

JFPopupView.popup.toast(hit: "自定義", icon: .imageName(name: "face"))

```

Loading:

```

DispatchQueue.main.async {

JFPopupView.popup.loading()

}

DispatchQueue.main.asyncAfter(deadline: .now() + 3) {

JFPopupView.popup.hideLoading()

JFPopupView.popup.toast(hit: "刷新成功")

}

```

適配靈動島具體過程

由於蘋果官方已經説了要在下半年推出的ActivityKit才會加入適配靈動島的Api。所以目前並沒有官方的api可以給我們適配。所以只能硬着頭皮自己去思考適配方案了。

- 首先要知道靈動島的區域大小

我們用最笨的方法,直接給模擬器截個圖自己去算大小。至少能還原99%的效果了。如圖得知,靈動島的區域大概是寬120dt,高34dp,那半圓圓角自然為17dt。居頂部大約10dp,以及在屏幕居中。有了這些信息,我們自然就能模擬靈動島的放大縮小轉場效果了。

- ToastView新增靈動島動畫

我們在原先基礎上新增靈動島動畫枚舉

```

public enum JFToastPosition {

case center

case top

case bottom

case dynamicIsland //新增靈動島位置動畫

}

```

重新實現下present 及 dismiss協議的轉場動畫代碼如下

展開:

```

let originSize = contianerView.jf.size

if config.toastPosition == .dynamicIsland {

contianerView.jf_size = CGSize(width: 120, height: 34)

contianerView.center = CGPoint(x: CGSize.jf.screenSize().width / 2, y: 27)

}

let updateV = {

contianerView.center = CGPoint(x: CGSize.jf.screenSize().width / 2, y: CGSize.jf.screenSize().height / 2)

if config.toastPosition == .top {

contianerView.jf_top = CGFloat.jf.navigationBarHeight() + 15

} else if config.toastPosition == .bottom {

contianerView.jf_bottom = CGSize.jf.screenHeight() - CGFloat.jf.safeAreaBottomHeight() - 15

} else if config.toastPosition == .dynamicIsland {

contianerView.jf_size = originSize

contianerView.center = CGPoint(x: CGSize.jf.screenSize().width / 2, y: originSize.height / 2 + 10)

}

contianerView.layoutIfNeeded()

}

guard config.withoutAnimation == false else {

updateV()

transitonContext?.completeTransition(true)

completion?(true)

return

}

if config.toastPosition == .dynamicIsland {

UIView.animate(withDuration: 0.25) {

updateV()

} completion: { finished in

transitonContext?.completeTransition(true)

completion?(finished)

}

return

}

```

消失:

```

UIView.animate(withDuration: 0.25, animations: {

if config.toastPosition == .dynamicIsland {

contianerView?.layer.cornerRadius = 17

contianerView?.jf_size = CGSize(width: 120, height: 34)

contianerView?.center = CGPoint(x: CGSize.jf.screenSize().width / 2, y: 27)

}

contianerView?.subviews.forEach({ v in

if config.toastPosition == .dynamicIsland {

v.isHidden = true

} else {

v.alpha = 0

}

})

contianerView?.alpha = 0

}) { (finished) in

transitonContext?.completeTransition(true)

completion?(finished)

}

```

末尾

以上即是我JFPopup內置組件JFToastView適配靈動島動畫的全過程,假如下半年蘋果更新了Api我也會第一時間重新適配。