需求:
一个 testButton
按钮, 设置上normal
和 selected
状态下的 title
和 title
颜色, 在点击按钮时, 改变选中状态, title
随之改变, 不需要高亮状态.
当按钮处于选中状态时, 长按 testButton
不松手, 按钮显示 normal
状态对应的设置,
- 如果松开手, 那么按钮的
selected
状态将被改成false
, 一切正常; - 如果不松手,而是将手拖动至按钮范围之外, 按钮又会恢复到 选中状态, 实际此时按钮的选中状态并未改变, 还是
true
. 如何验证选中状态未改变呢 ? 可以在按钮点击方法中打个断点, 未松手前并没有进入方法.
这就有点不完美了. 体验就不好了, 特别是作为自定义 tabBar 按钮时, 明显不是我们想要的.
待解决的问题:
当处于选中状态时, 长按时不发生任何变化, 即不显示 normal
状态的设置, 只有当松开手执行了按钮点击方法, 选中状态被改变才显示对应的设置.
本案例只设置了不同状态的
title
和title
的颜色, 不同状态的图片也是一样的.
有问题的代码
import UIKit
class ViewController: UIViewController {
private lazy var testButton: UIButton = {
let btn = UIButton(type: .custom)
btn.backgroundColor = .gray
btn.frame = CGRect(x: 157, y: 300, width: 100, height: 40)
btn.titleLabel?.font = UIFont.systemFont(ofSize: 20)
btn.setTitle("normal", for: .normal)
btn.setTitleColor(.red, for: .normal)
btn.setTitle("selected", for: .selected)
btn.setTitleColor(.green, for: .selected)
btn.adjustsImageWhenHighlighted = false
btn.addTarget(self, action: #selector(btnAction(_ :)), for: .touchUpInside)
return btn
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(testButton)
}
@objc func btnAction(_ sender: UIButton) {
sender.isSelected.toggle()
}
}
如何解决这个问题呢
解决问题的方法很简单, 只要在按钮初始化中对 title
和 title
的颜色增加一个设置即可, 这个设置的内容同选中状态, 图片同理. 具体看代码:
let select = UIControl.State.selected.rawValue
let high = UIControl.State.highlighted.rawValue
btn.setTitle("selected", for: UIControl.State(rawValue: select | high))
btn.setTitleColor(.green, for: UIControl.State(rawValue: select | high))
首先来看看解决这个问题的全部条件:
- 1.按钮类型必须为:
.custom
. - 2.设置
选中 | 高亮
状态, 配置与选中
状态相同. - 3.必须禁用高亮状态:
btn.adjustsImageWhenHighlighted = false
.
分析原理:
前两条禁用的高亮状态, 大家应该都知道 ,这是福利, 下面说重点.
为什么这样设置就可以了呢 ?
我们来年看看 UIControl.State 这个枚举的定义:
Swift 定义
public struct State : OptionSet {
public init(rawValue: UInt)
public static var normal: UIControl.State { get }
public static var highlighted: UIControl.State { get } // used when UIControl isHighlighted is set
public static var disabled: UIControl.State { get }
public static var selected: UIControl.State { get } // flag usable by app (see below)
@available(iOS 9.0, *)
public static var focused: UIControl.State { get } // Applicable only when the screen supports focus
public static var application: UIControl.State { get } // additional flags available for application use
public static var reserved: UIControl.State { get } // flags reserved for internal framework use
}
Swift 中的定义看的不明显, 我们通过对这个值的打印, 不难猜到这是个 位枚举
.
OC的定义比较清楚.
typedef NS_OPTIONS(NSUInteger, UIControlState) {
UIControlStateNormal = 0,
UIControlStateHighlighted = 1 << 0, // used when UIControl isHighlighted is set
UIControlStateDisabled = 1 << 1,
UIControlStateSelected = 1 << 2, // flag usable by app (see below)
UIControlStateFocused API_AVAILABLE(ios(9.0)) = 1 << 3, // Applicable only when the screen supports focus
UIControlStateApplication = 0x00FF0000, // additional flags available for application use
UIControlStateReserved = 0xFF000000 // flags reserved for internal framework use
};
按钮的状态是位枚举,不是普通的枚举,也就是说按钮可以有不止一个状态。所以当按钮的selected
为 true
时,再点击的时候状态应该不是 normal
状态而是其他状态。
发现了相关的说明: UIButton UIControl state
也就是说. 选中状态的不同, 按钮的状态也是不同的, 具体可以分为四种状态:
- 在
selected == false
的时候,分别对应normal
和highlighted
- 在
selected == true
的时候,分别对应selected
和selected | highlighted
由以上的说明,出现按钮在
selected
为true
时,再次点击按钮的状态变成了normal
状态情况的原因:没有设置selected | highlighted
的状态,系统默认会显示normal
的状态
网友评论