Swift 3中用约束实现UIButton图片始终居右的问题求助
嘿,我碰到过类似的情况,咱们来一步步搞定这个问题!
问题原因
你当前的代码遇到的问题,主要是因为UIButton内部有自己的布局逻辑:当按钮没有文本时,它的contentHorizontalAlignment默认是.center或者.leading,会自动调整imageView的位置,而你直接给imageView加的约束和按钮自身的布局逻辑冲突了。另外,用button.imageView!.frame.width来设置宽度约束也不靠谱——因为在布局完成前,frame的数值可能不是最终的真实尺寸。
解决方案一:利用UIButton内置属性(最简单)
不需要复杂的Auto Layout,直接用按钮的内置布局属性就能搞定,这种方法兼容性更好,也不容易出冲突:
class func setImageToRight(button: UIButton) { // 翻转内容布局,让图片在文字右侧 button.semanticContentAttribute = .forceRightToLeft // 让内容整体靠右对齐 button.contentHorizontalAlignment = .right // 调整图片和文字的间距(根据需求改数值) let spacing: CGFloat = 8.0 button.imageEdgeInsets = UIEdgeInsets(top: 0, left: spacing, bottom: 0, right: -spacing) button.titleEdgeInsets = UIEdgeInsets(top: 0, left: -spacing, bottom: 0, right: spacing) // 没有文字时,确保图片和右侧保持间距 button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 8.0) }
原理说明:
semanticContentAttribute = .forceRightToLeft:让按钮的内容(图片+文字)整体翻转顺序,图片自然到了文字右边contentHorizontalAlignment = .right:强制所有内容靠右对齐,哪怕没有文字,图片也会紧贴右侧(加上contentEdgeInsets的间距)- 调整
imageEdgeInsets和titleEdgeInsets是为了让图片和文字之间保持合适的间距,避免重叠
解决方案二:正确的Auto Layout约束方法
如果你一定要用Auto Layout,得注意约束的对象和顺序,还要避免和按钮自身布局逻辑冲突:
class func setImageToRightWithAutoLayout(button: UIButton) { guard let imageView = button.imageView else { return } // 先关闭自动转换约束,这一步必须在添加新约束之前做! imageView.translatesAutoresizingMaskIntoConstraints = false // 移除之前的约束,防止重复添加导致冲突 NSLayoutConstraint.deactivate(imageView.constraints) // 约束到button的contentView(而不是button本身),因为imageView是在contentView里的 NSLayoutConstraint.activate([ imageView.trailingAnchor.constraint(equalTo: button.contentView.trailingAnchor, constant: -8.0), imageView.centerYAnchor.constraint(equalTo: button.contentView.centerYAnchor), // 用intrinsicContentSize获取图片的真实尺寸,比frame靠谱 imageView.widthAnchor.constraint(equalToConstant: imageView.intrinsicContentSize.width), imageView.heightAnchor.constraint(equalToConstant: imageView.intrinsicContentSize.height) ]) // 如果按钮有文字,也要约束标题的位置 if let titleLabel = button.titleLabel { titleLabel.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.deactivate(titleLabel.constraints) NSLayoutConstraint.activate([ titleLabel.leadingAnchor.constraint(equalTo: button.contentView.leadingAnchor, constant: 8.0), titleLabel.centerYAnchor.constraint(equalTo: button.contentView.centerYAnchor), // 标题和图片之间的间距 titleLabel.trailingAnchor.constraint(equalTo: imageView.leadingAnchor, constant: -8.0) ]) } // 让按钮的内容填充整个空间,确保约束生效 button.contentHorizontalAlignment = .fill }
关键改进点:
- 约束对象从
button改成了button.contentView——UIButton的imageView和titleLabel都是放在contentView里的,直接约束到button会和内部布局冲突 - 先设置
translatesAutoresizingMaskIntoConstraints = false,再添加新约束,顺序不能错 - 用
intrinsicContentSize获取图片的真实尺寸,避免布局前frame数值不准确的问题 - 设置
contentHorizontalAlignment = .fill,让按钮的内容区域填满整个按钮,确保我们的约束能完全控制位置
总结
推荐用解决方案一,因为它利用了UIButton的原生布局逻辑,代码更简洁,也不容易出现奇怪的布局冲突。如果你的场景必须用Auto Layout,再考虑方案二。
内容的提问来源于stack exchange,提问作者Amit Chauhan
相关产品推荐
相关产品推荐

