iOS中的UITableViewCell内部的动态视图

时间:2019-02-27 14:01:02

标签: ios uitableview uiview autolayout

我正在创建以下视图(在运输中的显示 下显示),这些视图用于维护我的产品状态。参见下图。

Dyanamic Status View in Table View

我想在UITableViewCell中创建此视图,我尝试通过放置固定的高/宽视图(具有不同颜色的圆形视图)和水平灰线视图来解决此问题,该方法对于固定点非常有用。我可以使用情节提要为固定视图创建它。

  

我的问题是,这些是动态点视图。当前为4,但可以根据API响应中的可用状态而有所不同。

有人知道吗?如何实现此状态点动态视图?。

3 个答案:

答案 0 :(得分:1)

您可以使用UIStackView使用“间隔”视图来做到这一点。

在每个“点”视图之间添加透明的UIView,并将每个“间隔”视图的宽度限制为等于 first “ spacer”视图

添加UIStackView,将其宽度和centerY限制在跟踪线上,并将属性设置为:

Axis: Horizontal
Alignment: Fill
Distribution: Fill
Spacing: 0

您添加“点”的代码将如下所示:

for i in 0..<numberOfDots {

    create a dot view

    add it to the stackView using .addArrangedSubview()

    one fewer spacers than dots (e.g. 4 dots have a spacer between each = 3 spacers), so,

    if this is NOT the last dot,

        create a spacer view

        add it to the stackView

}

跟踪间隔视图,并将其宽度限制设置为等于第一个间隔视图。

以下是一些入门代码,可以帮助您入门。这些注释应使正在做的事情清楚。一切都在代码中完成(没有@IBOutlet),因此您应该能够通过在情节提要中添加视图控制器并将其自定义类分配给DotsViewController来运行它。它将视图添加为“普通”子视图...但是当然也可以将其添加为单元格的子视图。

class DotView: UIView {

    override func layoutSubviews() {
        super.layoutSubviews()
        layer.cornerRadius = bounds.size.height * 0.5
    }

}

class TrackingLineView: UIView {

    var theTrackingLine: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
        return v
    }()

    var theStack: UIStackView = {
        let v = UIStackView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.axis = .horizontal
        v.alignment = .fill
        v.distribution = .fill
        v.spacing = 0
        return v
    }()

    var trackingDot: DotView = {
        let v = DotView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = UIColor(red: 0.0, green: 0.5, blue: 1.0, alpha: 1.0)
        return v
    }()

    let dotWidth = CGFloat(6)

    let trackingDotWidth = CGFloat(20)

    var trackingDotCenterX = NSLayoutConstraint()

    var dotViews = [DotView]()

    var trackingPosition: Int = 0 {
        didSet {
            let theDot = dotViews[trackingPosition]
            trackingDotCenterX.isActive = false
            trackingDotCenterX = trackingDot.centerXAnchor.constraint(equalTo: theDot.centerXAnchor, constant: 0.0)
            trackingDotCenterX.isActive = true
        }
    }

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

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

    func commonInit() -> Void {

        // add the tracking line
        addSubview(theTrackingLine)

        // add the "big" tracking dot
        addSubview(trackingDot)

        // add the stack view that will hold the small dots (and spacers)
        addSubview(theStack)

        // the "big" tracking dot will be positioned behind a small dot, so we need to
        //  keep a reference to its centerXAnchor constraint
        trackingDotCenterX = trackingDot.centerXAnchor.constraint(equalTo: theTrackingLine.centerXAnchor, constant: 0.0)

        NSLayoutConstraint.activate([

            theTrackingLine.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0.0),
            theTrackingLine.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0.0),
            theTrackingLine.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 1.0, constant: -20.0),
            theTrackingLine.heightAnchor.constraint(equalToConstant: 2.0),

            theStack.centerXAnchor.constraint(equalTo: theTrackingLine.centerXAnchor, constant: 0.0),
            theStack.centerYAnchor.constraint(equalTo: theTrackingLine.centerYAnchor, constant: 0.0),
            theStack.widthAnchor.constraint(equalTo: theTrackingLine.widthAnchor, multiplier: 1.0, constant: 0.0),

            trackingDotCenterX,

            trackingDot.widthAnchor.constraint(equalToConstant: trackingDotWidth),
            trackingDot.heightAnchor.constraint(equalTo: trackingDot.widthAnchor, multiplier: 1.0),
            trackingDot.centerYAnchor.constraint(equalTo: theTrackingLine.centerYAnchor, constant: 0.0),

            ])

    }

    func setDots(with colors: [UIColor]) -> Void {

        // remove any previous dots and spacers
        //      (in case we're changing the number of dots after creating the view)
        theStack.arrangedSubviews.forEach {
            $0.removeFromSuperview()
        }

        // reset the array of dot views
        //      (in case we're changing the number of dots after creating the view)
        dotViews = [DotView]()

        // we're going to set all spacer views to equal widths, so use
        //  this var to hold a reference to the first one we create
        var firstSpacer: UIView?

        colors.forEach {
            c in

            // create a DotView
            let v = DotView()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.backgroundColor = c

            // add to array so we can reference it later
            dotViews.append(v)

            // add it to the stack view
            theStack.addArrangedSubview(v)

            // dots are round (equal width to height)
            NSLayoutConstraint.activate([
                v.widthAnchor.constraint(equalToConstant: dotWidth),
                v.heightAnchor.constraint(equalTo: v.widthAnchor, multiplier: 1.0),
                ])

            // we use 1 fewer spacers than dots, so if this is not the last dot
            if c != colors.last {

                // create a spacer (clear view)
                let s = UIView()
                s.translatesAutoresizingMaskIntoConstraints = false
                s.backgroundColor = .clear

                // add it to the stack view
                theStack.addArrangedSubview(s)

                if firstSpacer == nil {
                    firstSpacer = s
                } else {
                    // we know it's not nil, but we have to unwrap it anyway
                    if let fs = firstSpacer {
                        NSLayoutConstraint.activate([
                            s.widthAnchor.constraint(equalTo: fs.widthAnchor, multiplier: 1.0),
                            ])
                    }
                }

            }

        }

    }

}

