구속 조건 변경에 애니메이션을 적용하려면 어떻게합니까?


959

와 함께 이전 앱을 업데이트하고 있으며 AdBannerView광고가 없으면 화면에서 사라집니다. 광고가 있으면 화면에서 슬라이드됩니다. 기본 물건.

이전 스타일, 애니메이션 블록에서 프레임을 설정했습니다. 새로운 스타일, 위치 IBOutlet를 결정하는 자동 레이아웃 제약 조건 Y이 있습니다.이 경우 슈퍼 뷰의 하단에서 거리를두고 상수를 수정하십시오.

- (void)moveBannerOffScreen {
    [UIView animateWithDuration:5 animations:^{
        _addBannerDistanceFromBottomConstraint.constant = -32;
    }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen {
    [UIView animateWithDuration:5 animations:^{
        _addBannerDistanceFromBottomConstraint.constant = 0;
    }];
    bannerIsVisible = TRUE;
}

배너는 예상대로 정확하게 움직이지만 애니메이션은 없습니다 .


업데이트 : 애니메이션을 다루는 자동 레이아웃 마스터 링에 대한 WWDC 12 토크 모범 사례를 다시 보았습니다 . CoreAnimation을 사용하여 제약 조건을 업데이트하는 방법에 대해 설명합니다 .

다음 코드로 시도했지만 정확히 동일한 결과를 얻습니다.

- (void)moveBannerOffScreen {
    _addBannerDistanceFromBottomConstraint.constant = -32;
    [UIView animateWithDuration:2 animations:^{
        [self.view setNeedsLayout];
    }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen {
    _addBannerDistanceFromBottomConstraint.constant = 0;
    [UIView animateWithDuration:2 animations:^{
        [self.view setNeedsLayout];
    }];
    bannerIsVisible = TRUE;
}

참고로, 나는 여러 번 확인했으며 이것은 메인 스레드 에서 실행되고 있습니다.


11
나는 전에 SO에 오타에 대한 질문과 답변을 제공하는 많은 표를 본 적이
abbood

3
답변에 오타가 있으면 답변을 편집해야합니다. 이것이 편집 가능한 이유입니다.
i_am_jorf

@ jeffamaphone-오타를 지적하면 실수가 어디에 있는지 알면 더 유용 할 것입니다. 답을 직접 편집하고 오타를 수정하여 다른 모든 사람들이 당뇨병을 예방할 수 있습니다. 방금 애니메이션 블록에서 상수를 제거하도록 편집했습니다.
DBD

1
오타가 무엇인지 모르겠습니다. 위의 의견에 답변했습니다.
i_am_jorf

9
그렇다면 오타 문제입니다. 어리석게도 "layoutIfNeeded"대신 "setNeedsLayout"을 입력하고있었습니다. 오류가있는 코드와 올바른 명령으로 스크린 샷을 잘라 붙여 넣을 때 내 질문에 명확하게 표시됩니다. 그러나 누군가 지적하기 전까지는 알아 차리지 못했습니다.
DBD

답변:


1696

두 가지 중요한 사항 :

  1. layoutIfNeeded애니메이션 블록 내에서 호출해야합니다 . 실제로 보류중인 모든 레이아웃 작업이 완료되도록 애니메이션 블록 전에 한 번 호출하는 것이 좋습니다.

  2. 구속 조건이 첨부 된 자식보기가 아닌 부모보기 (예 :)에서 구체적으로 호출해야 self.view합니다. 이렇게하면 구속 조건을 변경 한 뷰로 제한 될 수있는 다른 뷰 애니메이션을 포함하여 모든 제한된 뷰 가 업데이트됩니다 (예 : 뷰 B가 뷰 A의 하단에 부착되고 뷰 A의 상단 오프셋이 변경되었으며 뷰 B를 원함) 애니메이션으로)

이 시도:

목표 -C

- (void)moveBannerOffScreen {
    [self.view layoutIfNeeded];

    [UIView animateWithDuration:5
        animations:^{
            self._addBannerDistanceFromBottomConstraint.constant = -32;
            [self.view layoutIfNeeded]; // Called on parent view
        }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen { 
    [self.view layoutIfNeeded];

    [UIView animateWithDuration:5
        animations:^{
            self._addBannerDistanceFromBottomConstraint.constant = 0;
            [self.view layoutIfNeeded]; // Called on parent view
        }];
    bannerIsVisible = TRUE;
}

스위프트 3

UIView.animate(withDuration: 5) {
    self._addBannerDistanceFromBottomConstraint.constant = 0
    self.view.layoutIfNeeded()
}

199
당신은 당신의 대답이 무엇인지 알고 있습니다. WWDC가 작동합니다 .... 내 비전이 실패합니다. 어떤 이유로 내가 setNeedsLayout대신 전화했다는 것을 깨닫는 데 일주일이 걸렸습니다 layoutIfNeeded. 나는 방금 잘못된 메소드 이름을 입력했다는 사실을 알지 못하고 몇 시간을 보냈는지 약간 두려워합니다.
DBD

23
솔루션은 작동하지만 애니메이션 블록 에서 구속 상수를 변경할 필요는 없습니다 . 애니메이션을 시작하기 전에 구속 조건을 한 번 설정하는 것이 좋습니다. 답을 편집해야합니다.
Ortwin Gentz

74
이것은 처음에는 효과가 없었으며 제약 조건이 적용되는 뷰가 아닌 PARENT 뷰에서 layoutIfNeeded를 호출해야한다는 것을 깨달았습니다.
Oliver Pearmain

20
layoutIfNeeded를 사용하면 구속 조건 변경뿐만 아니라 모든 서브 뷰 새로 고침에 애니메이션이 적용됩니다. 구속 조건 변경 만 어떻게 애니메이션합니까?
ngb

11
"애플은 실제로 보류중인 모든 레이아웃 작업이 완료되도록 애니메이션 블록 전에 한 번 호출하는 것이 좋습니다."
Rick van der Linde

109

제공된 답변에 감사하지만 조금 더 나아가면 좋을 것 같습니다.

문서의 기본 블록 애니메이션

[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
     // Make all constraint changes here
     [containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];

그러나 이것은 매우 간단한 시나리오입니다. updateConstraints메서드 를 통해 하위 뷰 제약 조건에 애니메이션을 적용하려면 어떻게해야 합니까?

서브 뷰 updateConstraints 메소드를 호출하는 애니메이션 블록

[self.view layoutIfNeeded];
[self.subView setNeedsUpdateConstraints];
[self.subView updateConstraintsIfNeeded];
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionLayoutSubviews animations:^{
    [self.view layoutIfNeeded];
} completion:nil];

updateConstraints 메소드는 UIView 서브 클래스에서 대체되며 메소드 끝에서 super를 호출해야합니다.

- (void)updateConstraints
{
    // Update some constraints

    [super updateConstraints];
}

AutoLayout Guide 는 많은 것을 원하지만 읽을 가치가 있습니다. 나는 이것을 간단하고 미묘한 축소 애니메이션 (0.2 초 길이) UISwitch으로 UITextFields 쌍으로 서브 뷰를 토글하는 부분으로 이것을 사용 하고 있습니다. 서브 뷰에 대한 제한 조건은 위에서 설명한 UIView 서브 클래스 updateConstraints 메소드에서 처리됩니다.


위의 모든 메소드를 호출 할 때 self.view(그 뷰의 서브 뷰 updateConstraintsIfNeeded가 아닌 ) 호출 할 필요는 없습니다 ( 그 뷰의 setNeedsLayout트리거도 있기 때문에 updateConstraints). 가장 사소한 것일 수도 있지만, 지금까지는 그렇지 않았습니다.)
anneblue

특정 경우 Autolayout과 스프링 및 스트럿 레이아웃의 전체 상호 작용을 알지 못하면 언급하기가 어렵습니다. 순수한 자동 레이아웃 시나리오에 대해 전적으로 말하고 있습니다. layoutSubviews 메소드에서 정확히 무슨 일이 일어나고 있는지 알고 싶습니다.
카메론 로웰 팔머

TranslatesAutoresizingMaskIntoConstraints = NO; 순수 자동 레이아웃을 원한다면 반드시 이것을 비활성화해야합니다.
카메론 로웰 팔머

나는 그것을 보지 못했지만 코드가 없으면 실제로 문제에 대해 말할 수 없다. 어쩌면 TableView를 조롱하고 GitHub에 붙일 수 있습니까?
Cameron Lowell Palmer

죄송합니다, gitHub를 사용하지 않습니다 :(
anneblue

74

일반적으로 layoutIfNeeded애니메이션 블록 내에서 구속 조건을 업데이트하고 호출 하면됩니다. 이는의 .constant속성을 변경하거나 NSLayoutConstraint제약 조건 제거 (iOS 7)를 추가하거나 .active제약 조건 의 속성을 변경 (iOS 8 & 9) 할 수 있습니다.

샘플 코드 :

[UIView animateWithDuration:0.3 animations:^{
    // Move to right
    self.leadingConstraint.active = false;
    self.trailingConstraint.active = true;

    // Move to bottom
    self.topConstraint.active = false;
    self.bottomConstraint.active = true;

    // Make the animation happen
    [self.view setNeedsLayout];
    [self.view layoutIfNeeded];
}];

샘플 설정 :

Xcode Project는 샘플 애니메이션 프로젝트입니다.

논쟁

제약 조건을 변경해야하는지 여부에 대한 몇 가지 질문이 있습니다 전에 애니메이션 블록 또는 내부 가 (이전 답변을 참조하십시오).

다음은 iOS를 가르치는 Martin Pilkington과 자동 레이아웃을 작성한 Ken Ferry의 트위터 대화입니다. Ken은 애니메이션 블록 외부에서 상수를 변경하면 현재 작동 할 수 있지만 안전하지 않으며 실제로 애니메이션 블록 에서 변경해야한다고 설명합니다 . https://twitter.com/kongtomorrow/status/440627401018466305

생기:

샘플 프로젝트

뷰에 애니메이션을 적용하는 방법을 보여주는 간단한 프로젝트가 있습니다. Objective C를 사용하고 .active여러 제약 조건 의 속성을 변경하여 뷰에 애니메이션을 적용합니다 . https://github.com/shepting/SampleAutoLayoutAnimation


새로운 활성 플래그를 사용한 예를 보여 주려면 +1 또한 애니메이션 블록 외부의 제약 조건을 변경하면 항상 해킹처럼 느껴졌습니다.
Korey Hinton

이 솔루션은 뷰를 원래 위치로 다시 이동시키는 데 작동하지 않기 때문에 github에서 문제가 발생했습니다. 활성 변경이 올바른 해결책이 아니라고 생각하고 우선 순위를 대신 변경해야합니다. 상단을 750으로, 하단을 250으로 설정 한 다음 코드에서 UILayoutPriorityDefaultHigh와 UILayoutPriorityDefaultLow를 번갈아 설정합니다.
malhal

블록 내부에서 업데이트하는 또 다른 이유는 layoutIfNeeded를 호출하기 위해 발생할 수있는 호출 코드에서 변경 사항을 분리하기 때문입니다. (그리고 트위터 링크에 감사드립니다)
Chris Conover

1
좋은 대답입니다. 특히 Martin과 Ken의 대화에 대해 언급했기 때문입니다.
Jona

제약 조건을 업데이트하는 방식에 혼란스러워서 이것을 작성 했습니다 . 좀 봐 주실 래요?
Honey

36
// Step 1, update your constraint
self.myOutletToConstraint.constant = 50; // New height (for example)

// Step 2, trigger animation
[UIView animateWithDuration:2.0 animations:^{

    // Step 3, call layoutIfNeeded on your animated view's parent
    [self.view layoutIfNeeded];
}];

29

스위프트 4 솔루션

UIView.animate

세 가지 간단한 단계 :

  1. 제약 조건을 변경하십시오. 예 :

    heightAnchor.constant = 50
  2. 포함 view에 레이아웃이 더럽고 자동 레이아웃이 레이아웃을 다시 계산해야한다고 알립니다.

    self.view.setNeedsLayout()
  3. 애니메이션 블록에서 레이아웃을 다시 계산하도록 레이아웃에 지시합니다. 이는 프레임을 직접 설정하는 것과 같습니다 (이 경우 자동 레이아웃이 프레임을 설정 함).

    UIView.animate(withDuration: 0.5) {
        self.view.layoutIfNeeded()
    }

가장 간단한 예 :

heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}

사이드 노트

선택적인 0 단계가 있습니다-제약 조건을 변경하기 전에 self.view.layoutIfNeeded()애니메이션의 시작점이 이전 제약 조건이 적용된 상태에서 시작되도록해야 할 수도 있습니다 (애니메이션에 포함되어서는 안되는 다른 제약 조건 변경 사항이있는 경우) ) :

otherConstraint.constant = 30
// this will make sure that otherConstraint won't be animated but will take effect immediately
self.view.layoutIfNeeded()

heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}

UIViewPropertyAnimator

iOS 10에서는 새로운 애니메이션 메커니즘이 생겼으므로 UIViewPropertyAnimator기본적으로 동일한 메커니즘이 적용됩니다. 단계는 기본적으로 동일합니다.

heightAnchor.constant = 50
self.view.setNeedsLayout()
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
    self.view.layoutIfNeeded()
}
animator.startAnimation()

animator애니메이션의 캡슐화 이므로 계속 참조하고 나중에 호출 할 수 있습니다. 그러나 애니메이션 블록에서는 자동 레이아웃에 프레임을 다시 계산하도록 지시하기 때문에를 호출하기 전에 제약 조건을 변경해야합니다 startAnimation. 따라서 다음과 같은 것이 가능합니다.

// prepare the animator first and keep a reference to it
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
    self.view.layoutIfNeeded()
}

