Я пытался обновить ограничение высоты моего представления во время анимации. Не обновляется, почему..?

Вот как я настроил вид профиля,

-(void)addProfileView
{
    if (!_profileView)
    {
        _profileView = [ProfileView new];
        _profileView.clipsToBounds = YES;
        _profileView.delegate=self;
        _profileView.alpha = 1.0;
        _profileView.opaque = YES;
        _profileView.translatesAutoresizingMaskIntoConstraints = false;
        [self.view addSubview:_profileView];
        NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:_profileView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0 constant:160];
        NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:_profileView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
        NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:_profileView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:0];
        NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:_profileView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:-64];
        [NSLayoutConstraint activateConstraints:@[heightConstraint, widthConstraint, leftConstraint, topConstraint]];
    }
}

Теперь, почему высота профиля не меняется после анимации? Должен ли я добавить ограничения в суперпредставление? В чем разница между добавлением ограничений непосредственно в суперпредставление и использованием [NSLayoutConstraint activeConstraints:@[]] ?

-(void)animateProfileViewBasedOnOffset:(BOOL)isTop
{
__block NSLayoutConstraint *heightConstraint;
    
    for (NSLayoutConstraint * constraint in [_profileView constraints]) {
        if (constraint.firstAnchor == NSLayoutAttributeHeight) {
            heightConstraint = constraint;
            break;
        }
    }
    
    [UIView animateWithDuration:0.3 animations:^{
        if (isTop) {
            heightConstraint.constant = 64;
        }
        else {
            heightConstraint.constant = 160;
        }
        [_profileView layoutIfNeeded];
        [self.view layoutIfNeeded];
    }completion:^(BOOL completion)
     {
         NULL;
     }];
}

Высота профиляView меняется только тогда, когда я добавляю его ограничение в суперпредставление ([self.view addConstraints:@[]]). Во время анимации я просматриваю все ограничения суперпредставления, чтобы найти конкретное ограничение и обновить его.

Придерживайтесь activateConstraints: он лучше вас знает, к чему добавить каждое ограничение. Вместо того, чтобы искать ограничение высоты во время анимации, просто сохраните ссылку на него во время его создания.

matt 18.06.2024 18:10

Во время анимации вы должны использовать presentationLayer. См. stackoverflow.com/questions/21953459/… но я не предлагаю вместо этого сохранять ссылку на ограничение...

Larme 18.06.2024 18:22

Также было бы полезно знать, когда все это происходит. Я мог бы включить ваш код практически в том виде, в котором он есть, в демонстрационный проект, где я нажимаю кнопку в интерфейсе и чередую анимацию между высотой 64 и высотой 160, и ваш код практически в том виде, в котором он есть, будет работать. Поэтому, чтобы узнать, почему ваш код не работает, нам может потребоваться больше узнать о других аспектах среды, в которой все это происходит.

matt 18.06.2024 18:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам следует проверить и подтвердить, что вы действительно находите ограничение высоты:

for (NSLayoutConstraint * constraint in [_profileView constraints]) {
    if (constraint.firstAnchor == NSLayoutAttributeHeight) {
        heightConstraint = constraint;
        break;
    }
}
if (heightConstraint) {
    NSLog(@"Found Height Constraint: %@", heightConstraint);
} else {
    NSLog(@"Did NOT find Height Constraint!");
}

Этот код (в моем быстром тесте) НЕ находит ограничение высоты, поэтому, конечно, никакой анимации.

Этот код:

for (NSLayoutConstraint *constraint in _profileView.constraints) {
    // Check if the constraint is a height constraint
    if (constraint.firstAttribute == NSLayoutAttributeHeight && constraint.firstItem == _profileView) {
        // Found the height constraint
        heightConstraint = constraint;
        break;
    }
}
if (heightConstraint) {
    NSLog(@"Found Height Constraint: %@", heightConstraint);
} else {
    NSLog(@"Did NOT find Height Constraint!");
}

Находит ограничение высоты, и анимация происходит так, как ожидалось.


В качестве примечания: возможно, вам захочется рассмотреть более современный способ установки ограничений. Это соответствует вашим ограничениям, но я думаю, вы согласитесь, что это гораздо более читабельно (и гораздо проще редактировать при необходимости):

[NSLayoutConstraint activateConstraints:@[
    [_profileView.heightAnchor constraintEqualToConstant:160.0],
    [_profileView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor],
    [_profileView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor],
    [_profileView.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:-64.0],
]];

Редактировать

Как упоминалось в комментариях Мэтта, вам (почти всегда) лучше добавить свойство ограничения, которое вы можете обновить при желании.

Вот пример такого подхода:

#import <UIKit/UIKit.h>

@interface AnimSubViewController : UIViewController
@end

@interface AnimSubViewController ()
@property (strong, nonatomic) UIView *profileView;
@property (strong, nonatomic) NSLayoutConstraint *heightConstraint;
@end

@implementation AnimSubViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = UIColor.systemBackgroundColor;
    
    [self addProfileView];
}

-(void)addProfileView
{
    if (!_profileView)
    {
        //_profileView = [ProfileView new];
        _profileView = [UIView new];
        _profileView.backgroundColor = UIColor.redColor;
        _profileView.clipsToBounds = YES;
        //_profileView.delegate=self;
        _profileView.alpha = 1.0;
        _profileView.opaque = YES;
        _profileView.translatesAutoresizingMaskIntoConstraints = false;
        [self.view addSubview:_profileView];

        // set the _heightConstraint property, so we can modify its .constant later
        _heightConstraint = [_profileView.heightAnchor constraintEqualToConstant:160.0];
        
        [NSLayoutConstraint activateConstraints:@[
            //[_profileView.heightAnchor constraintEqualToConstant:160.0],
            _heightConstraint,
            [_profileView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor],
            [_profileView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor],
            [_profileView.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:-64.0],
        ]];

    }
}

-(void)animateProfileViewBasedOnOffset:(BOOL)isTop
{

    [UIView animateWithDuration:0.3 animations:^{
        if (isTop) {
            self->_heightConstraint.constant = 64;
        }
        else {
            self->_heightConstraint.constant = 160;
        }
        // not needed
        //[self->_profileView layoutIfNeeded];
        
        [self.view layoutIfNeeded];
        
    } completion:^(BOOL completion) {
        NULL;
    }];
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    // hide/show _profileView on tap anywhere
    [self animateProfileViewBasedOnOffset:_heightConstraint.constant == 160.0];
}

@end

Я бы посоветовал ОП не слушать это, а сделать то, что я предложил в своем комментарии: «Вместо того, чтобы искать ограничение высоты во время анимации, просто сохраняйте ссылку на него во время его создания». Охота за ограничениями — плохой метод, даже если вы сможете заставить его работать. Это антипаттерн. Мы заранее знаем, что нам понадобится изменить ограничение этого единственного ограничения; поэтому правильный шаблон — сохранить ссылку на него.

matt 19.06.2024 17:38

@matt - Я согласен, «охота за ограничениями» - плохой метод... хотя я хотел объяснить ошибку ОП. В мой ответ добавлено изменение с использованием подхода «сохранять ссылку».

DonMag 19.06.2024 17:57

Другие вопросы по теме