UIView Animasyonlu Gizle / Göster


154

Basit amacım animasyon gizleme ve gösterme işlevlerini yavaşlatmak.

Button.hidden = YES;

Yeterince basit. Bununla birlikte, sadece yok olmaktan ziyade solmasını sağlamak mümkün mü? Bu şekilde profesyonelce görünmüyor.

Yanıtlar:


259

İOS 4 ve sonraki sürümlerde, bunu sadece QuartzCore'u içe aktarmaya gerek kalmadan UIView geçiş yöntemini kullanarak yapmanın bir yolu var. Sadece şunu söyleyebilirsiniz:

Hedef C

[UIView transitionWithView:button
                  duration:0.4
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
                     button.hidden = YES;
                }
                completion:NULL];

hızlı

UIView.transition(with: button, duration: 0.4, 
                  options: .transitionCrossDissolve, 
                  animations: {
                 button.hidden = false
              })

Önceki Çözüm

Michail'in çözümü işe yarayacak, ama aslında en iyi yaklaşım bu değil.

Alfa solması ile ilgili sorun, bazen farklı örtüşen görünüm katmanlarının soluklaştıkça garip görünmesidir. Core Animation kullanan başka alternatifler de var. Önce uygulamanıza QuartzCore çerçevesini ekleyin #import <QuartzCore/QuartzCore.h>ve başlığınıza ekleyin . Şimdi aşağıdakilerden birini yapabilirsiniz:

1) button.layer.shouldRasterize = YES;Michail'in cevabında verdiği alfa animasyon kodunu ayarlayın ve kullanın. Bu, katmanların garip bir şekilde karışmasını önler, ancak hafif bir performans cezasına sahiptir ve tam olarak bir piksel sınırına hizalanmamışsa düğmenin bulanık görünmesini sağlayabilir.

Alternatif:

2) Solmaya animasyon uygulamak için aşağıdaki kodu kullanın:

CATransition *animation = [CATransition animation];
animation.type = kCATransitionFade;
animation.duration = 0.4;
[button.layer addAnimation:animation forKey:nil];

button.hidden = YES;

Bu yaklaşımla ilgili güzel olan şey, canlandırılamıyor olsalar bile (örneğin, metnin veya düğmenin resmi), düğmenin herhangi bir özelliğini çapraz ifade edebilmeniz, sadece geçişi ayarlamanız ve hemen sonra özelliklerinizi ayarlamanızdır.


5
@robmathers, sadece kodunuzu test, iki kodun üstünde sadece button.hidden = HAYIR, durumun solması için çalışır; button.hidden = YES;
Jason


5
Giriş ve çıkışta transitionWithViewbaşarılı bir solma sağlamak için , animasyon yaptığınız şeyin denetimini parametre olarak kullanmalısınız.
allenh

159

UIView animasyonlu özellikleri şunlardır:

- frame
- bounds
- center
- transform
- alpha
- backgroundColor
- contentStretch

Açıklama: Animasyonlar

isHidden onlardan biri değil, bu yüzden en iyi şekilde gördüğüm gibi:

Hızlı 4:

func setView(view: UIView, hidden: Bool) {
    UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
        view.isHidden = hidden
    })
}

Hedef C:

- (void)setView:(UIView*)view hidden:(BOOL)hidden {
    [UIView transitionWithView:view duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:^(void){
        [view setHidden:hidden];
    } completion:nil];
}

8
Aslında bu basit ve en iyi cevap
Irshad Mohamed

3
Bu doğru bir şekilde canlandırırken, görüntülemeye çalıştığım UISearchBar, animasyon tamamlanana ve hemen doğru konuma atlayana kadar yanlış konumda görünüyor. Herhangi bir fikir? Arayüz Oluşturucu ve Kısıtlamalarla Storyboard'ları kullanıyorum.
Greg Hilston

5
Bu kod işe yaramıyor ...
Animasyon

2
@evya Yalnızca gizlendiğinde solmaya çalışın = HAYIR , Solmaya çalışmayın, gizli = EVET
Jason

