Программно создать UIView с размером на основе подпредставлений (меток) - PullRequest
0 голосов
/ 27 октября 2018

У меня есть сценарий, в котором мне нужно создать UIView полностью программно. Это представление отображается в виде наложения поверх видеопотока и содержит 2 UILabels в качестве подпредставлений.

Эти метки могут иметь различную ширину и высоту, поэтому я не хочу создавать фиксированную рамку для 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)
            }
        }        
    

Итак, моя проблема сейчас: как я могу добиться того же поведения, не используя autolayout?

Редактировать: вот видео о поведении https://streamable.com/s/4zusq/dvbgnb

Редактировать 2: Решение основано на ответе Махгола Фа и использовании стекового представления или вертикального позиционирования, чтобы не задавать рамку для отдельных меток. Таким образом, окончательная реализация

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)
        }
    }

1 Ответ

0 голосов
/ 28 октября 2018

Таким образом, вы можете получить ширину текстов ваших ярлыков:

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 : ....)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...