Вот как я настроил вид профиля,
-(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:@[]]). Во время анимации я просматриваю все ограничения суперпредставления, чтобы найти конкретное ограничение и обновить его.
Во время анимации вы должны использовать presentationLayer
. См. stackoverflow.com/questions/21953459/… но я не предлагаю вместо этого сохранять ссылку на ограничение...
Также было бы полезно знать, когда все это происходит. Я мог бы включить ваш код практически в том виде, в котором он есть, в демонстрационный проект, где я нажимаю кнопку в интерфейсе и чередую анимацию между высотой 64 и высотой 160, и ваш код практически в том виде, в котором он есть, будет работать. Поэтому, чтобы узнать, почему ваш код не работает, нам может потребоваться больше узнать о других аспектах среды, в которой все это происходит.
Вам следует проверить и подтвердить, что вы действительно находите ограничение высоты:
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 - Я согласен, «охота за ограничениями» - плохой метод... хотя я хотел объяснить ошибку ОП. В мой ответ добавлено изменение с использованием подхода «сохранять ссылку».
Придерживайтесь
activateConstraints
: он лучше вас знает, к чему добавить каждое ограничение. Вместо того, чтобы искать ограничение высоты во время анимации, просто сохраните ссылку на него во время его создания.