UIStackView Gizle Animasyonu Görüntüle


83

İOS 11'de a içindeki gizleme animasyonunun davranışı UIStackViewdeğişti, ancak bunu hiçbir yerde bulamadım.

iOS 10

iOS 10 animasyonu

iOS 11

iOS 11 animasyonu

Her ikisindeki kod şudur:

UIView.animate(withDuration: DiscoverHeaderView.animationDuration,
                       delay: 0.0,
                       usingSpringWithDamping: 0.9,
                       initialSpringVelocity: 1,
                       options: [],
                       animations: {
                            clear.isHidden = hideClear
                            useMyLocation.isHidden = hideLocation
                        },
                       completion: nil)

İOS 11'de önceki davranışı nasıl geri yüklerim?

Yanıtlar:


133

Sadece aynı sorunu yaşadım. Düzeltme, stackView.layoutIfNeeded()animasyon bloğunun içine ekleniyor . stackViewSaklamak istediğiniz eşyaların konteyneri nerede ?

UIView.animate(withDuration: DiscoverHeaderView.animationDuration,
                   delay: 0.0,
                   usingSpringWithDamping: 0.9,
                   initialSpringVelocity: 1,
                   options: [],
                   animations: {
                        clear.isHidden = hideClear
                        useMyLocation.isHidden = hideLocation
                        stackView.layoutIfNeeded()
                    },
                   completion: nil)

Bunun neden iOS 11'de aniden bir sorun olduğuna emin değilim, ancak adil olmak gerekirse, her zaman önerilen yaklaşım olmuştur.


1
Sen bir kahramansın: D
Infinity James

5
Uygun ad ve 'Springham' 😆
Infinity James

4
İOS <= 10'da , animasyon bloğundaki hiddena UIStackView'nın özelliğinin subviewbazı durumlarda göz ardı edildiği bir hata vardı , bu nedenle en iyi yol, onu animasyondan hemen önce onun dışında değiştirmektir.
Iulian Onofrei

2
Benim açımdan bir yanlış anlama olabilir, ancak dokümanlardaki gibi view.layoutIfNeeded()görünmüyor, StackView'daki diğer görünümlerin konumunu güncellemek istediğimiz şey bu. developer.apple.com/documentation/uikit/uiview/…
Bir Springham

6
view.layoutIfNeeded () tamam, ancak view.isHidden = true çağrılması, eğer view zaten gizliyse (veya tam tersi) şeyi boz. Bu nedenle, görünümün değiştirmek istediğiniz gizli durum olup olmadığını kontrol ettiğinizden emin olun. if (view.isHidden == true) {view.isHidden = false}
glemoulant

5

Swift 4 Uzantısı:

// MARK: - Show hide animations in StackViews

extension UIView {

func hideAnimated(in stackView: UIStackView) {
    if !self.isHidden {
        UIView.animate(
            withDuration: 0.35,
            delay: 0,
            usingSpringWithDamping: 0.9,
            initialSpringVelocity: 1,
            options: [],
            animations: {
                self.isHidden = true
                stackView.layoutIfNeeded()
            },
            completion: nil
        )
    }
}

func showAnimated(in stackView: UIStackView) {
    if self.isHidden {
        UIView.animate(
            withDuration: 0.35,
            delay: 0,
            usingSpringWithDamping: 0.9,
            initialSpringVelocity: 1,
            options: [],
            animations: {
                self.isHidden = false
                stackView.layoutIfNeeded()
            },
            completion: nil
        )
    }
}
}

5
Benim için düzeltme self.isHidden, zaten aynıysa değeri kontrol etmek ve ayarlamamaktı.
richy

1
bu kolayca toggleAnimated (in ..., show: Bool) olarak adlandırılan 1 işlev olabilir. sadece bir satır değiştiği için :) artı benim için işe yaramadı: s
Jean Raymond Daher

Evet, 2 işlev tek işlev yaptıktan sonra sözdizimsel şeker olacaktır
ergunkocak

4

Kabul edilen cevabın yorumlarında daha önce bahsedilmişti, ama bu benim sorunumdu ve buradaki cevapların hiçbirinde değil:

Zaten gizli olan bir görünümü asla ayarlamadığınızdan emin olun isHidden = true. Bu, yığın görünümünü bozacaktır.


