Swift。ExpandableButton展開式按鈕

Yuwen Chiu
Swift。隨筆
Published in
6 min readJul 4, 2020

不知不覺已經很久沒發文了🙇🏻‍♀️今天打起精神來分享一個小功能 “展開式按鈕”,之前工作上有製作需求所以就研究了一下,在這邊記錄下來也方便自己未來可以參考,如果有興趣就一起看下去吧🥳

開始之前先梳理一下展開式按鈕需要什麼效果。

● 有一顆 ControlButton,點擊後展開其他 ToolButton,再點一次就收合
● 展開、收合時,ControlButton 顯示不同圖片或文字
● 展開、收合時,ToolButton 都要有動畫
● 展開時背景反灰;收合時背景還原
● 每個 ToolButton 都有自己的功能

因為我想把展開式按鈕當成一個工具包來使用,所以把相關內容都包在一個 View 裡面,不只方便 Reuse 程式碼看起來也簡潔許多,使用時不容易混亂更容易維護。那我們就開始吧💪🏻💪🏻💪🏻

使用情境 { WebView側邊有一顆ControlButton,點擊後展開ToolButton。 }

1. 新增繼承 UIView 的 CocoaTouchClass

2. 定義相關 Property

isExpanded用來判斷目前狀態是展開或收合。

3. 設計 func setupShadowView()

反灰的背景 View 預設 alpha = 0 也就是完全透明,當按鈕展開時才會顯示顏色。這邊加上一個 TapGesture,當按鈕展開時點擊背景等同於點擊 ControlButton 會收合按鈕。

4. 設計 func setupButtons(buttonTitles: [String])

我用簡單的 buttonTitles: [String] 傳入 func 來決定要有幾顆 ToolButton,也可以使用自訂型別讓傳入的值帶更多資料,例如:

public class ButtonInfo {

var title: String!
var imURL: String!
var link: String!

convenience init(title: String, imURL: String, link: String) {
self.init()
self.title = title
self.imURL = imURL
self.link = link
}
}
func setupButtons(buttonList: [ButtonInfo])

可以依照自己的功能需求調整囉!

ToolButton 和 ControlButton 在這邊都是設定起始位置,也就是收合狀態的位置,展開狀態的位置會在點擊 ControlButton 事件處理。起始位置要在哪裡也可以自行變化唷~

設定 tag 值的用意是用來判斷 ToolButton 的順序,後面會再提到。

另外想提一個小事情,ControlButton 在 ToolButton 後面才 add 是因為我想讓 ToolButton 看起來是從 ControlButton 後面長出來而不是正面。一開始我寫相反視覺效果就怪怪的😂

5. 設計 func setButtonStyle(button: UIButton)

所有按鈕我都想刻成圓形而且有陰影,用這個 func 設定方便 reuse。

6. 定義 onTouchControlButton 點擊事件

首先最重要的 isExpanded 狀態要改變,預設為 false 第一次點擊變成 true,之後每次點擊都會反轉,方便用來判斷其他元件目前要顯示什麼。

第一個變化的是 ShadowView,展開時有顏色;收合時為透明。

第二個變化的是 ToolButtons,展開時往上長;收合時回起點。ToolButton 的 y 座標 -100 是減掉 ControlButton 的位置,再依照先前存的 tag 值按順序乘上距離展開。

第三個變化的是 ControlButton,展開和收合時分別顯示不同的文字、顏色、背景。

7. 定義 onTouchToolButton 點擊事件

點擊 ToolButton 時也需要改變反灰背景和收合按鈕,所以等同於點擊 ControlButton。

接著透過 delegate 將點擊的按鈕資訊回傳到使用 ExpandableButtonView 工具的 ViewController,這裡只簡單地用回傳 String 來示意,可以像上面提過的用自訂型別讓這個工具更靈活。

8. 定義傳遞資料的 delegate

之前我寫過一篇關於 delegate 的文章,不過當時還沒有認知到 ARC 和 MemoryLeak,所以相對不那麼安全,現在開始用安全的寫法吧!其實只要在 protocol 後面加關鍵字 class,就可以將 delegate 變成弱型別,另外要注意 weak property 一定要是 optional 唷!

參考資源:

9. 在 ViewController 使用 ExpandableButtonView

ExpandableButtonView 設定好後,記得把 delegate 指向 ViewController,然後 ViewController 要遵從 ExpandableButtonViewDelegate 並實作 func。

10. 關鍵的 override func hitTest

以上 9 個步驟寫完 Run 起來看很正常,但 ViewController 的 WebView 完全無法滑動,因為被 ExpandableButtonView 的 ShadowView 擋住了!所以在 ExpandableButtonView 要多寫一個 override func hitTest,控制哪一個 View 可以被點選。

參考資源:

這次的 ExpandableButtonView 工具包就先告一段落啦!之後可能會陸續記錄一些我寫過的小工具,希望我不會偷懶🥴以上如果有任何錯誤或是建議歡迎大家留言給我~

有興趣可以取用我的檔案🙆🏻‍♀️

--

--