【问题标题】:Dynamic View in iOS inside UITableViewCelliOS 内部 UITableViewCell 中的动态视图
【发布时间】:2019-07-21 06:37:57
【问题描述】:

我正在创建用于维护我的产品状态的以下视图(In Transit 下的显示)。见下图。

我想在UITableViewCell 中创建这个视图,我尝试通过放置固定高度/宽度视图(不同颜色的圆形视图)和水平灰线视图,它适用于固定点。我可以使用情节提要为固定视图创建它。

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

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

【问题讨论】:

  • 不太清楚你在问什么。您是否尝试将“现场”位置与跟踪详细信息标签相匹配?或者您可以定位“点”,但无法将“圆形视图”对齐到相应的“点”?
  • @DonMag,我正在尝试定位动态的“点”。那么支持有4个以上的“点”,我该如何定位呢?

标签: ios uitableview uiview autolayout


【解决方案1】:

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

【讨论】:

  • 仔细阅读问题,我使用的是UITableView,所以如果我使用UICollectionView,那么它将在表格内可用。我不知道在表视图中实现集合视图。你能帮我做吗?
  • 是的,它是可能的,我在这个链接 [link] (pastebin.com/vJ2NNT0v) 中放了一个例子,你可以看到 ViewController UITableView Delegate Extension、TableViewCell 类和 CollectionViewCell 。
【解决方案2】:

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

在每个“点”视图之间添加一个清晰的UIView,并将每个“间隔”视图的宽度限制为等于第一个“间隔”视图。

添加一个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

}

跟踪间隔视图,并将它们的宽度约束设置为每个等于第一个间隔视图。

这里有一些可以帮助您开始的入门代码。 cmets 应该清楚地说明正在做什么。一切都在代码中完成(没有@IBOutlets),因此您应该能够通过在情节提要中添加视图控制器并将其自定义类分配给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()
        })

    }

}

结果:

【讨论】:

  • 非常感谢您的工作。我可以在 UITableView 中使用它吗?因为,根据我的理解,cellForRow 方法不应该包含for 循环。从您的代码和解释来看,for 循环是必需的。我只是要求清除它。
  • 当然可以在表格视图单元格中使用。试一试。
  • 当然。如果有任何问题,我会尽力告诉您。
【解决方案3】:

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

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

CollectionViewCell:

查看约束:

关于spotview和circleview,你可以通过约束和视图来识别。所以不要混淆它们,否则所有命名约定都可以根据视图的优先级使用。

现在你需要在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
    }
}

希望对你有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 2012-06-29
    • 2013-10-12
    • 1970-01-01
    • 1970-01-01
    • 2014-02-16
    相关资源
    最近更新 更多