Swift UIKit 可拖拉按鈕,UIButton-UIPanGestureRecognizer、buttonPressed、buttonReleased
Published in
6 min readJul 15, 2024
# move the button
在觸發按鈕時,可以選擇或是buttonTapped
或是buttonPressed、buttonReleased
。
我會選擇buttonPressed
、buttonReleased
。是因為按下去會改變按鈕顏色。對只是這樣的原因。
但是UIPanGestureRecognizer跟buttonPressed、buttonReleased需要設條件去『分別啟動』,不然他們會打架,會有一方輸然後躺在地上不動…
我的整體思路:
建立按鈕 > 加入UIPanGestureRecognizer > 設定要幾指移動、移動範圍 > 移動結束後如有按按鈕 > 再加入並連接到buttonPressed、buttonReleased
以下是程式碼:
// 創建按鈕
circularButton = UIButton(type: .custom)
// 設置按鈕大小
circularButton.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
// 設置按鈕圓形
circularButton.layer.cornerRadius = 22 // 4ˋ的一半
circularButton.clipsToBounds = true
// 設置按鈕圖片填滿模式
circularButton.imageView?.contentMode = .scaleToFill
// 設置按鈕位置,在螢幕中央的最下方
circularButton.center = CGPoint(x: view.bounds.midX, y: view.bounds.maxY - 44 / 2 - 20) // 20 是距離底部的距離,可以根據需要調整
// 添加按鈕點擊事件,拖動手勢識別器
circularButton.addTarget(self, action: #selector(buttonPressed), for: .touchDown)//暫時沒寫功能但保留
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
circularButton.addGestureRecognizer(panGestureRecognizer)
@objc func buttonPressed(_ sender: UIButton) {
//按鈕按下去時的動作,可以設定換圖片,換顏色...
}
@objc func buttonReleased(_ sender: UIButton) {
// 放開按鈕後的動作
}
// 處理拖動的方法
@objc func handlePan(_ recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translation(in: view)
if let button = recognizer.view {
var newCenter = CGPoint(x: button.center.x + translation.x, y: button.center.y + translation.y)
// 限制按鈕的寬位置不超出父視圖的邊界
let halfWidth = button.frame.width / 2
newCenter.x = max(halfWidth, newCenter.x)
newCenter.x = min(view.bounds.size.width - halfWidth, newCenter.x)
//限制按鈕高度
let screenHeight = UIScreen.main.bounds.height
let halfHeight = button.frame.height / 2
//按鈕要低於navigationBar
let navigationBarHeight = navigationController?.navigationBar.frame.size.height ?? 44
//且低於狀態欄
let statusBarHeight = UIApplication.shared.statusBarFrame.height
//且低於searchBar,下條件是為了調整按鈕在小螢幕(iphoneSE)上的狀態
var searchBarHeight = 22
if screenHeight < 852{
searchBarHeight = 55
}else{
searchBarHeight = 22
}
newCenter.y = max(halfHeight + navigationBarHeight + statusBarHeight + CGFloat(searchBarHeight), newCenter.y) // 將導航欄和狀態欄高度納入計算
newCenter.y = min(view.bounds.size.height - halfHeight - 10, newCenter.y)
// 更新按鈕的中心位置
button.center = newCenter
}
recognizer.setTranslation(CGPoint.zero, in: view) // 重置拖動距離
//判斷是否完成拖拽,決定是否要啟動buttonReleased
if recognizer.state == .ended {
circularButton.addTarget(self, action: #selector(buttonReleased), for: [.touchUpInside, .touchUpOutside, .touchCancel])
} else if recognizer.state == .began {
circularButton.removeTarget(self, action: #selector(buttonReleased), for: [.touchUpInside, .touchUpOutside, .touchCancel])
}
}
參考資料
寫程式就是要腦洞大開,想到什麼路就試試看,一切皆有可能。