class DotsViewController: UIViewController {

    var theButton: UIButton = {
        let v = UIButton()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .red
        v.setTitle("Move Tracking Dot", for: .normal)
        v.setTitleColor(.white, for: .normal)
        return v
    }()

    var theTrackingLineView: TrackingLineView = {
        let v = TrackingLineView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .white
        return v
    }()

    var trackingDots: [UIColor] = [
        .yellow,
        .red,
        .orange,
        .green,
        .purple,
        ]

    var currentTrackingPosition = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor(red: 1.0, green: 0.8, blue: 0.5, alpha: 1.0)

        view.addSubview(theTrackingLineView)

        NSLayoutConstraint.activate([
            theTrackingLineView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0.0),
            theTrackingLineView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0.0),
            theTrackingLineView.heightAnchor.constraint(equalToConstant: 100.0),
            theTrackingLineView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.9),
            ])

        theTrackingLineView.setDots(with: trackingDots)
        theTrackingLineView.trackingPosition = currentTrackingPosition

        // add a button so we can move the tracking dot
        view.addSubview(theButton)

        NSLayoutConstraint.activate([
            theButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 40.0),
            theButton.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0.0),
            ])

        theButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)

    }

    @objc func buttonTapped(_ sender: Any) -> Void {

        // if we're at the last dot, reset to 0
        if currentTrackingPosition < trackingDots.count - 1 {
            currentTrackingPosition += 1
        } else {
            currentTrackingPosition = 0
        }

        theTrackingLineView.trackingPosition = currentTrackingPosition
        UIView.animate(withDuration: 0.25, animations: {
            self.view.layoutIfNeeded()
        })

    }

}

结果:

enter image description here

答案 1 :(得分:1)

您可以在UICollectionView中使用UITableViewCell来实现自己的目标。

首先为集合视图单元格创建以下设计。该集合视图已添加到表格视图单元格中。

CollectionViewCell:

UICollectionViewCell

请参阅约束条件:

Constraints

关于点视图和圆视图,您可以通过约束条件和视图来识别。因此,请不要混淆它们,否则所有命名约定都可以根据视图的优先级使用。

现在,无论您做什么,都需要在UITableViewCell的子类中获取集合视图的出口,并将集合视图单元的子视图变为UICollectionViewCell的子类。

UITableViewCell:

class CTrackOrderInTransitTVC: UITableViewCell {

    @IBOutlet weak var transitView : UIView!
    @IBOutlet weak var cvTransit : UICollectionView!

    var arrColors: [UIColor] = [.blue, .yellow, .green, .green]

    override func awakeFromNib() {
        super.awakeFromNib()
    }
}

现在在集合视图单元格子类中添加以下代码,其中包含集合视图单元格的子视图的出口:

class CTrackOrderInTransitCVC: UICollectionViewCell {

    @IBOutlet weak var leftView                     : UIView!
    @IBOutlet weak var rightView                    : UIView!

    @IBOutlet weak var spotView                     : UIView!
    @IBOutlet weak var circleView                   : UIView!
}

此后,您必须实现表视图数据源方法,将您的集合视图单元格加载到表内部。

请参见以下代码:

extension YourViewController: UITableViewDataSource {

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

    //------------------------------------------------------------------------------

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

        let cell = tableView.dequeueReusableCell(withIdentifier: "CTrackOrderInTransitTVC", for: indexPath) as! CTrackOrderInTransitTVC

        // Reload collection view to update sub views
        cell.cvTransit.reloadData()

        return cell
    }
}

我希望这会对您有所帮助。

答案 2 :(得分:0)

我建议您在表格单元格内使用集合视图,以便您可以通过简单的验证来定义位置