如何用Swift Visual Format Language实现四个按钮居中布局?
用VFL实现中心环绕的计算器按钮布局
嘿,我明白你想做的事——不用硬编码坐标、不用栈视图,纯靠VFL让四个运算按钮围绕父视图中心排列,还能自适应缩放对吧?先说说你现有代码的问题:之前的约束把按钮绑到了父视图的左右和底部,没和父视图中心关联,而且没给按钮设置固定宽高,所以才会出现拉伸或者位置偏离的情况。
下面是修改后的完整代码,我会一步步解释关键改动:
@IBDesignable class CalculatorButtonContainer: UIButton { override init(frame: CGRect) { super.init(frame: frame) setupCalcButtons() } required init?(coder: NSCoder) { super.init(coder: coder) setupCalcButtons() } private func setupCalcButtons() { // 创建四个运算按钮,抽离重复逻辑 let calcPlus = createCalcButton(title: "+") let calcSubtract = createCalcButton(title: "-") let calcMultiply = createCalcButton(title: "x") let calcDivide = createCalcButton(title: "/") addSubview(calcPlus) addSubview(calcSubtract) addSubview(calcMultiply) addSubview(calcDivide) // 定义布局常量:按钮大小、间距(可按需调整) let metrics = ["btnSize": 60, "spacing": 20] let views = [ "calcPlus": calcPlus, "calcSubtract": calcSubtract, "calcMultiply": calcMultiply, "calcDivide": calcDivide ] // 1. 给按钮设置固定宽高,避免拉伸 NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:[calcPlus(btnSize)]", metrics: metrics, views: views)) NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:[calcPlus(btnSize)]", metrics: metrics, views: views)) // 让其他按钮和calcPlus等宽等高,保证统一尺寸 NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:[calcSubtract(==calcPlus)]", views: views)) NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:[calcSubtract(==calcPlus)]", views: views)) NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:[calcMultiply(==calcPlus)]", views: views)) NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:[calcMultiply(==calcPlus)]", views: views)) NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:[calcDivide(==calcPlus)]", views: views)) NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:[calcDivide(==calcPlus)]", views: views)) // 2. 水平布局:上下两行按钮分别居中,按钮间保持20pt间距 // 上面一行(+、-)水平居中,>=0保证父视图缩小时按钮不被挤压 NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-(>=0)-[calcPlus]-(spacing)-[calcSubtract]-(>=0)-|", options: [.alignAllCenterY, .centerHorizontally], metrics: metrics, views: views)) // 下面一行(x、/)水平居中 NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-(>=0)-[calcMultiply]-(spacing)-[calcDivide]-(>=0)-|", options: [.alignAllCenterY, .centerHorizontally], metrics: metrics, views: views)) // 3. 垂直布局:两行按钮围绕父视图中心排列,行间距20pt NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|-(>=0)-[calcPlus]-(spacing)-[calcMultiply]-(>=0)-|", options: [.alignAllCenterX, .centerVertically], metrics: metrics, views: views)) } // 抽离按钮创建逻辑,减少重复代码 private func createCalcButton(title: String) -> UIButton { let button = UIButton() button.translatesAutoresizingMaskIntoConstraints = false button.setTitle(title, for: .normal) button.setTitleColor(.black, for: .normal) button.setTitleColor(.white, for: .highlighted) button.backgroundColor = .orange return button } }
关键改动说明:
- 抽离按钮创建逻辑:把重复的按钮初始化代码放到
createCalcButton方法里,让代码更整洁易维护。 - 固定按钮尺寸:用VFL给按钮设置固定宽高,同时让其他按钮和第一个按钮等宽等高,彻底解决按钮拉伸问题。
- 水平居中布局:通过
H:|-(>=0)-[btn1]-(spacing)-[btn2]-(>=0)-|的VFL配合.centerHorizontally选项,让按钮行自动在父视图水平居中,>=0的约束保证父视图缩小时按钮不会被挤压变形。 - 垂直中心关联:用
V:|-(>=0)-[topBtn]-(spacing)-[bottomBtn]-(>=0)-|的VFL配合.centerVertically选项,让两行按钮围绕父视图垂直中心排列,行间距始终保持20pt。
这样调整后,不管父视图怎么缩放,四个按钮都会始终围绕中心排列,间距和尺寸保持一致,完全符合你要的自适应效果,而且全程用VFL实现,没有直接创建NSLayoutConstraint。
内容的提问来源于stack exchange,提问作者Gabby
相关产品推荐
相关产品推荐

