ios - 활성화 - 오라클 테이블 생성 제약 조건




제약 조건 변경 사항을 어떻게 애니메이트합니까? (9)

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

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

강력한 참조를 보유하기 위해 클래스 변수에 대상으로 지정할 제약 조건을 만듭니다. Swift에서 저는 게으른 변수를 사용했습니다 :

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

어떤 실험을 한 후에는 제약 조건이 정의 된 두 개의 뷰인 ABOVE (일명 superview) 뷰에서 제약 조건을 가져와야합니다. 아래 예제에서 (MNGStarRating과 UIWebView는 둘 사이에 제약 조건을 만드는 두 가지 유형의 항목이며 self.view 내의 하위 뷰입니다).

필터 체이닝

Swift의 필터 방법을 이용하여 변곡점 역할을 할 원하는 구속 조건을 분리합니다. 하나는 훨씬 더 복잡해질 수 있지만 여기서는 필터가 훌륭하게 작동합니다.

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에주의하십시오. 때로는 아무 일도 일어나지 않을 때 다른보기의 일부를 숨기거나보기 디버거를 사용하여 애니메이션보기를 찾아야합니다. Storyboard의 xml에서 사용자 정의 런타임 속성이 손실되어 애니메이션보기가 적용되는 경우도 발견되었습니다 (작동하는 동안).

  2. 문서 (신구문), 빠른 도움말 및 헤더를 읽으려면 항상 잠시 시간을 내십시오. Apple은 AutoLayout 제약 조건을보다 잘 관리하기 위해 많은 변화를 계속하고 있습니다 (스택 뷰 참조). 또는 적어도 AutoLayout 요리 책 . 때로는 최상의 솔루션이 이전 문서 / 비디오에 있음을 명심하십시오.

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

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

  5. 필요한 경우 제약 조건 정의에 참여하는보기와 관련된 레이아웃 여백을 사용하는 것을 주저하지 마십시오. let viewMargins = self.webview.layoutMarginsGuide : is on example
  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를 추가 할 위치와 같은 간단한 정보를 잊어 버린 경우에는 아무 일도 일어나지 않을 것입니다. 어떤 경우에는 다음과 같이 반쯤 구운 해결책이있을 수 있습니다.

주의 - 아래의 AutoLayout Section and Original guide를 읽어보십시오. 이러한 기술을 사용하여 동적 애니메이터를 보완하는 방법이 있습니다.

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
        }

    }

AutoLayout Guide의 스 니펫 (두 번째 스 니펫은 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에서 확인하십시오.

집중 해주세요

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

행운을 빈다.

AdBannerView 로 오래된 앱을 업데이트하고 광고가없는 경우 화면에서 벗어납니다. 광고가 있으면 화면에 표시됩니다. 기본적인 것들.

이전 스타일, 애니메이션 블록에서 프레임을 설정했습니다. 새로운 스타일, Y 위치를 결정하는 제약 조건에 IBOutlet 이 있습니다.이 경우에는 수퍼 뷰의 맨 아래로부터의 거리이며 상수를 수정합니다.

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

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

그리고 배너는 정확히 예상대로 움직이지만 애니메이션은 없습니다.

업데이트 : 애니메이션을 다루는 WWDC12 비디오 " 마스터 레이아웃 자동 레이아웃 우수 사례 "를 다시 보았습니다. 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;
}

참고로, 나는 수없이 많은 시간을 점검했고 이것은 메인 스레드에서 실행 중이다.


Constraints에 애니메이션을 적용하려고했는데 좋은 설명을 찾지 못했습니다.

다른 답변이 말하는 것은 완전히 사실입니다. [self.view layoutIfNeeded]; 를 호출해야합니다 [self.view layoutIfNeeded]; inside animateWithDuration: animations: . 그러나, 또 다른 중요한 점은 당신이 애니메이트하고자하는 모든 NSLayoutConstraint 대한 포인터를 가지는 것입니다.

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


동료 Xamarians의 경우 여기 Xamarin.iOS / C # 버전이 있습니다.

UIView.Animate(5, () =>
{
    _addBannerDistanceFromBottomConstraint.Constant = 0;
    View.LayoutIfNeeded();
});

두 가지 중요한 메모 :

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

  2. 제약 조건이 붙은 자식 뷰가 아니라 부모 뷰 (예 : self.view )에서 구체적으로 호출해야합니다. 이렇게하면 제약 조건을 변경 한 뷰에 제약이 될 수있는 다른 뷰의 애니메이션을 포함하여 모든 제약 뷰가 업데이트됩니다 (예 : 뷰 A가 뷰 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()
}

이에 대한 기사가 있습니다. 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];
        }];
    }
}

희망이 도움이됩니다.


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

샘플 코드 :

[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];
}];

샘플 설정 :

논쟁

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

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

생기:

샘플 프로젝트

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


제약 애니메이션의 컨텍스트에서 keyboard_opened 알림 내에서 제약 조건을 즉시 애니메이션으로 처리하는 특정 상황에 대해 말씀 드리고자합니다.

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

필자는 키보드 알림 내에서 일관된 부드러운 제약 애니메이션을 직접 구현할 수 없었습니다. 약 절반의 시간은 애니메이션을 사용하지 않고 새로운 위치로 이동합니다.

키보드 열기로 인해 일부 추가 레이아웃이 발생할 수도 있습니다. 10ms 지연이있는 간단한 dispatch_after 블록을 추가하면 매번 애니메이션이 실행되고 점프하지 않게되었습니다.


스위프트 4 솔루션

UIView.animate

세 가지 간단한 단계 :

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

    heightAnchor.constant = 50
    
  2. 포함 된 view 에 레이아웃이 더럽고 autolayout이 레이아웃을 다시 계산해야한다고 알려줍니다.

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

    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 는 애니메이션 캡슐화이기 때문에 나중에 참조 할 수 있습니다. 그러나 애니메이션 블록에서는 autolayout에게 프레임을 다시 계산하도록 알려주기 때문에 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()

제약 조건을 변경하고 애니메이터를 시작하는 순서는 중요합니다. 제약 조건을 변경하고 나중에 애니메이터를 남겨두면 다음 다시 그리기주기가 자동 레이아웃 다시 계산을 호출 할 수 있으며 변경 사항이 애니메이션으로 표시되지 않습니다.

또한 하나의 애니메이터는 재사용 할 수 없으므로 한번 실행하면 다시 실행할 수 없습니다. 따라서 우리는 대화식 애니메이션을 제어하기 위해 애니메이션을 사용하지 않는 한, 실제로 애니메이터를 유지할 좋은 이유가 없다고 생각합니다.


// 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];
}];






autolayout