애니메이션으로 UIView 숨기기 / 보이기


154

저의 간단한 목표는 애니메이션 숨기기 및 표시 기능을 흐리게하는 것입니다.

Button.hidden = YES;

충분히 간단합니다. 그러나 그냥 사라지지 않고 페이드 아웃 할 수 있습니까? 그렇게 비전문적 인 것 같습니다.

답변:


259

iOS 4 이상에서는 QuartzCore를 가져올 필요없이 UIView 전환 방법을 사용하여이 작업을 수행 할 수 있습니다. 당신은 단지 말할 수 있습니다 :

목표 C

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

빠른

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

이전 솔루션

Michail의 솔루션은 효과가 있지만 실제로 최선의 방법은 아닙니다.

알파 페이딩의 문제점은 때때로 서로 다른 겹치는 뷰 레이어가 페이드 아웃 될 때 이상하게 보입니다. 코어 애니메이션을 사용하는 다른 대안이 있습니다. 먼저 QuartzCore 프레임 워크를 앱에 포함시키고 #import <QuartzCore/QuartzCore.h>헤더에 추가 하십시오. 이제 다음 중 하나를 수행 할 수 있습니다.

1) button.layer.shouldRasterize = YES;Michail이 자신의 답변에서 제공 한 알파 애니메이션 코드를 설정 한 다음 사용하십시오. 이렇게하면 레이어가 이상하게 블렌딩되는 것을 방지 할 수 있지만 약간의 성능 저하가 발생하며 픽셀 경계에 정확하게 정렬되지 않으면 버튼이 흐리게 보일 수 있습니다.

또는

2) 대신 다음 코드를 사용하여 페이드에 애니메이션을 적용하십시오.

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

button.hidden = YES;

이 방법의 좋은 점은 버튼의 텍스트 나 이미지와 같이 애니메이션을 적용 할 수없는 경우에도 버튼의 모든 속성을 크로스 페이드 할 수 있으며 전환을 설정 한 다음 바로 속성을 설정하는 것입니다.


5
@robmathers, 난 그냥 코드를 테스트, 두 코드 위의 상황에서 페이드에 대해 button.hidden = NO 일 때 작동합니다. button.hidden = YES 일 때 페이드 아웃에 애니메이션 효과가 없습니다.
Jason

iOS 12.0에서 작동하지 않는 것 같습니다
user3532505

5
transitionWithView성공적인 페이드 인 및 아웃을 보장하기 위해 애니메이션하려는 항목의 슈퍼 뷰를 매개 변수로 사용해야합니다 .
allenh

159

UIView 애니메이션 속성은 다음과 같습니다.

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

설명 : 애니메이션

isHidden 가장 좋은 방법은 다음과 같습니다.

스위프트 4 :

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

목표 C :

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

8
실제로 이것은 간단하고 최상의 답변입니다
Irshad Mohamed

3
이 애니메이션이 올바르게 애니메이션되는 동안 애니메이션이 완료 될 때까지 표시하려는 UISearchBar가 잘못된 위치에 나타나고 바로 올바른 위치로 이동합니다. 어떤 생각? Interface Builder 및 Constraints와 함께 스토리 보드를 사용하고 있습니다.
Greg Hilston 2016 년

5
이 코드는 작업은 ... 그것은 바로 생기를하지 않고 상태를 변경하지 않습니다
미 히어 메타에게

2
@evya 숨겨진 = 아니오 일 때 페이드 인을 위해서만 작동, 페이드 아웃을 위해 작용하지 않음, 숨겨진 = 예
Jason

대박. 10 배 많음
Vyacheslav

125

페이드 아웃하려면 :

목표 -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*)
}];

스위프트 2

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

스위프트 3, 4, 5

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

페이드 인 :

목표 -C

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

스위프트 2

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

스위프트 3, 4, 5

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

숨겨진 상태와 함께 페이드 인 / 아웃을 사용하면 내 문제가 해결되었습니다.
ACLima

어떤 이유로 든 hidden = YES로 애니메이션을 적용해도 효과가 있었지만 hidden = NO로 애니메이션을 적용해도 아무런 효과가 없었으므로 알파 애니메이션과 숨겨진 속성 설정의 조합이 도움이되었습니다.
arlomedia

난 그냥 데모를 작성하지만 숨겨진 = NO 만, 작품에서 페이드, 이상한
Jason

9

이 작은 Swift 3 확장을 사용합니다.

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

스위프트 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

스위프트 4.2

확장명 :

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

간단한 방법 :

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

이 지연을 어떻게 추가 할 수 있습니까?
cvdogan

7

부드러운 페이드 아웃 및 페이드 인 효과를 위해이 솔루션을 사용하십시오.

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

사용법은

uielement.fadeIn()
uielement.fadeOut()

감사


fadeOut내가 설정 한 줄을 제거해야 iOS 13에서 작동합니다 self.isHidden.
Mike Taverne

6

UIView이 목적 을 위해 카테고리를 만들고 특별한 약간 다른 개념을 구현했습니다 visibility. 내 솔루션의 주요 차이점은 호출 [view setVisible:NO animated:YES]후 바로 동기화하여 확인 [view visible]하고 올바른 결과를 얻을 수 있다는 것입니다. 이것은 매우 간단하지만 매우 유용합니다.

