Как получить значение ширины UIView, который находится внутри UIStackView - PullRequest
0 голосов
/ 03 июня 2018

У меня есть свой собственный пользовательский вид, ProgressBar, который я создаю программно:

let pb = ProgressBar(frame: CGRect(x: 0, y: 0, width: 200, height: 16))

Я создаю его, используя ширину 200, но затем добавляю его в горизонтальный вид стека.Из-за этого представление будет увеличиваться в зависимости от размера экрана, например, на iPhone X увеличится до 250.

В этом пользовательском представлении я пытаюсь использовать ширину, но она всегда равна 200, и это вызываетвсе виды вопросов.

Что мне действительно нужно, так это значение, которое представление имеет внутри стекового представления, в моем случае 250.

Есть ли способ получить это значение внутри моего пользовательского представления?
ИлиКакие у меня есть альтернативы?

edit - добавлен код:

class CustomTableViewCell: UITableViewCell {
  func configure() {
     let progressBar: ProgressBar = {
         let pb = ProgressBar(frame: CGRect(x: 0, y: 0, width: 200, height: 16))
     }()
  }
}

И этот код вызывается из контроллера представления:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.row == 0 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell1") as! CustomTableViewCell
            cell.configure()
            return cell
}

edit 2 - настраиваемое представлениекод:

class ProgressBar: UIView {

    var progressView: UIView = {
        let v = UIView()
        v.backgroundColor = .white
        return v
    }()

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

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

    func configure() {
        backgroundColor = UIColor(white: 1.0, alpha: 0.1)
        layer.cornerRadius = 8.0
        clipsToBounds = true

        progressView.frame = bounds
        progressView.frame.size.width = 0.0
        addSubview(progressView)
    }

    func animate(_ pct: CGFloat) -> Void {
        UIView.animate(withDuration: 1.0, animations: {
            self.progressView.frame.size.width = self.bounds.size.width * pct
        })
    }
}

edit3 - вызов animate

    let progressBar: ProgressBar = {
        let pb = ProgressBar(frame: CGRect(x: 0, y: 0, width: 200, height: 16))
        pb.translatesAutoresizingMaskIntoConstraints = false

        if data.count >= i {
            if let session = data[i - 1].session {
                let values = Array(session).sorted(by: { $0.date.compare($1.date) == .orderedDescending })
                var sum = 0.0
                for value in values {
                    sum += Double(value.score)
                }
                pb.animate(CGFloat(sum / 40)) // returns a value between 0 and 1
            }
        }

        return pb;
    }()

edit 4:

enter image description here

edit 5- добавлены ограничения отладки:

Printing description of $16:
<UIView: 0x107d6a100; frame = (0 0; 200 16); layer = <CALayer: 0x1d003f3c0>>
Printing description of $17:
<StepUp.ProgressBar: 0x107d6c8e0; frame = (54.3333 0; 250 16); clipsToBounds = YES; layer = <CALayer: 0x1d0220880>>

1 Ответ

0 голосов
/ 03 июня 2018

Как я уже упоминал в разделе комментариев, не имеет смысла иметь представление прогресса в представлении стека, это потребует утомительных шагов для достижения анимации изменения width.

все, что вам нужно, чтобы избавиться от явной установки frame, а именно: , не указывайте ширину и высоту при использовании автоматического макета .Вместо этого используйте CGRectZero.

Затем необходимо настроить представление стека (я предполагаю, что вы используете представление вертикального стека) следующим образом:

stackView.alignment = .leading

Вы не можете использовать ни одно изfill печатает здесь.Потому что, если вы используете заливку, то все упорядоченные вложенные представления должны иметь всю ширину представления стека.В результате вы не сможете изменить их ширину для анимации.

Теперь, как только вы предоставите представление стека, .leading выровняйте обычные представления (представления, которые неимеет внутренний размер содержимого) будет задана ширина zero.Поэтому, когда вы запустите свое приложение, вы не увидите ни одного из ваших представлений.Здесь вам нужно проделать утомительную работу, давая каждому из них ширину .Одним из решений может быть: вы перечисляете через подпредставления вашего стекового представления и даете всем представлениям равную ширину с вашим стековым представлением, оставляя представление прогресса равным нулю ширины

// update these when the sub views of the view are layout already
// otherwise stack view won't have it's own size yet 
stackView.subviews.forEach { (view) in
    if view == progressView {
        // save this constraint for use when animating
        progressViewWidthConstraint = view.widthAnchor.constraint(equalToConstant: 0)
        progressViewWidthConstraint.isActive = true
    } else {
        view.widthAnchor.constraint(equalToConstant: stackView.frame.size.width).isActive = true
    }
}

Теперьваша анимация должна работать следующим образом:

view.layoutIfNeeded()
progressViewWidthConstraint.constant = stackView.frame.size.width
UIView.animate(withDuration: 2) {
    self.view.layoutIfNeeded()
}

Вот результат: Анимировать UIView в качестве просмотра прогресса внутри UIStackView

Я сделал демонстрацию если вы застряли где-нибудь в процессе.Ура ?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...