// at some other point in time we change the constraints and call the animator
heightAnchor.constant = 50
self.view.setNeedsLayout()
animator.startAnimation()

구속 조건을 변경하고 애니메이터를 시작하는 순서는 중요합니다. 구속 조건을 변경하고 나중에 애니메이터를 그대로두면 다음 다시 그리기주기가 자동 레이아웃 재 계산을 호출 할 수 있으며 변경 내용은 애니메이션되지 않습니다.

또한 단일 애니메이터는 재사용 할 수 없습니다. 일단 실행 한 후에는 "재실행"할 수 없습니다. 따라서 대화식 애니메이션을 제어하는 ​​데 애니메이터를 사용하지 않는 한 애니메이터를 유지할 좋은 이유는 없습니다.


👍 스위프트 5에서도
훌륭하게 작동합니다

layoutIfNeeded ()가 핵심입니다
Medhi

15

스토리 보드, 코드, 팁 및 몇 가지 단점

다른 답변은 괜찮지 만 최근 예제를 사용하여 제약 조건에 애니메이션을 적용하는 몇 가지 중요한 문제점을 강조합니다. 나는 다음을 깨닫기 전에 많은 변형을 겪었습니다.

강력한 참조를 유지하기 위해 대상 변수를 클래스 변수로 만듭니다. 스위프트에서는 게으른 변수를 사용했습니다.