Muhteşem. 10x çok
Vyacheslav

125

Kaybolmak için:

Objective-C

[UIView animateWithDuration:0.3 animations:^{
    button.alpha = 0;
} completion: ^(BOOL finished) {//creates a variable (BOOL) called "finished" that is set to *YES* when animation IS completed.
    button.hidden = finished;//if animation is finished ("finished" == *YES*), then hidden = "finished" ... (aka hidden = *YES*)
}];

Hızlı 2

UIView.animateWithDuration(0.3, animations: {
    button.alpha = 0
}) { (finished) in
    button.hidden = finished
}

Hızlı 3, 4, 5

UIView.animate(withDuration: 0.3, animations: {
    button.alpha = 0
}) { (finished) in
    button.isHidden = finished
}

Solmaya:

Objective-C

button.alpha = 0;
button.hidden = NO;
[UIView animateWithDuration:0.3 animations:^{
    button.alpha = 1;
}];

Hızlı 2

button.alpha = 0
button.hidden = false
UIView.animateWithDuration(0.3) {
    button.alpha = 1
}

Hızlı 3, 4, 5

button.alpha = 0
button.isHidden = false
UIView.animate(withDuration: 0.3) {
    button.alpha = 1
}

gizli devlet ile birlikte solmaya giriş / çıkış kullanarak sorunumu çözdü
ACLima

Bazı nedenlerden dolayı, hidden = YES öğesine animasyon uygulamak benim için iyi çalıştı, ancak hidden = NO öğesine animasyon uygulamak hiçbir şey yapmadı, bu yüzden alfa animasyonuyla gizli özelliği ayarlama bu yardımcı oldu.
arlomedia

Ben sadece bir demo yazıyorum, ama sadece gizli = HAYIR, çalışmalarda solmaya, garip
Jason

9

Bu küçük Swift 3 uzantısını kullanıyorum:

extension UIView {

  func fadeIn(duration: TimeInterval = 0.5,
              delay: TimeInterval = 0.0,
              completion: @escaping ((Bool) -> Void) = {(finished: Bool) -> Void in }) {
    UIView.animate(withDuration: duration,
                   delay: delay,
                   options: UIViewAnimationOptions.curveEaseIn,
                   animations: {
      self.alpha = 1.0
    }, completion: completion)
  }

  func fadeOut(duration: TimeInterval = 0.5,
               delay: TimeInterval = 0.0,
               completion: @escaping (Bool) -> Void = {(finished: Bool) -> Void in }) {
    UIView.animate(withDuration: duration,
                   delay: delay,
                   options: UIViewAnimationOptions.curveEaseIn,
                   animations: {
      self.alpha = 0.0
    }, completion: completion)
  }
}

7

Hızlı 3

func appearView() {
     self.myView.alpha = 0
     self.myView.isHidden = false

     UIView.animate(withDuration: 0.9, animations: {
         self.myView.alpha = 1
     }, completion: {
         finished in
         self.myView.isHidden = false
     })
}

7

hızlı 4.2

uzantısı ile:

extension UIView {
func hideWithAnimation(hidden: Bool) {
        UIView.transition(with: self, duration: 0.5, options: .transitionCrossDissolve, animations: {
            self.isHidden = hidden
        })
    }
}

basit yöntem:

func setView(view: UIView, hidden: Bool) {
    UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
        view.isHidden = hidden
    })
}

Bunun için nasıl gecikme ekleyebilirim?
cvdogan

7

Düzgün bir solma ve solma efektleri için bu çözümü kullanın

extension UIView {
    func fadeIn(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, completion: @escaping ((Bool) -> Void) = {(finished: Bool) -> Void in }) {
        self.alpha = 0.0

        UIView.animate(withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations: {
            self.isHidden = false
            self.alpha = 1.0
        }, completion: completion)
    }

