ios 多态的应用(swift)

概念
多态的概念详细见
iOS封装、继承、多态项目应用-tableview(OC篇)
应用场景

图1

分析:
上图整体采用tableView来实现,分为三个section(1,2,3)
区域2的做法有几种:
1、采用tableView嵌套tableView来实现,不好计算高度,考虑到可能会有多行,把内容撑大,需要分别计算高度
2、把区域2切割成tableView的row,如下图
图2

如上图,需要好几个cell,title样式、开关样式、输入框样式、点击更多样式等,但是考虑到以下几点:

  • 第一个cell上部分有圆角、最后一个cell下部分有圆角,中间无圆角,因为样式不确定(不同设备详情样式不确定,不同设备详情cell不同)
  • 每个cell有相同的地方,如icon,title,有不同的地方,如content,开关等
    考虑创建一个基类,用于设置公共的部分(icon、title、圆角等)
    基类WCDeviceBaseTableViewCell代码如下
import UIKit

enum LocationType {
    case first //第一行
    case middle //中间行
    case last //最后一行
}

class WCDeviceBaseTableViewCell: WCBaseTableViewCell {

    //MARK: - public variable
    //cell的位置,用于处理圆角位置
    var locationType:LocationType = .first
    //标题
    var title:String? {
        didSet {
            if let title = title {
                self.titleLabel.text = title
            }
        }
    }
    //图标名
    var iconName:String? {
        didSet {
            if let iconName = iconName {
                self.iconIV.image = UIImage(named: iconName)
            }
        }
    }
    //内容
    var content:String?
    //view
    //圆角view
    lazy var cornerView:UIView = {
        let cornerView = UIView()
        cornerView.backgroundColor = .white
        return cornerView
    }()
    //图标
    lazy var iconIV:UIImageView = {
        let iconIV = UIImageView()
        return iconIV
    }()
    
    lazy var titleLabel:UILabel = {
        let titleLabel = UILabel()
        titleLabel.textColor = .black
        titleLabel.font = UIFont.systemFont(ofSize: 16)
        return titleLabel
    }()
    
    //MARK: - function
    //override UI
    override func prepareUI() {
        super.prepareUI()
        
        self.containerView.addSubview(self.cornerView)
        self.cornerView.snp.makeConstraints { make in
            make.top.bottom.equalToSuperview()
            make.left.equalTo(12)
            make.right.equalTo(-12)
        }
        
        self.cornerView.addSubview(self.iconIV)
        self.iconIV.snp.makeConstraints { make in
            make.left.top.equalTo(20)
            make.width.height.equalTo(32)
            make.bottom.lessThanOrEqualTo(-20)
        }
        
        self.cornerView.addSubview(self.titleLabel)
        self.titleLabel.snp.makeConstraints { make in
            make.centerY.equalTo(self.iconIV)
            make.left.equalTo(self.iconIV.snp.right).offset(8)
        }
    }
    
    //MARK: - system
    override func layoutSubviews() {
        super.layoutSubviews()
        if self.bounds.height > 0 && self.bounds.width > 0 {
            var rect = self.bounds
            rect.size.width = rect.width - 12 * 2
            var corner:UIRectCorner = [.allCorners]
            var radii = CGSize(width: 12, height: 12)
            if self.locationType == .first {
                corner = [.topLeft, .topRight]
            } else if self.locationType == .last {
                corner = [.bottomLeft, .bottomRight]
            } else if self.locationType == .middle {
                corner = [.allCorners]
                radii = CGSize(width: 0, height: 0)
            }
            
            self.cornerView.layer.mask = self.configRectCorner(view: self.cornerView, bounds: rect, corner: corner, radii: radii)
        }
    }
    
    //MARK: - private function
    //设置部分圆角
    private func configRectCorner(view: UIView, bounds:CGRect? = nil, corner: UIRectCorner, radii: CGSize) -> CALayer {
        let maskPath = UIBezierPath.init(roundedRect: bounds ?? view.bounds, byRoundingCorners: corner, cornerRadii: radii)
        let maskLayer = CAShapeLayer.init()
        maskLayer.frame = bounds ?? view.bounds
        maskLayer.path = maskPath.cgPath
        return maskLayer
    }
    
}

基类中设置了一些公共的变量、UI布局等,并且声名子类的变量
子类cell代码如下
WCDeviceTitleTableViewCell

class WCDeviceTitleTableViewCell: WCDeviceBaseTableViewCell {

    override func prepareUI() {
        super.prepareUI()
        
        self.iconIV.isHidden = true
        self.iconIV.snp.removeConstraints()
        self.titleLabel.snp.remakeConstraints { make in
            make.left.top.equalTo(20)
            make.bottom.equalTo(-12)
        }
    }

}

WCDeviceSwitchTableViewCell

class WCDeviceSwitchTableViewCell: WCDeviceBaseTableViewCell {

    //MARK: - prvate variable
    private lazy var switchButton:UIButton = {
        let switchButton = UIButton(type: .custom)
        switchButton.setImage(UIImage(named: "ic_switch_on"), for: .normal)
        return switchButton
    }()
    
    override func prepareUI() {
        super.prepareUI()
        
        self.cornerView.addSubview(self.switchButton)
        self.switchButton.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.right.equalTo(-20)
            make.width.equalTo(44)
            make.height.equalTo(22)
        }
    }

}

WCDeviceLabelTableViewCell