Bu benim sorunumdu ve aramama gerek yoktu, layoutIfNeededbu yüzden bunun doğru cevap olup olmadığını merak ediyorum.
B Roy Dawson

3

Birçok görünümü gizlemek ve göstermek için iyi olan bu işlevi paylaşmak istiyorum UIStackView, çünkü daha önce kullandığım tüm kodlarla düzgün çalışmıyordu çünkü birinin bazı katmanlardan Animasyonu kaldırması gerekiyor:

extension UIStackView {
    public func make(viewsHidden: [UIView], viewsVisible: [UIView], animated: Bool) {
        let viewsHidden = viewsHidden.filter({ $0.superview === self })
        let viewsVisible = viewsVisible.filter({ $0.superview === self })

        let blockToSetVisibility: ([UIView], _ hidden: Bool) -> Void = { views, hidden in
            views.forEach({ $0.isHidden = hidden })
        }

        // need for smooth animation
        let blockToSetAlphaForSubviewsOf: ([UIView], _ alpha: CGFloat) -> Void = { views, alpha in
            views.forEach({ view in
                view.subviews.forEach({ $0.alpha = alpha })
            })
        }

        if !animated {
            blockToSetVisibility(viewsHidden, true)
            blockToSetVisibility(viewsVisible, false)
            blockToSetAlphaForSubviewsOf(viewsHidden, 1)
            blockToSetAlphaForSubviewsOf(viewsVisible, 1)
        } else {
            // update hidden values of all views
            // without that animation doesn't go
            let allViews = viewsHidden + viewsVisible
            self.layer.removeAllAnimations()
            allViews.forEach { view in
                let oldHiddenValue = view.isHidden
                view.layer.removeAllAnimations()
                view.layer.isHidden = oldHiddenValue
            }

            UIView.animate(withDuration: 0.3,
                           delay: 0.0,
                           usingSpringWithDamping: 0.9,
                           initialSpringVelocity: 1,
                           options: [],
                           animations: {

                            blockToSetAlphaForSubviewsOf(viewsVisible, 1)
                            blockToSetAlphaForSubviewsOf(viewsHidden, 0)

                            blockToSetVisibility(viewsHidden, true)
                            blockToSetVisibility(viewsVisible, false)
                            self.layoutIfNeeded()
            },
                           completion: nil)
        }
    }
}

Bu aynı zamanda görüşlerin kaybolmaması sorununu da çözdü. Güzel!
Petr Fiala

3

Tek öğeleri gizlemek / göstermek için uzantı

% 100 ilişkili değil, ancak tek UIViewöğelerin öğelerini (yığın görünümünde veya başka herhangi bir yerde) gizlemenin kısa bir yolunu arıyorsanız , yaptığım bu basit uzantıyı kullanabilirsiniz:

extension UIView {
    func isHiddenAnimated(value: Bool, duration: Double = 0.2) {
        UIView.animate(withDuration: duration) { [weak self] in self?.isHidden = value }
    }
}

Tek bir kod satırı ile yığın görünümünde animasyonlu öğeleri rahatça gizlemek / göstermek için kullanıyorum. Misal:

validatableButton.isHiddenAnimated(value: false)

1

Umarım bu başkalarını birkaç saat hayal kırıklığından kurtarır.

Aynı anda birden fazla UIStackView alt görünümünü gizlemek VE göstermek animasyon yapmak bir karmaşa.

Bazı durumlarda animasyon bloklarındaki .isHidden değişiklikleri bir sonraki animasyona kadar doğru şekilde görüntülenir, ardından .isHidden yoksayılır. Bunun için bulduğum tek güvenilir numara, animasyon bloğunun tamamlama bölümünde .isHidden talimatlarını tekrar etmektir.

    let time = 0.3

    UIView.animate(withDuration: time, animations: {

        //shows
        self.googleSignInView.isHidden = false
        self.googleSignInView.alpha = 1
        self.registerView.isHidden = false
        self.registerView.alpha = 1

        //hides
        self.usernameView.isHidden = true
        self.usernameView.alpha = 0
        self.passwordView.isHidden = true
        self.passwordView.alpha = 0

        self.stackView.layoutIfNeeded()

    }) { (finished) in

        self.googleSignInView.isHidden = false
        self.registerView.isHidden = false
        self.usernameView.isHidden = true
        self.passwordView.isHidden = true
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.