анимация стека - сворачивание упорядоченных подпредставлений

Мне нужно использовать stackview в качестве родительского представления. Я пытаюсь анимировать stackview с двумя строками, чтобы получить эффект сжатия и раздувания нижней строки. Вы можете сказать, что я пытаюсь сделать то же самое, что и вы, когда применяете этот код к обычному автоматически раскладывающемуся представлению с подпредставлениями:

func showView()
{
    if(!expand)
    {  UIView.animateWithDuration(0.5, animations:{
        self.expandableViewHeight.constant = 50
        // Update layout of all subviews
        self.parentViewController!.view.layoutIfNeeded()})
    } else {   
      UIView.animateWithDuration(0.5, animations:{
        self.expandableViewHeight.constant = 100
        // Update layout of all subviews
        self.parentViewController!.view.layoutIfNeeded()})
    }
}

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

Это похоже на простую вещь, но я не могу этого сделать с помощью stackview. Когда я добавляю вторую строку в stackview, а затем анимирую layoutIfNeeded (), как в нескольких учебных пособиях, тогда: - при накачивании нижняя строка перемещается слева в ее позицию, - при сворачивании нижняя строка просто исчезает (без анимации) - правильно анимирован только фоновый вид (см. код)

Когда я использую ограничения по высоте и не анимирую layoutIfNeeded () в нижней строке, тогда: - при накачивании нижняя строка масштабируется до полной высоты по ходу анимации - при сворачивании - нижняя строка масштабируется до 0 как анимация идет

Не могу обрезать нижний ряд! Любые советы приветствуются! :)

Это мой код просмотра стека:

override func viewDidLoad(){
    super.viewDidLoad()

    background = UIView(frame:CGRectMake(0, 0, frame.width,frame.height))
    background.backgroundColor = UIColor.whiteColor()
    background.layer.cornerRadius = 5
    background.layer.masksToBounds = true

    self.addSubview(background)

    vStack = UIStackView()
    vStack.axis = .Vertical
    vStack.alignment = .Fill
    vStack.distribution = .Fill
    vStack.spacing = 0

    self.addArrangedSubview(vStack)

    hStack = UIStackView()
    hStack.axis = .Horizontal
    hStack.alignment = .Center
    hStack.distribution = .EqualSpacing
    hStack.spacing = 10

    hStack2 = UIStackView()
    hStack2.axis = .Horizontal
    hStack2.alignment = UIStackViewAlignment.Center
    hStack2.distribution = UIStackViewDistribution.EqualCentering
    hStack2.spacing = 10

    lquestionStack = UIStackView()
    questionStack.axis = .Horizontal
    questionStack.alignment = .Center
    questionStack.distribution = .EqualSpacing
    questionStack.spacing = QUESTION_PADDING


    let labelQuestionNumber = UIButton()
    labelQuestionNumber.userInteractionEnabled = false
    let numberImage = UIImage(named: "backgroundImage")
    labelQuestionNumber.setBackgroundImage(numberImage, forState: .Normal)

    questionStack.addArrangedSubview(labelQuestionNumber)


    hStack.addArrangedSubview(questionStack)
    vStack.addArrangedSubview(hStack)

    hStack2.addArrangedSubview(questionStack)
    vStack.addArrangedSubview(hStack2)

 }
 public func collapseInflateAction() {
    if checkWidget.collapsed {
        inflateWidget()
    } else {
        collapseWidget()
    }
    checkWidget.collapsed = !checkWidget.collapsed
}

private func collapseWidget(){
    vStack.removeArrangedSubview(self.hStack2)
    self.hStack2.removeFromSuperview()

    UIView.animateWithDuration(0.5, animations: { () -> Void in
        self.background.frame.size.height = (self.background.frame.size.height)/2
        self.layoutIfNeeded()
        self.superview?.layoutIfNeeded()
        })
}

private func inflateWidget(){
    self.vStack.addArrangedSubview(self.hStack2)

    UIView.animateWithDuration(0.5, animations: { () -> Void in
        self.background.frame.size.height = self.background.frame.size.height*2
        self.layoutIfNeeded()
        self.superview?.layoutIfNeeded()
    })

}

И это вариант двух последних методов, который использует ограничения вместо анимации layoutIfNeeded (). А также изменяемое ограничение:

override func viewDidLoad(){
    super.viewDidLoad()
(...)
 heightConstraint = NSLayoutConstraint(item: hStack2, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 0)
    self.addConstraint(heightConstraint)
}
private func collapseWidget(){
    UIView.animateWithDuration(0.5, animations: { () -> Void in
        self.background.frame.size.height = 44
        self.heightConstraint.constant = 0
        self.superview?.layoutIfNeeded()
        })
}

private func inflateWidget(){
    UIView.animateWithDuration(0.5, animations: { () -> Void in
        self.background.frame.size.height = 88
        self.heightConstraint.constant = 44
        self.superview?.layoutIfNeeded()
    })

}

person dorsz    schedule 13.11.2015    source источник
comment
Интересно, находили ли вы когда-нибудь решение своей проблемы, учитывая, сколько лет вашему вопросу. Разум разделяете это?   -  person ldiqual    schedule 23.03.2016


Ответы (2)


Это было давно, но я думаю, что это помогло добавить self.layoutIfNeeded () перед компоновкой супервизора.

   fileprivate func collapseWidget(){

    UIView.animate(withDuration: 0.25, animations: { () -> Void in
        self.background.frame.size.height = self.heightCollapsed
        self.heightConstraint.constant = self.heightCollapsed
        self.layoutIfNeeded()
        self.superview?.layoutIfNeeded()
        })
}

fileprivate func inflateWidget(){
    self.separatorView.isHidden = false
    UIView.animate(withDuration: 0.25, animations: { () -> Void in
        self.background.frame.size.height = self.heightInflated
        self.heightConstraint.constant = self.heightInflated
        self.layoutIfNeeded()
        self.superview?.layoutIfNeeded()
    })
}
person dorsz    schedule 03.02.2017
comment
Не знаю, зачем это нужно, но работает. Мне нужно было только заменить self.layoutIfNeeded() на self.superview?.layoutIfNeeded() (и то и другое не нужно) - person malvarez; 09.03.2020

В этом случае что-то, что могло бы помочь людям заставить их анимацию работать плавно, - это активировать layoutIfNeeded() на самом высоком представлении в иерархии.

Это особенно полезно, когда ваш UIStackView встроен в UIScrollView. Если вы активируете layoutIfNeeded только на своем arrangedSubviews или UIStackView, вы получите странные сбои в вашей анимации.

Другое решение - слишком простой запуск layoutIfNeeded в вашем UIViewController представлении.

Надеюсь, этот ответ поможет.

person Steven    schedule 15.05.2020