如何为setFrame设置动画:在Objective-C中使用自动布局

时间:2013-02-10 00:43:46

标签: ios objective-c xcode autolayout nslayoutconstraint

我正在开发一个iOS(6)应用程序,我有一个视图,其大小我更改(动画),并且在该视图中是UILabel,我想与视图一起成长,但不是按比例。

即。如果视图是一定的大小,我需要视图占据视图的90%,但是当我将视图设置得更大(达到另一个特定大小)时,我只希望它占用80%。这是为了容纳UILabel周围的其他子视图,当超级视图增长时,这些子视图将变得可见。

我已经尝试过使用NSLayoutContraints,并将前导空间设置为它需要的位置,以及设置UILabel的宽度以使其适当增长,我还尝试使用前导和尾随设置空格(因为宽度会自动增长)。

奇怪的是,我有其他的子视图我正在玩的NSLayoutContraints,在相同的动画代码块中(使用UIView animateWithDuration:...)并且它们都有效。所有这些都是间距约束,而不是尺寸限制,没有涉及UILabels所以我不知道这是否与它有任何关系......

然后我尝试设置UILabel的translatesAutoresizingMaskIntoConstraints = YES,并且只在标签上使用setFrame:虽然这会将标签的大小和位置设置在我想要的位置,但更改不是动画,所以它看起来很糟糕。 ..

还有其他人有过这方面的经验或任何想法来帮助我吗?

由于

以下是我一直在尝试的一些代码,其中“left”是标签的前导空间约束,“width”是标签的宽度约束。

在父视图控制器的动画代码块中调用setFrame方法。

- (void)setFrame:(CGRect)frame {
    [super setFrame:frame];

    float gap = ((frame.size.height - 36) - 9 * [self.account.accountData numberOfBars]) / ([self.account.accountData numberOfBars] + 1);
    for (NSLayoutConstraint *constraint in constraints) {
        constraint.constant = gap;
    }

    self.left.constant = frame.size.width * 34/160 + (2 - 34 * 140 / 160);
    self.width.constant = frame.size.width * 0.575 + 55.5;

    [self layoutIfNeeded];

}

1 个答案:

答案 0 :(得分:1)

你应该可以在代码中使用constraintWithItem执行此操作:attribute:relatedBy:toItem:attribute:multiplier:constant:。一起使用乘数和常数应该有效。将标签的宽度设置为等于其超视图的宽度,但使用乘数为0.7或0.8,然后使用常量,在视图的较小尺寸处为您提供正确的宽度。随着视图的增长,该常量值将占整个宽度的一小部分。例如,乘数为.7且常数为20,如果超级视图为100点宽,则标签为90点(100 * .7 +20)。如果视图增长到200,则标签将为160宽(或超视图的80%)。

编辑后:

实际上,我认为上面提到的方法不起作用。在WWDC 2012的演讲“掌握自动布局的最佳实践”中,他们讨论了使用核心动画或直接设置约束的动画。我认为这是你必须做后者的情况。如果你使用核心动画,标签会在视图动画时跳转到新的大小,即使两者都在动画块中(至少它对我有用 - Rob,如果你知道的更好,请发帖)。要直接为约束设置动画(在IOS中),您必须使用计时器,并增加约束常量。您可以使用NSTimer,但由于其分辨率(50-100 mSec)的限制,我发现它有点不稳定。更顺畅的方法是使用与显示刷新率相关的CADisplayLink(我认为是16.7毫秒)。所以这是我使用的代码。我在IB中的设置是一个190宽的视图,内部有170个宽标签。我对两者都有宽度限制(你需要为此添加QuartzCore框架)。

#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>

@interface ViewController ()
@property (strong,nonatomic) CADisplayLink *displayLink;
@end

@implementation ViewController {

    IBOutlet NSLayoutConstraint *labelWidthCon;
    IBOutlet NSLayoutConstraint *viewWidthCon;
}


-(IBAction)startViewTimer:(id)sender {
    [self startDisplayLink];
}

-(void)startDisplayLink {
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(expandView:)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}

- (void)stopDisplayLink {
    [self.displayLink invalidate];
    self.displayLink = nil;
}


-(void)expandView:(CADisplayLink *) link {
    labelWidthCon.constant += 5;
    viewWidthCon.constant +=10;
    if (viewWidthCon.constant > 370) [self stopDisplayLink];
}