我正在研究可扩展托盘视图的代码,该视图使用UIDynamicAnimator来实现漂亮的扩展/合约动画。
为了获得逼真的加速度,我使用UIGravityBehavior
让托盘掉落,直到托盘的“标签”碰到屏幕底部。
这很有效,但即使场景中的所有项目都停止移动,也永远不会调用UIDynamicAnimatorDelegate dynamicAnimatorDidPause:
。这意味着动画师继续使用CPU周期为场景设置动画(委托已设置,并触发UIDynamicAnimatorDelegate dynamicAnimatorDidPause:
)。
我尝试从场景中移除UIGravityBehavior
,这确实导致动画师最终停止。我没有时间去除重力行为,因为我需要在一切都停止移动后将其从场景中移除。
我知道引力是一个恒定的力量,但我仍然认为一旦所有物体都有0速度和0加速度就会停止动画。
这最后的假设是假的吗?
有类似问题的人吗?
答案 0 :(得分:6)
你知道,一旦一切都休息,动画师应该暂停。
检查items
与重力行为的关联,并确保没有其他物品仍在下降。例如,很容易意外地创建以下错误:
在这种情况下,“鬼项目”将永远失效。
另一个可能的问题(尽管你的描述不太可能)是你的物品是否附加到导致无限但小的“反弹”的其他行为上。我会检查你的动画师的完整行为列表(记得检查孩子的行为)。特别是我对添加UIDynamicItemBehavior
的任何elasticity
感兴趣。
编辑:
你可能也想走另一条路。从一个非常基本的动力学系统开始,添加您的组件,直到您可以重现问题。例如,以下内容会很快收敛(记录“暂停”):
@interface PTLViewController () <UIDynamicAnimatorDelegate>
@property (nonatomic, strong) UIDynamicAnimator *animator;
@end
@implementation PTLViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(100,100,100,100)];
view.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:view];
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
self.animator.delegate = self;
UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[view]];
collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
[self.animator addBehavior:collisionBehavior];
UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[view]];
[self.animator addBehavior:gravityBehavior];
}
- (void)dynamicAnimatorDidPause:(UIDynamicAnimator *)animator {
NSLog(@"pause");
}
@end
关于获得所有物品速度的问题,我不知道一个简单的方法。遗憾的是,UIDynamicAnimator
并未直接了解其所有项目。这是间接的,因为UIDyanamicBehavior
不包含items
属性。如果这对我造成困扰,请考虑重复radar://15054405。
但是,如果您只想知道特定项目的当前线速度,则有一个解决方案。只需添加UIDynamicItemBehavior
并使用自定义操作进行记录:
UIDynamicItemBehavior *dynamicItemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[view]];
__weak UIDynamicItemBehavior *weakBehavior = dynamicItemBehavior;
dynamicItemBehavior.action = ^{
NSLog(@"Velocity: %@", NSStringFromCGPoint([weakBehavior linearVelocityForItem:view]));
};
[self.animator addBehavior:dynamicItemBehavior];
答案 1 :(得分:1)
我最近遇到过类似的问题。最后,我使用带有边界而不是项目的UICollisionBehavior
(因为否则移动的项目会撞击其他项目......)并实现委托方法collisionBehavior:beganContactForItem:withBoundaryIdentifier:atPoint:
以了解何时应该删除重力
UICollisionBehavior *collide = [[[UICollisionBehavior alloc] initWithItems:borders] retain];
[collide addItem:movingItem];
[collide setCollisionMode:UICollisionBehaviorModeBoundaries];
[collide setTranslatesReferenceBoundsIntoBoundary:YES];
如果您找到更好的解决方案,请告诉我们:)!
答案 2 :(得分:1)
我的问题是一样的。我的动画师永远不会休息所以一旦开始,我的应用程序永远消耗3到4%的CPU。我的观点似乎都在1/2秒内停止移动。因此,我不是弄清楚为什么我没有达到平衡,而是用锤子击打它并用计时器杀死动画师。我给它2秒钟。
- (void)createAnimator {
if (_timer) {
[_timer invalidate];
}
if (_animator) {
[_animator removeAllBehaviors];
}
_animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
// create all behaviors
// kill the animator in 2 seconds
_timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(killAnimator:) userInfo:nil repeats:NO];
}
- (void)killAnimator:(NSTimer *)timer {
[_animator removeAllBehaviors];
_animator = nil;
_timer = nil;
}