class WCDeviceLabelTableViewCell: WCDeviceBaseTableViewCell {

    //MARK: - private variable
    private lazy var moreIV:UIImageView = {
        let moreIV = UIImageView()
        moreIV.image = UIImage(named: "ic_list_more")
        return moreIV
    }()
    
    //override
    override var content: String? {
        didSet {
            self.contentLabel.text = content
        }
    }
    
    private lazy var contentLabel:UILabel = {
        let contentLabel = UILabel()
        contentLabel.textColor = .gray
        contentLabel.font = UIFont.systemFont(ofSize: 13)
        contentLabel.textAlignment = .right
        contentLabel.numberOfLines = 0
        return contentLabel
    }()
    
    override func prepareUI() {
        super.prepareUI()
        self.cornerView.addSubview(self.moreIV)
        self.moreIV.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.right.equalTo(-20)
            make.width.height.equalTo(24)
        }
        self.cornerView.addSubview(self.contentLabel)
        self.contentLabel.snp.makeConstraints { make in
            make.right.equalTo(self.moreIV.snp.left)
            make.width.equalTo(148)
            make.top.equalTo(14)
            make.bottom.equalTo(-14)
            make.height.greaterThanOrEqualTo(40)
        }
    }

}

WCDeviceTFTableViewCell


    //MARK: - private variable
    private lazy var textField:UITextField = {
        let textField = UITextField()
        textField.textColor = .gray
        textField.font = UIFont.systemFont(ofSize: 13)
        textField.textAlignment = .right
        return textField
    }()
    
    //override
    override var content: String? {
        didSet {
            self.textField.text = content
        }
    }
    
    override func prepareUI() {
        super.prepareUI()
        
        self.cornerView.addSubview(self.textField)
        self.textField.snp.makeConstraints { make in
            make.top.bottom.equalToSuperview()
            make.right.equalTo(-20)
            make.width.equalTo(200)
        }
    }

}

控制器中代码如下

fileprivate enum CellType {
    case title
    case openSwitch
    case name
    case area
    case timimg
    case countdown
}

class TestViewController: UIViewController {
    
    //MARK: - private variable
    private lazy var tableView:UITableView = {
        let tableView = UITableView(frame: self.view.bounds)
        tableView.backgroundColor = .clear
        tableView.separatorStyle = .none
        tableView.delegate = self
        tableView.dataSource = self
        return tableView
    }()
    
    //cell内容
    private var cellTypes:[CellType] = [
        .title,
        .openSwitch,
        .name,
        .area,
        .timimg,
        .countdown,
    ]
    private let titleDic:[CellType:String] = [
        .title : "设备信息",
        .openSwitch : "开关",
        .name : "名称",
        .area : "区域",
        .timimg : "定时",
        .countdown : "倒计时",
    ]
    private let iconDic:[CellType:String] = [
        .openSwitch : "ic_area_switch",
        .name : "ic_area_name",
        .area : "ic_area_area",
        .timimg : "ic_area_timing",
        .countdown : "ic_area_countdown",
    ]
    private let classDic:[CellType:WCDeviceBaseTableViewCell.Type] = [
        .title : WCDeviceTitleTableViewCell.self,
        .openSwitch : WCDeviceSwitchTableViewCell.self,
        .name : WCDeviceTFTableViewCell.self,
        .area : WCDeviceLabelTableViewCell.self,
        .timimg : WCDeviceLabelTableViewCell.self,
        .countdown : WCDeviceLabelTableViewCell.self,
    ]
    
    //MARK: - lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.backgroundColor = .gray
        self.view.addSubview(self.tableView)
        
    }
}

extension TestViewController:UITableViewDelegate, UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.cellTypes.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellType = self.cellTypes[indexPath.row]
        
        var aclass:WCDeviceBaseTableViewCell.Type = self.classDic[cellType] ?? WCDeviceBaseTableViewCell.self
        if indexPath.row == 0 {
            aclass = WCDeviceTitleTableViewCell.self
        }
        
        let cell = aclass.wc_baseTableViewCell(tableView: tableView) as! WCDeviceBaseTableViewCell
        if indexPath.row == 0 {
            cell.locationType = .first
        } else if indexPath.row == self.cellTypes.count - 1 {
            cell.locationType = .last
        } else {
            cell.locationType = .middle
        }
        cell.iconName = self.iconDic[cellType]
        cell.title = self.titleDic[cellType]
        
        var content:String = ""
        if cellType == .name {
            content = "照明吊灯"
        } else if cellType == .area {
            content = "主卧"
        } else if cellType == .countdown {
            content = "03:45"
        }
        cell.content = content
        return cell
    }
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 12
    }
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        return UIView()
    }
}

运行结果

运行结果

总结
控制器中的代码

var aclass:WCDeviceBaseTableViewCell.Type = self.classDic[cellType] ?? WCDeviceBaseTableViewCell.self
let cell = aclass.wc_baseTableViewCell(tableView: tableView) as! WCDeviceBaseTableViewCell

使用了多态的特性,声名的cell类型为WCDeviceBaseTableViewCell,但是根据实际调用的class(aclass)调用对应的类函数,会返回实际的实例变量(但都是WCDeviceBaseTableViewCell的子类),后续的赋值、显示等操作均会根据实际的变量类型来执行。
可应用的项目: 后端返回的数据是相同的model,但根据数据的类型不同(可能是数据中的某个字段来判断),UI等有区别的情况

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容