复杂UITableViewCell的问题

时间:2017-05-10 18:33:40

标签: ios iphone swift uitableview tableviewcell

我正在尝试实施自定义复合体UITableViewCell。我的数据源相对简单,但我可以有一些多元素。

class Element: NSObject {
    var id: String
    var titles: [String]
    var value: String

    init(id: String, titles: [String], value: String) {
        self.id = id
        self.titles = titles
        self.value = value
    }
}

我有一个元素数组[Element],正如您所看到的,每个元素titles可能有多个字符串值。我必须使用以下布局:

single_cell

double_cell

multiple_cell

我的第一种方法是实现动态UITableViewCell,尝试在运行时在self.contentView内添加内容。一切正常,但它并不是那么好,你可以看到,可重用性没有以正确的方式处理。滞后是可怕的。

import UIKit

class ElementTableCell: UITableViewCell {

    var titles: [String]!
    var value: String!
    var width: CGFloat!
    var titleViewWidth: CGFloat!
    var cellHeight: Int!

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:)")
    }

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        self.selectionStyle = .none
    }

    func drawLayout() {
        titleViewWidth = (width * 2)/3
        cellHeight = 46 * titles.count

        for i in 0 ..< titles.count {
            let view = initTitleView(title: titles[i], width: titleViewWidth, yPosition: CGFloat(cellHeight * i))
            self.contentView.addSubview(view)
        }

        self.contentView.addSubview(initButton())
    }

    func initTitleView(title: String, width: CGFloat, yPosition: CGFloat) -> UIView {
        let titleView: UILabel = UILabel(frame:CGRect(x:0, y:Int(yPosition), width: Int(width), height: 45))
        titleView.text = title
        return titleView
    }

    func initButton(value: String) -> UIButton {
        let button = UIButton(frame:CGRect(x: 0, y: 0, width: 70, height:34))
        button.setTitle(value, for: .normal)
        button.center.x = titleViewWidth + ((width * 1)/3)/2
        button.center.y = CGFloat(cellHeight/2)
        return priceButton
    }
}

UITableView委托方法:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = ElementTableCell(style: .default, reuseIdentifier: "ElementTableCell")

    cell.width = self.view.frame.size.width
    cell.titles = elements[indexPath.row].titles
    cel.value = elements[indexPath.row].value
    cell.drawLayout()

    return cell
}

现在我正在考虑一种完全不同的方法,例如对elements数组中的每个元素使用UITableView部分,为标题中的每个标题使用UITableViewCell。它可以工作,但我担心正确的按钮。 您有任何建议或其他方法可以分享吗?

5 个答案:

答案 0 :(得分:1)

我解决了更改应用程序UI逻辑以解决问题。谢谢大家。

答案 1 :(得分:0)

这里有一些你可以玩的代码。 应该只是在故事板中创建一个新的UITableView并将其分配给此文件中的BoxedTableViewController ...

//
//  BoxedTableViewController.swift
//

import UIKit

class BoxedCell: UITableViewCell {

    var theStackView: UIStackView!
    var containingView: UIView!
    var theButton: UIButton!

    var brdColor = UIColor(white: 0.7, alpha: 1.0)