lazy var centerYInflection:NSLayoutConstraint = {
       let temp =  self.view.constraints.filter({ $0.firstItem is MNGStarRating }).filter ( { $0.secondItem is UIWebView }).filter({ $0.firstAttribute == .CenterY }).first
        return temp!
}()

몇 가지 실험을 한 후에 나는 제약 조건이 정의 된 두 개의 보기 의 뷰 (일명 슈퍼 뷰) 에서 제약 조건을 얻어야한다고 언급했습니다 . 아래 예에서 (MNGStarRating과 UIWebView는 둘 사이에 제약 조건을 만드는 두 가지 유형의 항목이며 self.view 내의 하위보기입니다).

필터 체이닝

Swift의 필터 방법을 활용하여 변곡점으로 사용할 원하는 구속 조건을 분리합니다. 하나는 훨씬 더 복잡해질 수 있지만 필터는 여기서 잘 작동합니다.

스위프트를 사용하여 구속 조건 애니메이션

Nota Bene-이 예제는 스토리 보드 / 코드 솔루션이며 스토리 보드에서 기본 제한 조건을 설정했다고 가정합니다. 그런 다음 코드를 사용하여 변경 사항에 애니메이션을 적용 할 수 있습니다.

정확한 기준으로 필터링하고 애니메이션의 특정 변곡점을 얻는 속성을 생성한다고 가정하면 (물론 여러 제약 조건이 필요한 경우 배열을 필터링하고 반복 할 수 있음) :

lazy var centerYInflection:NSLayoutConstraint = {
    let temp =  self.view.constraints.filter({ $0.firstItem is MNGStarRating }).filter ( { $0.secondItem is UIWebView }).filter({ $0.firstAttribute == .CenterY }).first
    return temp!
}()

....

언젠가 ...

@IBAction func toggleRatingView (sender:AnyObject){

    let aPointAboveScene = -(max(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height) * 2.0)

    self.view.layoutIfNeeded()


    //Use any animation you want, I like the bounce in springVelocity...
    UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.75, options: [.CurveEaseOut], animations: { () -> Void in

        //I use the frames to determine if the view is on-screen
        if CGRectContainsRect(self.view.frame, self.ratingView.frame) {

            //in frame ~ animate away
            //I play a sound to give the animation some life

            self.centerYInflection.constant = aPointAboveScene
            self.centerYInflection.priority = UILayoutPriority(950)

        } else {

            //I play a different sound just to keep the user engaged
            //out of frame ~ animate into scene
            self.centerYInflection.constant = 0
            self.centerYInflection.priority = UILayoutPriority(950)
            self.view.setNeedsLayout()
            self.view.layoutIfNeeded()
         }) { (success) -> Void in

            //do something else

        }
    }
}

많은 잘못된 차례

이 노트는 실제로 내가 작성한 팁입니다. 나는 개인적으로 고통스럽게 모든 것을하지 않았다. 이 안내서가 다른 사람들을 아끼지 않기를 바랍니다.

  1. zPositioning을 조심하십시오. 아무 일도 일어나지 않는 경우 다른 뷰를 숨기거나 뷰 디버거를 사용하여 애니메이션 뷰를 찾아야합니다. 스토리 보드의 XML에서 사용자 정의 런타임 속성이 손실되어 애니메이션 뷰가 작동하는 경우를 발견했습니다.

  2. 설명서 (신규 및 이전), 빠른 도움말 및 헤더를 읽으려면 항상 1 분 정도 걸립니다. Apple은 AutoLayout 제약 조건을보다 잘 관리하기 위해 많은 변경을 계속하고 있습니다 (스택 뷰 참조). 또는 적어도 AutoLayout Cookbook 입니다. 때때로 가장 좋은 솔루션은 이전 문서 / 비디오에 있습니다.

  3. 애니메이션의 값을 가지고 놀면서 다른 animateWithDuration 변형 사용을 고려하십시오.

  4. 특정 레이아웃 값을 다른 상수에 대한 변경 사항을 결정하기위한 기준으로 하드 코딩하지 말고 대신 뷰의 위치를 ​​결정할 수있는 값을 사용하십시오. CGRectContainsRect하나의 예입니다

  5. 필요한 경우 제약 조건 정의에 참여하는 뷰와 관련된 레이아웃 여백을 사용하는 것을 망설이지 마십시오 let viewMargins = self.webview.layoutMarginsGuide.
  6. 스토리 보드에 제약 조건이있는 모든 뷰에는 self.viewName.constraints 속성에 제약 조건이 첨부되어 있습니다.
  7. 제한 조건의 우선 순위를 1000 미만으로 변경하십시오. 스토리 보드에서 내 값을 250 (낮음) 또는 750 (높음)으로 설정했습니다. (코드에서 1000 우선 순위를 변경하려고하면 1000이 필요하기 때문에 앱이 중단됩니다)
  8. activateConstraints 및 deactivateConstraints를 즉시 사용하려고 시도하지 마십시오 (그 자리가 있지만 배우는 경우 또는 스토리 보드를 사용하는 경우 아마도 너무 많은 것을 의미합니다 ~ 아래에 표시된 것처럼 장소가 있음)
  9. 실제로 코드에 새 제약 조건을 추가하지 않는 한 addConstraints / removeConstraints를 사용하지 마십시오. 대부분의 경우 스토리 보드의 뷰를 원하는 제약 조건 (보기를 화면 외부에 배치)으로 배치 한 다음 코드에서 뷰 스토리에서 이전에 생성 된 제약 조건에 애니메이션을 적용하여 뷰를 이동시키는 것으로 나타났습니다.
  10. 새로운 NSAnchorLayout 클래스와 하위 클래스로 제약 조건을 구축하는 데 많은 시간을 낭비했습니다. 이것들은 잘 작동하지만 필요한 모든 제약 조건이 스토리 보드에 이미 존재한다는 것을 깨닫는 데 시간이 걸렸습니다. 코드에서 제약 조건을 작성하는 경우이 방법을 사용하여 제약 조건을 집계하십시오.