    func fadeOut(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, completion: @escaping (Bool) -> Void = {(finished: Bool) -> Void in }) {
        self.alpha = 1.0

        UIView.animate(withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseOut, animations: {
            self.isHidden = true
            self.alpha = 0.0
        }, completion: completion)
    }
}

kullanım gibi

uielement.fadeIn()
uielement.fadeOut()

Teşekkürler


fadeOutiOS 13'te yalnızca ayarlanan çizgileri kaldırırsam çalışır self.isHidden.
Mike Taverne

6

Ben kategorisini oluşturdu UIViewbu amaçla özel bir biraz farklı konsepti bit uygulanmaktadır: visibility. Çözümümün temel farkı, [view setVisible:NO animated:YES]eşzamanlı olarak kontrol [view visible]edip doğru sonucu alabilmenizdir. Bu oldukça basit ama son derece kullanışlı.

Ayrıca, "negatif boole mantığı" kullanmaktan kaçınılmasına izin verilir ( daha fazla bilgi için bkz. Kod Tamamlandı, sayfa 269, Pozitif boole değişken adları kullanma).

hızlı

UIView+Visibility.swift

import UIKit


private let UIViewVisibilityShowAnimationKey = "UIViewVisibilityShowAnimationKey"
private let UIViewVisibilityHideAnimationKey = "UIViewVisibilityHideAnimationKey"


private class UIViewAnimationDelegate: NSObject {
    weak var view: UIView?

    dynamic override func animationDidStop(animation: CAAnimation, finished: Bool) {
        guard let view = self.view where finished else {
            return
        }

        view.hidden = !view.visible
        view.removeVisibilityAnimations()
    }
}


extension UIView {

    private func removeVisibilityAnimations() {
        self.layer.removeAnimationForKey(UIViewVisibilityShowAnimationKey)
        self.layer.removeAnimationForKey(UIViewVisibilityHideAnimationKey)
    }

    var visible: Bool {
        get {
            return !self.hidden && self.layer.animationForKey(UIViewVisibilityHideAnimationKey) == nil
        }

        set {
            let visible = newValue

            guard self.visible != visible else {
                return
            }

            let animated = UIView.areAnimationsEnabled()

            self.removeVisibilityAnimations()

            guard animated else {
                self.hidden = !visible
                return
            }

            self.hidden = false

            let delegate = UIViewAnimationDelegate()
            delegate.view = self

            let animation = CABasicAnimation(keyPath: "opacity")
            animation.fromValue = visible ? 0.0 : 1.0
            animation.toValue = visible ? 1.0 : 0.0
            animation.fillMode = kCAFillModeForwards
            animation.removedOnCompletion = false
            animation.delegate = delegate

            self.layer.addAnimation(animation, forKey: visible ? UIViewVisibilityShowAnimationKey : UIViewVisibilityHideAnimationKey)
        }
    }

    func setVisible(visible: Bool, animated: Bool) {
        let wereAnimationsEnabled = UIView.areAnimationsEnabled()

        if wereAnimationsEnabled != animated {
            UIView.setAnimationsEnabled(animated)
            defer { UIView.setAnimationsEnabled(!animated) }
        }

        self.visible = visible
    }

}

Objective-C

UIView+Visibility.h

#import <UIKit/UIKit.h>

@interface UIView (Visibility)

- (BOOL)visible;
- (void)setVisible:(BOOL)visible;
- (void)setVisible:(BOOL)visible animated:(BOOL)animated;

@end

UIView+Visibility.m

#import "UIView+Visibility.h"

NSString *const UIViewVisibilityAnimationKeyShow = @"UIViewVisibilityAnimationKeyShow";
NSString *const UIViewVisibilityAnimationKeyHide = @"UIViewVisibilityAnimationKeyHide";

@implementation UIView (Visibility)

- (BOOL)visible
{
    if (self.hidden || [self.layer animationForKey:UIViewVisibilityAnimationKeyHide]) {
        return NO;
    }

    return YES;
}

- (void)setVisible:(BOOL)visible
{
    [self setVisible:visible animated:NO];
}

- (void)setVisible:(BOOL)visible animated:(BOOL)animated
{
    if (self.visible == visible) {
        return;
    }

    [self.layer removeAnimationForKey:UIViewVisibilityAnimationKeyShow];
    [self.layer removeAnimationForKey:UIViewVisibilityAnimationKeyHide];

    if (!animated) {
        self.alpha = 1.f;
        self.hidden = !visible;
        return;
    }

    self.hidden = NO;

    CGFloat fromAlpha = visible ? 0.f : 1.f;
    CGFloat toAlpha = visible ? 1.f : 0.f;
    NSString *animationKey = visible ? UIViewVisibilityAnimationKeyShow : UIViewVisibilityAnimationKeyHide;

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    animation.duration = 0.25;
    animation.fromValue = @(fromAlpha);
    animation.toValue = @(toAlpha);
    animation.delegate = self;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    [self.layer addAnimation:animation forKey:animationKey];
}

#pragma mark - CAAnimationDelegate

- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished
{
    if ([[self.layer animationForKey:UIViewVisibilityAnimationKeyHide] isEqual:animation]) {
        self.hidden = YES;
    }
}

@end

@valentin shergin Swift sürümü geliyor?
Juan Boero

Elbette! Swift sürümünü ekledim.
Valentin Shergin

5

@Umair Afzal kodu bazı değişikliklerden sonra hızlıca 5 iyi çalışıyor

 extension UIView {

func fadeIn(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, completion: @escaping ((Bool) -> Void) = {(finished: Bool) -> Void in }) {
    self.alpha = 0.0

    UIView.animate(withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations: {
        self.isHidden = false
        self.alpha = 1.0
    }, completion: completion)
}

func fadeOut(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, completion: @escaping (Bool) -> Void = {(finished: Bool) -> Void in }) {
    self.alpha = 1.0

    UIView.animate(withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations: {
        self.alpha = 0.0
    }) { (completed) in
        self.isHidden = true
        completion(true)
    }
  }
}

kullanmak için

yourView.fadeOut()
yourView.fadeIn()

fadeout yaparken bazı sert efektler veren, burada
Dhanu K

4

Hızlı 4

extension UIView {

func fadeIn(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, completion: @escaping ((Bool) -> Void) = {(finished: Bool) -> Void in }) {
    self.alpha = 0.0

    UIView.animate(withDuration: duration, delay: delay, options: UIViewAnimationOptions.curveEaseIn, animations: {
        self.isHidden = false
        self.alpha = 1.0
    }, completion: completion)
}

func fadeOut(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, completion: @escaping (Bool) -> Void = {(finished: Bool) -> Void in }) {
    self.alpha = 1.0

    UIView.animate(withDuration: duration, delay: delay, options: UIViewAnimationOptions.curveEaseIn, animations: {
        self.alpha = 0.0
    }) { (completed) in
        self.isHidden = true
        completion(true)
    }
}
}

Ve kullanmak için, aşağıdaki gibi basit işlevleri çağırın:

yourView.fadeOut() // this will hide your view with animation
yourView.fadeIn() /// this will show your view with animation

@ MarkMckelvie'nin cevabını yeni kopyaladınız
Ashley Mills

Bir fark var, o görüşü saklamıyordu. Manzarayı da gizlemem gerekiyordu. Bunu da yaptım ve paylaşın.
Umair Afzal

3
Neden diğer cevabı kopyalayıp kendi cevabınız olarak vermek yerine yorum yapmıyorsunuz?
Ashley Mills

2

isHidden hemen bir değerdir ve üzerindeki bir animasyonu etkileyemezsiniz, bunun yerine görünümünüzü gizlemek için Alfa'yı kullanabilirsiniz

UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
        view.alpha = 0
    })

Ve göstermek için:

UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
      view.alpha = 1
})

1

Animatics kütüphanesini kullanarak ÇOK kolayca yapabilirsiniz :

//To hide button:
AlphaAnimator(0) ~> button

//to show button
AlphaAnimator(1) ~> button

1
func flipViews(fromView: UIView, toView: UIView) {

    toView.frame.origin.y = 0

    self.view.isUserInteractionEnabled = false

    UIView.transition(from: fromView, to: toView, duration: 0.5, options: .transitionFlipFromLeft, completion: { finished in            

        fromView.frame.origin.y = -900

        self.view.isUserInteractionEnabled = true

    })


}

1

Bunu deneyebilirsiniz.

 func showView(objView:UIView){

    objView.alpha = 0.0
    UIView.animate(withDuration: 0.5, animations: {
        objView.alpha = 0.0
    }, completion: { (completeFadein: Bool) -> Void in
        objView.alpha = 1.0
        let transition = CATransition()
        transition.duration = 0.5
        transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        transition.type = kCATransitionFade
        objView.layer.add(transition, forKey: nil)
    })
}

func HideView(objView:UIView){

    UIView.animate(withDuration: 0.5, animations: {
        objView.alpha = 1.0
    }, completion: { (completeFadein: Bool) -> Void in
        objView.alpha = 0.0
        let transition = CATransition()
        transition.duration = 0.5
        transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        transition.type = kCATransitionFade
        objView.layer.add(transition, forKey: nil)
    })
}

Ve görünüm adınızı iletin

        showView(objView: self.viewSaveCard)
        HideView(objView: self.viewSaveCard)

1

Görünümünüz varsayılan olarak gizli olarak ayarlanmışsa veya birçok durumda yapmanız gerektiğini düşündüğüm Gizli durumu değiştirirseniz, bu sayfadaki yaklaşımlardan hiçbiri size FadeIn / FadeOut animasyonu vermez, bu durumlardan yalnızca birine animasyon uygular, sebebi aradığınız önce false değeri için Gizli devlet ayarlarken edilir UIView.animate Bunun nedeni, ani bir görünüme neden olacak yöntemini yalnızca alfaya animasyon uygularsanız nesne alanı hala oradadır, ancak bazı UI sorunlarına neden olacak görünür değildir.

Bu yüzden en iyi yaklaşım önce görünümün gizli olup olmadığını kontrol etmektir, ardından alfa değerini 0.0 olarak ayarlayın, Gizli durumunu yanlış olarak ayarladığınızda ani bir görünürlük görmezsiniz.

func hideViewWithFade(_ view: UIView) {
    if view.isHidden {
        view.alpha = 0.0
    }

    view.isHidden = false

    UIView.animate(withDuration: 0.3, delay: 0.0, options: .transitionCrossDissolve, animations: {
        view.alpha = view.alpha == 1.0 ? 0.0 : 1.0
    }, completion: { _ in
        view.isHidden = !Bool(truncating: view.alpha as NSNumber)
    })
}

Bu, başkalarının fadeinlerin nerede çalışmadığı hakkında sorduğu sorunu çözer. Akıllı yaklaşım.
BooTooMany

1

UIView.transition (ile :) işlevi güzel ve derli toplu.

Birçoğu yayınladı ama hiçbiri sadece onu çalıştırdığınızda ortaya çıkacak bir hata olduğunu fark etmedi.

Hidden özelliğini true değerine mükemmel bir şekilde geçirebilirsiniz, oysa false değerine geçmeye çalıştığınızda, görünüm herhangi bir animasyon olmadan aniden kaybolacaktır.

Çünkü bu api sadece bir görünüm içinde çalışır , yani bir görünümü göstermek için geçiş yaptığınızda, aslında hemen kendini gösterir, sadece içeriği yavaş yavaş canlandırılır.

Bu görünümü gizlemeye çalıştığınızda, kendisi hemen gizlenir, animasyonu içeriğine anlamsız hale getirir.

Bunu çözmek için bir görünümü gizlerken geçiş hedefi, gizlemek istediğiniz görünüm yerine ana görünümü olmalıdır.

func transitionView(_ view: UIView?, show: Bool, completion: BoolFunc? = nil) {
    guard let view = view, view.isHidden == show, let parent = view.superview else { return }

    let target: UIView = show ? view : parent
    UIView.transition(with: target, duration: 0.4, options: [.transitionCrossDissolve], animations: {
        view.isHidden = !show
    }, completion: completion)
}

0

Swift 3 için çözümüm . Bu nedenle, görünümü doğru sırayla gizleyen / göstermeyen işlevi oluşturdum (gizlendiğinde - alfa değerini 0 olarak ayarlayın ve sonra true olarak saklanır; gizleme - önce görünümü ortaya çıkarın ve ardından alfa değerini 1 olarak ayarlayın):

func hide(_ hide: Bool) {
    let animations = hide ? { self.alpha = 0 } :
                            { self.isHidden = false }
    let completion: (Bool) -> Void = hide ? { _ in self.isHidden = true } :
                                            { _ in UIView.animate(withDuration: duration, animations: { self.alpha = 1 }) }
    UIView.animate(withDuration: duration, animations: animations, completion: completion)
}

Neden completionblokta hideyanlış olduğunda başka bir animasyon var ?
Giorgio

0

Swift 4 Geçişi

    UIView.transition(with: view, duration: 3, options: .transitionCurlDown,
                      animations: {
                        // Animations
                        view.isHidden = hidden
    },
                      completion: { finished in
                        // Compeleted
    })

Eski hızlı sürümler için yaklaşımı kullanırsanız bir hata alırsınız:

Cannot convert value of type '(_) -> ()' to expected argument type '(() -> Void)?'

Yararlı referans .


bu autolayout ile çalışır mı? benzer kod canlandırmıyor. isHiddendeğeri (yani anında görünümünü gösteren / gizleme) anında oluşturulur.
Crashalot

0

Bu kod, uinavigation kontrol cihazında viewController'ı itmek gibi bir animasyon verir ...

CATransition *animation = [CATransition animation];
 animation.type = kCATransitionPush;
 animation.subtype = kCATransitionFromRight;
 animation.duration = 0.3;
 [_viewAccountName.layer addAnimation:animation forKey:nil];

 _viewAccountName.hidden = true;

Bunu pop animasyonu için kullandı ...

 CATransition *animation = [CATransition animation];
 animation.type = kCATransitionPush;
 animation.subtype = kCATransitionFromLeft;
 animation.duration = 0.3;
 [_viewAccountName.layer addAnimation:animation forKey:nil];

 _viewAccountName.hidden = false;

0

Çıkılan cevaplardan bazıları denendi, bazıları sadece bir durum için çalışıyor, bazılarının iki işlev eklemesi gerekiyor.

seçenek 1

Yapacak bir şey yok view.isHidden.

extension UIView {
    func animate(fadeIn: Bool, withDuration: TimeInterval = 1.0) {
        UIView.animate(withDuration: withDuration, delay: 0.0, options: .curveEaseInOut, animations: {
            self.alpha = fadeIn ? 1.0 : 0.0
        })
    }
}

Sonra geç isFadeIn( trueveya false)

view.animate(fadeIn: isFadeIn) 

seçenek 2

Herhangi bir parametre iletmeyin. Buna göre içeri veya dışarı kaybolur isUserInteractionEnabled. Bu durum aynı zamanda ileri geri canlandırma durumuna da çok uygundur.

func animateFadeInOut(withDuration: TimeInterval = 1.0) {
    self.isUserInteractionEnabled = !self.isUserInteractionEnabled
    UIView.animate(withDuration: withDuration, delay: 0.0, options: .curveEaseInOut, animations: {
        self.alpha = self.isUserInteractionEnabled ? 1.0 : 0.0
    })
}

Sonra ara

yourView.animateFadeInOut()

Neden self.isUserInteractionEnabled?

Yerine çalıştı self.isUserInteractionEnabledtarafından self.isHiddentüm hiç şans.

Bu kadar. Bir ara bana mal ol, umarım birisine yardım eder.

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.