简体   繁体   English

如何使可重用视图接受泛型类型

[英]How to make a reusable view accept generic types

I created a reusable control to be used in a project I'm working on.我创建了一个可重用的控件,用于我正在处理的项目中。 It's just a UITextField which shows a UIPickerView as its inputView .它只是一个UITextField ,它显示一个UIPickerView作为它的inputView

在此处输入图像描述

class InputPickerView: UIView {
    @IBOutlet private var view: UIView!
    @IBOutlet weak private var titleLabel: UILabel!
    @IBOutlet weak private var textField: UITextField!

    private(set) var pickerView = UIPickerView()

    var options: [String] = []

    var option: String {
        get {
            return textField.text ?? ""
        }
        set {
            textField.text = newValue
        }
    }

    var title: String = "" {
        didSet {
            titleLabel.text = title
        }
    }


    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    private func commonInit() {
        Bundle.main.loadNibNamed("InputPickerView", owner: self, options: nil)
        addSubview(view)
        view.frame = bounds
        view.autoresizingMask = [.flexibleHeight, .flexibleWidth]

        pickerView.dataSource = self
        pickerView.delegate = self
        textField.inputView = pickerView
    }
}

extension InputPickerView: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        return false
    }
}

extension InputPickerView: UIPickerViewDataSource {
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return options.count
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return options[row]
    }
}

extension InputPickerView: UIPickerViewDelegate {
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        textField.text = options[row]
    }
}

Currently it only accepts an array of strings and returns a string.目前它只接受一个字符串数组并返回一个字符串。 I'm trying to make it even more reusable by make it accept/return any types such as structs and enums with the help of generics.我试图通过在 generics 的帮助下接受/返回任何类型(例如结构和枚举)来使其更具可重用性。 I was hoping to make the structs/enums conform to CustomStringConvertible and use the description property value as the display value for the picker view options.我希望使结构/枚举符合CustomStringConvertible并使用描述属性值作为选择器视图选项的显示值。

But I'm having trouble figuring out how to do that.但我很难弄清楚如何做到这一点。 All the articles, questions, tutorials I came across have protocols involved in them.我遇到的所有文章、问题、教程都涉及协议。 So I'm a little confused.所以我有点困惑。

How can I make the options and option variables accept/return any type with generics?如何使用 generics 使optionsoption变量接受/返回任何类型?

By which I mean, say I create an object called State .我的意思是说,我创建了一个名为 State 的State

struct State {
    let id: Int
    let title: String
}

extension State: CustomStringConvertible {
    var description: String {
        return title
    }
}

Instead of passing in strings to the view, I'm trying to make it accept instances of State objects in the options property and have the view use the description value as the display value.我没有将字符串传递给视图,而是试图让它在options属性中接受State对象的实例,并让视图使用description值作为显示值。 And when the user selects one, it returns the selected State object via the option property.当用户选择一个时,它通过option属性返回选择的State object。

Demo project 演示项目

First you need a protocol that extracts a string from your conforming types to display in the picker:首先,您需要一个协议,从您的符合类型中提取字符串以显示在选择器中:

protocol Presentable {
    var title: String { get }
}

Make your State struct conform to Presentable :使您的State结构符合Presentable

struct State: Presentable {
    let id: Int
    let title: String
}

Add some generic constraints to your InputPickerView and whenever you need the text from your model just reference the title property.向 InputPickerView 添加一些通用约束,当您需要InputPickerView中的文本时,只需引用title属性即可。 Note that if you use generics you can no longer create extensions for your UIPickerViewDataSource and UIPickerViewDelegate methods.请注意,如果您使用 generics 您不能再为您的UIPickerViewDataSourceUIPickerViewDelegate方法创建扩展。

class InputPickerView<OptionType: Presentable>: UIView, UIPickerViewDataSource, UIPickerViewDelegate {

    private var titleLabel: UILabel!
    private var textField: UITextField!

    var options: [OptionType] = []

    var selectedOption: OptionType?

    var title: String = "" {
        didSet {
            titleLabel.text = title
        }
    }

    // ... Other stuff you need to add ...

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return options.count
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return options[row].title
    }

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        textField.text = options[row].title
        selectedOption = options[row]
    }
}

You create your InputPickerView like this:您可以像这样创建InputPickerView

let pickerView = InputPickerView<State>()
pickerView.options = [
    State(id: 1, title: "First"),
    State(id: 2, title: "Second"),
    State(id: 3, title: "Third"),
]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何为视图生命周期事件(onAppear、onDisappear)制作可重用的修饰符? - How to make a reusable modifier for view lifecycle events (onAppear, onDisappear)? 如何为UITableViewCell和UICollectionViewCell制作可重用的视图单元格? 我尝试将单元格的UIView转换为子视图,但无法正常工作 - How to make a reusable view cells for UITableViewCell and UICollectionViewCell ? I've tried to sublassing UIView for the cell but it's not working UITableView的可重用池如何查看内容 - How to view the content UITableView's reusable pool 如何创建和使用可重用的视图模板 - How to create and use reusable view-templates 如何使用不可重用的表视图单元格? - How to use table view cells, which are not reusable? 如何为TableView和CollectionView创建可重用的单元格 - How to make a reusable cell for both TableView and CollectionView 如何使包含UILabel的可重用UIView模板 - How to make reusable UIView template consisiting UILabels 如何制作可重复使用的UIView - How do I make a reusable UIView 如何使具有不同子视图的UITableViewCell可重用? - How to make a UITableViewCell with different subviews reusable? 如何使SFSpeechRecongnizer可重用于每个UIViewControllers - How to make SFSpeechRecongnizer Reusable for every UIViewControllers
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM