【问题标题】:Programmatically create UIView with size based on subviews(labels)基于子视图(标签)以编程方式创建具有大小的 UIView
【发布时间】:2018-10-27 18:44:30
【问题描述】:

我有一个需要完全以编程方式创建 UIView 的场景。此视图显示为视频源的叠加层,它包含 2 个 UILabel 作为子视图。

这些标签可以有不同的宽度和高度,所以我不想为 UIView 或标签创建一个固定的框架。

我已经用程序约束完成了这个,没有问题,但问题是移动手机时视图出现故障,我正在使用的框架建议不要使用自动布局,因为这个确切的问题.

我当前的代码:

  • 我创建视图

        func ar(_ arViewController: ARViewController, viewForAnnotation: ARAnnotation) -> ARAnnotationView {
                let annotationView = AnnotationView() //*this is the view, inherits from UIView
                annotationView.annotation = viewForAnnotation
                annotationView.delegate = self
    
                return annotationView
            }
    
  • 以及实际的视图代码

    class AnnotationView: ARAnnotationView {
    
    
            var titleLabel: UILabel?
            var distanceLabel: UILabel!
            var delegate: AnnotationViewDelegate?
            override var annotation: ARAnnotation? {
                didSet {
                    loadUI()
                }
            }
    
            override func didMoveToSuperview() {
                super.didMoveToSuperview()
    
                setupUI()
            }
    
            private func setupUI() {
                layer.cornerRadius = 5
                layer.masksToBounds = true
                backgroundColor = .transparentWhite
            }
    
            private func loadUI() {
                titleLabel?.removeFromSuperview()
                distanceLabel?.removeFromSuperview()
    
                let label = UILabel()
                label.font = UIFont(name: "AvenirNext-Medium", size: 16.0) ?? UIFont.systemFont(ofSize: 14)
                label.numberOfLines = 2
                label.textColor = UIColor.white
                self.titleLabel = label
    
                distanceLabel = UILabel()
                distanceLabel.textColor = .cbPPGreen
                distanceLabel.font = UIFont(name: "AvenirNext-Medium", size: 14.0) ?? UIFont.systemFont(ofSize: 12)
                distanceLabel.textAlignment = .center
    
                self.translatesAutoresizingMaskIntoConstraints = false
                label.translatesAutoresizingMaskIntoConstraints = false
                distanceLabel.translatesAutoresizingMaskIntoConstraints = false
    
                self.addSubview(label)
                self.addSubview(distanceLabel)
    
                if self.constraints.isEmpty {
                    NSLayoutConstraint.activate([
                        NSLayoutConstraint(item: label, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 5),
                        NSLayoutConstraint(item: label, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1, constant: -5),
                        NSLayoutConstraint(item: label, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0),
                        NSLayoutConstraint(item: label, attribute: .bottom, relatedBy: .equal, toItem: distanceLabel, attribute: .top, multiplier: 1, constant: 0),
    
                        NSLayoutConstraint(item: distanceLabel, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 0),
                        NSLayoutConstraint(item: distanceLabel, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1, constant: 0),
                        NSLayoutConstraint(item: distanceLabel, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0),
                        NSLayoutConstraint(item: distanceLabel, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 15),
                        ])
        }
    
                if let annotation = annotation as? BikeStationAR {
                    titleLabel?.text = annotation.address
                    distanceLabel?.text = String(format: "%.2f km", annotation.distanceFromUser / 1000)
                }
            }
    
            override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
                delegate?.didTouch(annotationView: self)
            }
        }        
    

所以我现在的问题是:如何在不使用自动布局的情况下实现相同的行为?

编辑:这是https://streamable.com/s/4zusq/dvbgnb行为的视频

编辑 2:解决方案基于 Mahgol Fa 的回答并使用堆栈视图或垂直定位,以便不为各个标签设置框架。所以最终的实现是

private func loadUI() {
        titleLabel?.removeFromSuperview()
        distanceLabel?.removeFromSuperview()

        let label = UILabel()
        label.font = titleViewFont
        label.numberOfLines = 0
        label.textColor = UIColor.white
        label.textAlignment = .center
        self.titleLabel = label

        distanceLabel = UILabel()
        distanceLabel.textColor = .cbPPGreen
        distanceLabel.font = subtitleViewFont
        distanceLabel.textAlignment = .center

        label.translatesAutoresizingMaskIntoConstraints = false
        distanceLabel.translatesAutoresizingMaskIntoConstraints = false

        if let annotation = annotation as? BikeStationAR {
            let title = annotation.address
            let subtitle = String(format: "%.2f km", annotation.distanceFromUser / 1000)

            let fontAttributeTitle = [NSAttributedString.Key.font: titleViewFont]
            let titleSize = title.size(withAttributes: fontAttributeTitle)

            let fontAttributeSubtitle = [NSAttributedString.Key.font: subtitleViewFont]
            let subtitleSize = annotation.address.size(withAttributes: fontAttributeSubtitle)

            titleLabel?.text = title
            distanceLabel?.text = subtitle

            let stackView = UIStackView(frame: CGRect(x: 0, y: 0, width: titleSize.width + 5, height: titleSize.height + subtitleSize.height + 5))
            stackView.axis = .vertical
            stackView.distribution = .fillProportionally
            stackView.alignment = .fill
            stackView.addArrangedSubview(titleLabel ?? UIView())
            stackView.addArrangedSubview(distanceLabel)

            frame = stackView.bounds
            addSubview(stackView)
        }
    }

【问题讨论】:

  • 你能展示一下它出现故障时的截图吗?
  • 移动手机是什么意思?喜欢旋转?
  • 我添加了一个视频。

标签: ios swift uiview autolayout


【解决方案1】:

这样你可以得到你的标签文本的宽度:

let fontAttributes1= [NSAttributedStringKey.font: your declared font in your code]
   let size1 = (“your string” as String).size(withAttributes: fontAttributes1)
let fontAttributes2= [NSAttributedStringKey.font: your declared font in your code]
   let size2 = (“your string” as String).size(withAttributes: fontAttributes2)

然后:

YourView.frame = CGRect( width: size1.width + size2.width + some spacing , height : ....)

【讨论】:

  • 你是真正的MVP!
  • 没问题??
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-04
  • 1970-01-01
  • 1970-01-01
  • 2018-06-04
  • 2014-05-29
相关资源
最近更新 更多