스토리 보드를 사용할 때 피해야 할 빠른 솔루션 샘플

private var _nc:[NSLayoutConstraint] = []
    lazy var newConstraints:[NSLayoutConstraint] = {

        if !(self._nc.isEmpty) {
            return self._nc
        }

        let viewMargins = self.webview.layoutMarginsGuide
        let minimumScreenWidth = min(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height)

        let centerY = self.ratingView.centerYAnchor.constraintEqualToAnchor(self.webview.centerYAnchor)
        centerY.constant = -1000.0
        centerY.priority = (950)
        let centerX =  self.ratingView.centerXAnchor.constraintEqualToAnchor(self.webview.centerXAnchor)
        centerX.priority = (950)

        if let buttonConstraints = self.originalRatingViewConstraints?.filter({

            ($0.firstItem is UIButton || $0.secondItem is UIButton )
        }) {
            self._nc.appendContentsOf(buttonConstraints)

        }

        self._nc.append( centerY)
        self._nc.append( centerX)

        self._nc.append (self.ratingView.leadingAnchor.constraintEqualToAnchor(viewMargins.leadingAnchor, constant: 10.0))
        self._nc.append (self.ratingView.trailingAnchor.constraintEqualToAnchor(viewMargins.trailingAnchor, constant: 10.0))
        self._nc.append (self.ratingView.widthAnchor.constraintEqualToConstant((minimumScreenWidth - 20.0)))
        self._nc.append (self.ratingView.heightAnchor.constraintEqualToConstant(200.0))

        return self._nc
    }()

이러한 팁 중 하나 또는 layoutIfNeeded를 추가 할 위치와 같은보다 간단한 팁 중 하나를 잊어 버린 경우 아무 일도 일어나지 않을 것입니다.이 경우 다음과 같은 반 구운 솔루션이있을 수 있습니다.

주의 사항-아래의 자동 레이아웃 섹션과 원본 안내서를 읽으십시오. 이러한 기술을 사용하여 동적 애니메이터를 보완하는 방법이 있습니다.

UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 1.0, options: [.CurveEaseOut], animations: { () -> Void in

            //
            if self.starTopInflectionPoint.constant < 0  {
                //-3000
                //offscreen
                self.starTopInflectionPoint.constant = self.navigationController?.navigationBar.bounds.height ?? 0
                self.changeConstraintPriority([self.starTopInflectionPoint], value: UILayoutPriority(950), forView: self.ratingView)

            } else {

                self.starTopInflectionPoint.constant = -3000
                 self.changeConstraintPriority([self.starTopInflectionPoint], value: UILayoutPriority(950), forView: self.ratingView)
            }

        }) { (success) -> Void in

            //do something else
        }

    }

자동 레이아웃 안내서의 스 니펫 (두 번째 스 니펫은 OS X 사용을위한 것입니다). BTW-이것은 더 이상 현재 안내서에 없습니다. 선호하는 기술은 계속 발전하고 있습니다.

자동 레이아웃으로 변경 사항 애니메이션

자동 레이아웃으로 변경 한 애니메이션 효과를 완전히 제어해야하는 경우 프로그래밍 방식으로 구속 조건을 변경해야합니다. 기본 개념은 iOS와 OS X 모두 동일하지만 약간의 차이가 있습니다.

iOS 앱에서 코드는 다음과 같습니다.