또한 "부울 부울 논리"를 사용하지 않아도됩니다 (자세한 내용은 269 ​​페이지 코드 완료, 양의 부울 변수 이름 사용 참조 ).

빠른

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
    }

}

목표 -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 버전이오고 있습니까?
Juan Boero

확실한! Swift 버전을 추가했습니다.
Valentin Shergin

5

@Umair Afzal의 코드는 약간의 변경 후 swift 5에서 잘 작동합니다.

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

사용하기위한

yourView.fadeOut()
yourView.fadeIn()

페이드 아웃하는 동안 약간의 효과를 제공, 여기에
Dhanu K

4

스위프트 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)
    }
}
}

그리고 그것을 사용하려면 다음과 같이 간단히 다음 함수를 호출하십시오.

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

방금 @MarkMckelvie의 답변을 복사했습니다.
Ashley Mills

차이점이 있습니다. 그는 시야를 숨기지 않았습니다. 그리고 뷰도 숨겨야했습니다. 그렇게하고 공유했습니다.
Umair Afzal

3
다른 답변을 복사하여 자신의 것으로 전달하는 대신 다른 답변에 대해 왜 언급하지 않습니까?
Ashley Mills

2

isHidden 즉각적인 가치이며 애니메이션에 영향을 줄 수 없으며 대신 알파를 사용하여 뷰를 숨길 수 있습니다

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

그리고 보여주기 위해 :

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


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

당신은 이것을 시도 할 수 있습니다.

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

뷰 이름을 전달하십시오.

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

1

뷰가 기본적으로 숨김으로 설정되어 있거나 숨겨져있는 상태를 변경하는 경우가 많지만이 페이지의 어떤 방법도 FadeIn / FadeOut 애니메이션을 제공하지 않으면 이러한 상태 중 하나만 애니메이션으로 표시합니다. 그 이유는 UIView.animate 메서드를 호출하기 전에 Hidden 상태를 false로 설정하여 갑작스런 가시성을 유발하고 알파에만 애니메이션을 적용하면 객체 공간이 여전히 남아 있지만 표시되지 않아 일부 UI 문제가 발생하기 때문입니다.

따라서 가장 좋은 방법은 먼저 뷰가 숨겨져 있는지 확인한 다음 알파를 0.0으로 설정하는 것입니다. 숨겨진 상태를 false로 설정하면 갑자기 표시되지 않습니다.

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

이것은 다른 사람들이 어디 페데 인이 작동하지 않았는 지에 대한 질문을 해결합니다. 영리한 접근.
BooTooMany

1

UIView.transition (with :) 함수는 훌륭하고 깔끔합니다.

많은 사람들이 그것을 게시했지만 아무도 그것을 실행할 때만 오류가 표시되는 것을 알지 못했습니다.

숨겨진 속성을 완벽하게 true로 전환 할 수 있지만, 속성을 false로 전환하려고하면 뷰가 애니메이션없이 갑자기 사라집니다.

이 api 는보기 에서만 작동하기 때문에 보기를 전환하여 표시 할 때 실제로 그 자체 만 즉시 표시되며 콘텐츠 만 점차적으로 애니메이션으로 표시됩니다.

이보기를 숨기려고하면 즉시 숨겨져 서 해당 내용의 애니메이션이 의미가 없게됩니다.

이를 해결하려면 뷰를 숨길 때 전환 대상이 숨기려는 뷰 대신 상위 뷰 여야합니다.

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

스위프트 3에 대한 내 솔루션 . 그래서 올바른 순서로보기를 숨기거나 숨기기 해제하는 함수를 만들었습니다 (숨기기-알파를 0으로 설정하고 isHidden을 true로 설정하면 숨기지 않음-먼저보기를 표시 한 다음 알파를 1로 설정하십시오).

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

거짓 일 completion때 왜 다른 애니메이션이 블록에 hide있습니까?
조르지오

0

스위프트 4 전환

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

구식 빠른 버전에 대한 접근 방식을 사용하면 오류가 발생합니다.

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

유용한 참조 .


자동 레이아웃과 함께 작동합니까? 유사한 코드가 애니메이션되지 않습니다. isHidden값 (즉, 즉시보기를 표시 / 숨기기) 즉시 렌더링됩니다.
Crashalot

0

이 코드는 uinavigation 컨트롤러에서 viewController를 누르는 것과 같은 애니메이션을 제공합니다.

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

 _viewAccountName.hidden = true;

팝 애니메이션에 사용했습니다 ...

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

 _viewAccountName.hidden = false;

0

종료 된 답변 중 일부를 시도했지만 일부는 한 상황에서만 작동하며 일부는 두 가지 기능을 추가해야합니다.

옵션 1

와는 아무런 관련이 없습니다 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
        })
    }
}

그런 다음 isFadeIn( true또는 false)

view.animate(fadeIn: isFadeIn) 

옵션 2

매개 변수를 전달하지 마십시오. 에 따라 페이드 인 또는 페이드 아웃됩니다 isUserInteractionEnabled. 이것은 또한 애니메이션이 앞뒤로 움직이는 상황에 매우 적합합니다.

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

그런 다음 전화

yourView.animateFadeInOut()

self.isUserInteractionEnabled?

교체 시도 self.isUserInteractionEnabledself.isHidden전혀 행운.

그게 다야. 언젠가는 비용이 들었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.