如果您正在编写自己的配置,则您负责其属性。所以让你的配置定义一个协议并给它一个delegate
属性!单元注册对象将视图控制器(或任何人)设置为配置的委托。内容视图配置 UISwitch 或任何向它发出信号的内容视图,内容视图将该信号传递给配置的委托。
一个工作示例
这是一个工作示例的完整代码。我选择使用表格视图而不是集合视图,但这完全不相关;内容配置适用于两者。
您需要做的就是在视图控制器中放置一个表视图,使视图控制器成为表视图的数据源,并使表视图成为视图控制器的tableView
.
extension UIResponder {
func next<T:UIResponder>(ofType: T.Type) -> T? {
let r = self.next
if let r = r as? T ?? r?.next(ofType: T.self) {
return r
} else {
return nil
}
}
}
protocol SwitchListener : AnyObject {
func switchChangedTo(_:Bool, sender:UIView)
}
class MyContentView : UIView, UIContentView {
var configuration: UIContentConfiguration {
didSet {
config()
}
}
let sw = UISwitch()
init(configuration: UIContentConfiguration) {
self.configuration = configuration
super.init(frame:.zero)
sw.translatesAutoresizingMaskIntoConstraints = true
self.addSubview(sw)
sw.center = CGPoint(x:self.bounds.midX, y:self.bounds.midY)
sw.autoresizingMask = [.flexibleTopMargin, .flexibleBottomMargin, .flexibleLeftMargin, .flexibleRightMargin]
sw.addAction(UIAction {[unowned sw] action in
(configuration as? Config)?.delegate?.switchChangedTo(sw.isOn, sender:self)
}, for: .valueChanged)
config()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func config() {
self.sw.isOn = (configuration as? Config)?.isOn ?? false
}
}
struct Config: UIContentConfiguration {
var isOn = false
weak var delegate : SwitchListener?
func makeContentView() -> UIView & UIContentView {
return MyContentView(configuration:self)
}
func updated(for state: UIConfigurationState) -> Config {
return self
}
}
class ViewController: UIViewController, UITableViewDataSource {
@IBOutlet var tableView : UITableView!
var list = Array(repeating: false, count: 100)
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
var config = Config()
config.isOn = list[indexPath.row]
config.delegate = self
cell.contentConfiguration = config
return cell
}
}
extension ViewController : SwitchListener {
func switchChangedTo(_ newValue: Bool, sender: UIView) {
if let cell = sender.next(ofType: UITableViewCell.self) {
if let ip = self.tableView.indexPath(for: cell) {
self.list[ip.row] = newValue
}
}
}
}
该示例的关键部分
好的,它可能看起来很多,但对于任何具有自定义内容配置的表视图来说,它主要是纯粹的样板。唯一有趣的部分是 SwitchListener 协议及其实现,以及addAction
内容视图的初始化程序中的行;这就是这个答案的第一段描述的东西。
因此,在内容视图的初始化程序中:
sw.addAction(UIAction {[unowned sw] action in
(configuration as? Config)?.delegate?.switchChangedTo(sw.isOn, sender:self)
}, for: .valueChanged)
在扩展中,响应该调用的方法:
func switchChangedTo(_ newValue: Bool, sender: UIView) {
if let cell = sender.next(ofType: UITableViewCell.self) {
if let ip = self.tableView.indexPath(for: cell) {
self.list[ip.row] = newValue
}
}
}
另一种方法
该答案仍然使用协议和委托架构,并且 OP 宁愿不这样做。现代方法是提供一个属性,其值是可以直接调用的函数。
因此,我们没有给我们的配置一个委托,而是给它一个回调属性:
struct Config: UIContentConfiguration {
var isOn = false
var isOnChanged : ((Bool, UIView) -> Void)?
内容视图的初始化程序配置接口元素,以便在它发出信号时isOnChanged
调用该函数:
sw.addAction(UIAction {[unowned sw] action in
(configuration as? Config)?.isOnChanged?(sw.isOn, self)
}, for: .valueChanged)
剩下的只是显示isOnChanged
功能是什么。在我的示例中,它与之前架构中的委托方法完全相同。所以,当我们配置单元格时:
config.isOn = list[indexPath.row]
config.isOnChanged = { [weak self] isOn, v in
if let cell = v.next(ofType: UITableViewCell.self) {
if let ip = self?.tableView.indexPath(for: cell) {
self?.list[ip.row] = isOn
}
}
}
cell.contentConfiguration = config