Czy nslayoutconstraints można animować? [duplikat]

To pytanie ma już odpowiedź tutaj:

Staram się animować niektóre widoki tak, aby były blokowane przez gigantyczną klawiaturę w krajobrazie. To działa dobrze, jeśli po prostu animować klatki, ale inni sugerują, że jest to przeciwne do produktywności i powinienem być aktualizowanie Zamiast tego NSLayoutConstraints. Jednak nie wydają się być animowane. Czy ktoś namówił ich do pracy z sukcesem?

//heightFromTop is an NSLayoutConstraint referenced from IB
[UIView animateWithDuration:0.25 animations:^{
    self.heightFromTop.constant= 550.f;
}];

Rezultatem jest natychmiastowy skok na daną wysokość.

Author: borrrden, 2012-10-17

4 answers

Po prostu postępuj zgodnie z tym wzorem:

self.heightFromTop.constant = 550.0f;
[myView setNeedsUpdateConstraints];

[UIView animateWithDuration:0.25f animations:^{
   [myView layoutIfNeeded];
}];

Gdzie myView jest widokiem, do którego dodano self.heightFromTop. Twój widok jest "skokowy", ponieważ jedyną rzeczą, którą zrobiłeś w bloku animacji, było ustawienie ograniczenia, co nie powoduje natychmiastowych układów. W kodzie układ występuje w następnej pętli run Po ustawieniu heightFromTop.constant i do tego czasu jesteś już poza zakresem bloku animacji.

W Języku Swift 2:

self.heightFromTop.constant = 550
myView.setNeedsUpdateConstraints()

UIView.animateWithDuration(0.25, animations: {
   myView.layoutIfNeeded()
})
 458
Author: John Estropia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-03 15:55:53

Sugerowany przez Apple sposób jest nieco inny (Zobacz przykład w sekcji "animowanie zmian dokonanych przez układ Automatyczny" ). Najpierw musisz wywołać layoutIfNeeded przed animacją. Następnie dodaj swoje animacje wewnątrz bloku animacji, a następnie ponownie wywołaj layoutIfNeeded na końcu. Dla facetów takich jak ja, którzy przechodzą do autolayout, jest to bardziej podobny sposób do poprzednich animacji, które robiliśmy z klatkami wewnątrz bloków animacji. Musimy tylko zadzwonić do layoutIfNeeded dwa razy-przed animacjami i po animacjach:

[self.view layoutIfNeeded]; // Ensures that all pending layout operations have been completed

[UIView animateWithDuration:1.0f animations:^{

  // Make all constraint changes here
  self.heightFromTop.constant= 550.f;

  [self.view layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes

}];
 77
Author: Centurion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-23 11:22:58

Próbowałem podejścia @ Centurion, ale jakoś mój widok animuje się do złej klatki, jeśli jest załadowany z storyboardu. Problem zniknie, jeśli zamienię pierwszą layoutIfNeeded na updateConstraintsIfNeeded, choć nie mam pojęcia dlaczego. Jeśli ktoś może dać wyjaśnienie, byłoby to bardzo mile widziane.

[self.view updateConstraintsIfNeeded];
[UIView animateWithDuration:1.0 animations:^{
    self.myConstraint.constant= 100;
    [self.view layoutIfNeeded];
}];
 9
Author: Joseph Lin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-24 00:59:05

Miałem podobny problem i ten wątek był bardzo pomocny, aby go ominąć.

Odpowiedź od erurainon postawiła mnie na dobrej drodze, ale chciałbym zaproponować nieco inną odpowiedź. Sugerowany kod z erurainon nie działał dla mnie, ponieważ nadal miałem skok zamiast animowanego przejścia. Link podany przez cnotethegr8 dał mi działającą odpowiedź:

Auto Layout Przewodnik https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html (na samym dole strony).

Kilka różnic od odpowiedzi erurainona:

  1. wywołanie layoutIfNeeded w widoku kontenera przed wywołaniem metody animacji (i zamiast setNeedsUpdateConstraints w myView).
  2. Ustaw nowe ograniczenie w animacjach blok.
  3. wywołanie layoutIfNeeded w widoku kontenera w metodzie animations (po ustawieniu ograniczenia), zamiast w myView.

Będzie to zgodne ze wzorem sugerowanym przez Apple w linku powyżej.

Przykład

Chciałem animować konkretny widok, zamykając go lub rozszerzając jednym kliknięciem. Ponieważ używam autolayout i nie chcę kodować żadnych wymiarów (w moim przypadku wysokość) w kodzie, postanowiłem uchwycić wysokość in viewDidLayoutSubviews. Musisz użyć tej metody, a nie viewWillAppear podczas korzystania z autolayout. Ponieważ viewDidLayoutSubviews może być wywoływany wiele razy, użyłem BOOL, aby dać mi znać o pierwszym uruchomieniu dla mojej inicjalizacji.

// Code snippets

@property (weak, nonatomic) IBOutlet UIView *topView; // Container for minimalView
@property (weak, nonatomic) IBOutlet UIView *minimalView; // View to animate

@property (nonatomic) CGFloat minimalViewFullHeight; // Original height of minimalView

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *minimalViewHeightConstraint;

@property (nonatomic) BOOL executedViewDidLayoutSubviews;


- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];


    // First execution of viewDidLayoutSubviews?
    if(!self.executedViewDidLayoutSubviews){
        self.executedViewDidLayoutSubviews = YES;


        // Record some original dimensions
        self.minimalViewFullHeight = self.minimalView.bounds.size.height;


        // Setup our initial view configuration & let system know that 
        // constraints need to be updated.
        self.minimalViewHeightConstraint.constant = 0.0;
        [self.minimalView setNeedsUpdateConstraints];

        [self.topView layoutIfNeeded];
    }
}

Resize full action snippet

// An action to close our minimal view and show our normal (full) view
- (IBAction)resizeFullAction:(UIButton *)sender {

    [self.topView layoutIfNeeded];

    [UIView transitionWithView:self.minimalView
                  duration:1.0
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
                    self.minimalViewHeightConstraint.constant = 0.0;

                    // Following call to setNeedsUpdateConstraints may not be necessary
                    [self.minimalView setNeedsUpdateConstraints];

                    [self.topView layoutIfNeeded];

                } completion:^(BOOL finished) {
                    ;
                }];

    // Other code to show full view
    // ...
}

Resize small action snippet

// An action to open our minimal view and hide our normal (full) view
- (IBAction)resizeSmallAction:(UIButton *)sender {

    [self.topView layoutIfNeeded];

    [UIView transitionWithView:self.minimalView
                  duration:1.0
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
                    self.minimalViewHeightConstraint.constant = self.minimalViewFullHeight;
                    [self.minimalView setNeedsUpdateConstraints];

                    [self.topView layoutIfNeeded];

                } completion:^(BOOL finished) {
                    ;
                }];

        // Other code to hide full view
        // ...
    }

Jeśli chcesz, możesz użyć programu animateWithDuration zamiast transitionWithView.

Mam nadzieję, że to pomoże.
 4
Author: Scott Carter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-01 19:49:44