[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
     // Make all constraint changes here
     [containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];

OS X에서는 레이어 기반 애니메이션을 사용할 때 다음 코드를 사용하십시오.

[containterView layoutSubtreeIfNeeded];
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
     [context setAllowsImplicitAnimation: YES];
     // Make all constraint changes here
     [containerView layoutSubtreeIfNeeded];
}];

레이어 기반 애니메이션을 사용하지 않는 경우 제약 조건의 애니메이터를 사용하여 상수에 애니메이션을 적용해야합니다.

[[constraint animator] setConstant:42];

시각적으로 더 잘 배우려면 Apple의 초기 비디오를 확인하십시오 .

집중 해주세요

종종 문서에는 더 큰 아이디어로 이어지는 작은 메모 나 코드 조각이 있습니다. 예를 들어 자동 레이아웃 제약 조건을 동적 애니메이터에 연결하는 것이 좋습니다.

행운을 빈다.


11

스위프트 솔루션 :

yourConstraint.constant = 50
UIView.animate(withDuration: 1.0, animations: {
    yourView.layoutIfNeeded
})

6

작업 솔루션 100 % 스위프트 3.1

모든 답변을 읽었으며 모든 응용 프로그램에서 올바르게 애니메이션을 적용하는 데 사용 된 코드 및 계층 구조를 공유하려고합니다. 여기서 일부 솔루션이 작동하지 않으므로이 순간에 iPhone 5와 같은 느린 장치에서 확인해야합니다.

self.view.layoutIfNeeded() // Force lays of all subviews on root view
UIView.animate(withDuration: 0.5) { [weak self] in // allowing to ARC to deallocate it properly
       self?.tbConstraint.constant = 158 // my constraint constant change
       self?.view.layoutIfNeeded() // Force lays of all subviews on root view again.
}

4

구속 조건에 애니메이션을 적용하려고했지만 좋은 설명을 찾기가 쉽지 않았습니다.

다른 답변이 말하는 것은 완전히 사실입니다. [self.view layoutIfNeeded];내부 에 전화해야합니다 animateWithDuration: animations:. 그러나 다른 중요한 점은 NSLayoutConstraint애니메이션을 적용하려는 모든 대상에 대한 포인터를 갖는 것 입니다.

GitHub에서 예제를 만들었습니다 .


4

Xcode 8.3.3을 사용하는 Swift 3에 대한 효과적이고 방금 테스트 된 솔루션 :

self.view.layoutIfNeeded()
self.calendarViewHeight.constant = 56.0

UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
        self.view.layoutIfNeeded()
    }, completion: nil)

self.calendarViewHeight는 customView (CalendarView)라는 제약 조건이라는 것을 명심하십시오. self.view에서 .layoutIfNeeded ()를 호출했지만 self.calendarView에서는 호출하지 않았습니다.

이 도움을 바랍니다.


3

이에 대한 기사 이야기가 있습니다 : http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was

그는 다음과 같이 코딩했습니다.

- (void)handleTapFrom:(UIGestureRecognizer *)gesture {
    if (_isVisible) {
        _isVisible = NO;
        self.topConstraint.constant = -44.;    // 1
        [self.navbar setNeedsUpdateConstraints];  // 2
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded]; // 3
        }];
    } else {
        _isVisible = YES;
        self.topConstraint.constant = 0.;
        [self.navbar setNeedsUpdateConstraints];
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded];
        }];
    }
}

도움이 되길 바랍니다.


1

제약 조건 애니메이션의 맥락에서, keyboard_opened 알림 내에서 제약 조건을 즉시 애니메이션화 한 특정 상황을 언급하고 싶습니다.

구속 조건은 텍스트 필드에서 컨테이너의 상단까지의 상단 공간을 정의했습니다. 키보드를 열면 상수를 2로 나눕니다.

키보드 알림 내에서 직접 부드러운 부드러운 구속 조건 애니메이션을 얻을 수 없었습니다. 시간의 절반 정도는 애니메이션 없이도 새로운 위치로 점프합니다.

키보드 열기의 결과로 추가 레이아웃이 발생할 수 있습니다. 지연이 10ms 인 간단한 dispatch_after 블록을 추가하면 애니메이션이 매번 실행됩니다.

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