Widget小元件如何自適應高度

xDEHANG發表於2019-02-12

OneSwift - iOS Tips Based On Swift

一位使用者@NaThan INN 反饋了關於Widget小元件的Bug,他提到日期的一行文字無法顯示,後來又收到一位使用者反饋了同樣的問題。

Widget小部件顯示日期異常

我在手機上試了很多次,在模擬器上也試過了,都無法找出是什麼問題。後來我發現使用者給的截圖中,字型的大小和模擬器上有些差別,通過對系統設定字型大小,我發現了問題的根源。

因為開發之初將cell的高定位了固定的55,但是這個值隨著系統字型大小的設定,影響了解析度的處理,Cell在不同的系統字型下有不同的高度。

解決方案:將固定高度改為自適應高度。

方案策略:摺疊狀態下的高度作為自適應的參考高度。

第一步:檢測Widget的摺疊和展開

Class中新增 NCWidgetProviding,同時新增一個儲存高度的變數cellHeight。這樣才能檢測Widget的狀態,同時獲取高度儲存後使用。

第二步:獲取Widget總體高度

具體程式碼如下,其中NCWidgetDisplayMode.compact表示摺疊狀態,NCWidgetDisplayMode.expanded表示展開狀態。

在OneDay中,摺疊狀態只顯示兩行,所以每個Cell的高度為總體高的的1/2,也就是maxSize.height/2,同時這個高度會作為展開狀態下其他Cell的高度。

當然,這個函式中我還順便把展開狀態的高度做了,根據資料的個數去計算高度。

//摺疊change size

func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize) {

    if activeDisplayMode == NCWidgetDisplayMode.compact {

    self.preferredContentSize = CGSize(width:maxSize.width,height: maxSize.height)

    self.activeDisplayIndex = 0

    self.cellHeight = Int(maxSize.height/2)

    print("cellHeight",self.cellHeight)

        }else{

    let hei = CGFloat((self.cellHeight * self.number)+self.cellHeight+5)

    self.preferredContentSize = CGSize(width: maxSize.width,height:hei )

    self.activeDisplayIndex = 1

    print("cellHeight",self.cellHeight)

        }

//        self.eventsTable.reloadData()

}
複製程式碼

第三步:給Tableview載入高度

獲取高度之後來使用就很簡單了,直接用heightForRowAt。

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

        return CGFloat(self.cellHeight)

}
複製程式碼

第四步:注意事項和重新載入

注意要給 cellHeight一個初始值,一般推薦50~55;

var cellHeight:Int = 50
複製程式碼

因為widget通常是載入好的,所以在viewWillAppear中加入tableviewreloadData方法,以便在使用者改變系統字型後隨時改變。

self.eventsTable.reloadData()
複製程式碼

最後:看看效果

系統最大字型和最小字型的適配結果對比

其實,Widget小元件自適應的效果,看了幾個應用都沒有處理得很好,往往容易被忽視。我手機裡的應用,workflow應該也是這樣類似的解決方案,以便應對系統字型設定帶來widget適配問題。

最後,感謝NaThan INN使用者的反饋,不然真的很難發現,這項特性將在OneDay 2.4.0版本中正式釋出。

GitHub:OneSwift - iOS Tips Based On Swift

微博:xDEHANG

相關文章