    // "spacer" view is just a 1-pt tall UIView used as a horizontal-line between labels
    //      when there is more than one title label
    func getSpacer() -> UIView {

        let newView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 1))
        newView.backgroundColor = brdColor

        newView.translatesAutoresizingMaskIntoConstraints = false

        newView.heightAnchor.constraint(equalToConstant: 1.0).isActive = true

        return newView

    }

    // "label view" is a UIView containing on UILabel
    //      embedding the label in a view allows for convenient borders and insets
    func getLabelView(text: String, position: Int) -> UIView {

        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false

        let newLabel = UILabel()
        newLabel.font = UIFont.systemFont(ofSize: 15.0)
        newLabel.backgroundColor = UIColor(white: 0.8, alpha: 1.0)
        newLabel.textColor = .black

        newLabel.layer.borderWidth = 1
        newLabel.layer.borderColor = brdColor.cgColor

        newLabel.numberOfLines = 0
        newLabel.text = text

        newLabel.translatesAutoresizingMaskIntoConstraints = false

        v.addSubview(newLabel)

        newLabel.leadingAnchor.constraint(equalTo: v.leadingAnchor, constant: 8.0).isActive = true
        newLabel.trailingAnchor.constraint(equalTo: v.trailingAnchor, constant: -8.0).isActive = true

        var iTop: CGFloat = 0.0
        var iBot: CGFloat = 0.0

        // the passed "position" tells me whether this label is:
        //      a Single Title only
        //      the first Title of more than one
        //      the last Title of more than one
        //      or a Title with a Title above and below
        // so we can set up proper top/bottom padding

        switch position {
        case 0:
            iTop = 16.0
            iBot = 16.0
            break

        case 1:
            iTop = 12.0
            iBot = 8.0
            break

        case -1:
            iTop = 8.0
            iBot = 12.0
            break

        default:
            iTop = 8.0
            iBot = 8.0
            break
        }

        newLabel.topAnchor.constraint(equalTo: v.topAnchor, constant: iTop).isActive = true
        newLabel.bottomAnchor.constraint(equalTo: v.bottomAnchor, constant: -iBot).isActive = true

        return v

    }

    func setupThisCell(rowNumber: Int) -> Void {

        // if containingView is nil, it hasn't been created yet
        //      so, create it + Stack view + Button
        // else
        //      don't create new ones
        // This way, we don't keep adding more and more views to the cell on reuse

        if containingView == nil {

            containingView = UIView()
            containingView.translatesAutoresizingMaskIntoConstraints = false

            contentView.addSubview(containingView)

            containingView.layer.borderWidth = 1
            containingView.layer.borderColor = brdColor.cgColor
            containingView.backgroundColor = .white

            containingView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0).isActive = true
            containingView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8.0).isActive = true

            containingView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 6.0).isActive = true
            containingView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -6.0).isActive = true

            theStackView = UIStackView()
            theStackView.translatesAutoresizingMaskIntoConstraints = false

            containingView.addSubview(theStackView)

            theStackView.axis = .vertical
            theStackView.spacing = 4.0
            theStackView.alignment = .fill
            theStackView.distribution = .fill

            theButton = UIButton(type: .custom)
            theButton.translatesAutoresizingMaskIntoConstraints = false

            containingView.addSubview(theButton)

            theButton.backgroundColor = .blue
            theButton.setTitleColor(.white, for: .normal)
            theButton.setTitle("The Button", for: .normal)

            theButton.setContentHuggingPriority(1000, for: .horizontal)

            theButton.centerYAnchor.constraint(equalTo: containingView.centerYAnchor, constant: 0.0).isActive = true
            theButton.trailingAnchor.constraint(equalTo: containingView.trailingAnchor, constant: -8.0).isActive = true

            theStackView.topAnchor.constraint(equalTo: containingView.topAnchor, constant: 0.0).isActive = true
            theStackView.bottomAnchor.constraint(equalTo: containingView.bottomAnchor, constant: 0.0).isActive = true
            theStackView.leadingAnchor.constraint(equalTo: containingView.leadingAnchor, constant: 0.0).isActive = true

            theStackView.trailingAnchor.constraint(equalTo: theButton.leadingAnchor, constant: -8.0).isActive = true

        }

        // remove all previously added Title labels and spacer views

        for v in theStackView.arrangedSubviews {
            v.removeFromSuperview()
        }

        // setup 1 to 5 Titles
        let n = rowNumber % 5 + 1

        // create new Title Label views and, if needed, spacer views
        //      and add them to the Stack view

        if n == 1 {

            let aLabel = getLabelView(text: "Only one title for row: \(rowNumber)", position: 0)
            theStackView.addArrangedSubview(aLabel)

        } else {

            for i in 1..<n {

                let aLabel = getLabelView(text: "Title number \(i)\n for row: \(rowNumber)", position: i)
                theStackView.addArrangedSubview(aLabel)
                let aSpacer = getSpacer()
                theStackView.addArrangedSubview(aSpacer)

            }

            let aLabel = getLabelView(text: "Title number \(n)\n for row: \(rowNumber)", position: -1)
            theStackView.addArrangedSubview(aLabel)

        }

    }

}

class BoxedTableViewController: UITableViewController {

    let cellID = "boxedCell"

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(BoxedCell.self, forCellReuseIdentifier: cellID)

        tableView.estimatedRowHeight = 100
        tableView.rowHeight = UITableViewAutomaticDimension

        self.tableView.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0)

    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1250
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! BoxedCell

        // Configure the cell...

        cell.setupThisCell(rowNumber: indexPath.row)

        return cell

    }

}

我会检查你是否遇到任何问题(必须运行,还没有完全测试它 - 并且没时间评论它了 - 呃)。

答案 2 :(得分:0)

您还可以将tableview用作tableviecell并相应地调整单元格。

答案 3 :(得分:0)

在将数据设置为label和imageview之后,你需要在func layoutsubviews中布局单元格;

答案 4 :(得分:0)

是的,将ElementTableCell拆分为带有标题和单元格的部分是更好的方法。在这种情况下,您无需创建约束或处理复杂的手动布局。这将使您的代码变得简单并使滚动顺利。 您使用的按钮可以轻松移动到可重复使用的标题视图

您是否仍希望将其保留在一个完整的单元格中,这是一种手动绘制动态元素的方法,例如标题和分隔符行。手动绘图比往常更快。或者每次添加新内容时从cell.contentView中删除所有视图。但这种方式要复杂得多。

关于如何使UITableView外观swmoth的文章: Perfect smooth scrolling in UITableViews