之前我们接触了UIDynamic中的重力行为和碰撞行为,都比较好理解。今天我们来看另外两个行为:吸附行为(捕捉行为)UISnapBehavior 和 附着行为UIAttachmentBehavior。
从一个简单的Demo开始
先看看效果图:
这个项目展示的是两个视图View通过一根线连接起来的运动模拟,正方形物体可以随意摆动和旋转,触摸屏幕可带动两个物体一起运动,这是个很好的将吸附行为和附着行为结合的例子。
下面来看具体代码:
@implementation ViewController
{
UIDynamicAnimator *_animator; //物理仿真器
UIGravityBehavior *_gravity; //重力行为
UICollisionBehavior *_collision; //碰撞行为
UISnapBehavior *_snap; //吸附(捕捉)行为
UIAttachmentBehavior *_attach; //附着行为
UIView *_view1;
UIView *_view2;
BackView *_backView; //用来作为仿真器视图容器范围
CADisplayLink *_link;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_backView = [[BackView alloc] initWithFrame:self.view.bounds];
_view1 = [[UIView alloc] initWithFrame:CGRectMake(100, 50, 50, 50)];
_view2 = [[UIView alloc] initWithFrame:CGRectMake(100, 150, 50, 50)];
_backView.backgroundColor = [UIColor whiteColor];
_view1.backgroundColor = [UIColor blueColor];
_view1.layer.cornerRadius = 25.0;
_view2.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:0.5];
[self.view addSubview:_backView];
[_backView addSubview:_view1];
[_backView addSubview:_view2];
//初始化仿真器
_animator = [[UIDynamicAnimator alloc] initWithReferenceView:_backView];
//添加重力行为
_gravity = [[UIGravityBehavior alloc] initWithItems:nil];
[_gravity addItem:_view2];
// 添加碰撞行为
_collision = [[UICollisionBehavior alloc] initWithItems:nil];
_collision.translatesReferenceBoundsIntoBoundary = YES;
[_collision addItem:_view1];
[_collision addItem:_view2];
//添加吸附行为(捕捉行为),意思是让物体吸附到某一点上
_snap = [[UISnapBehavior alloc] initWithItem:_view1 snapToPoint:CGPointMake(125, 125)];
_snap.damping = 1.0;
//添加附着行为,让_view2视图附着在_view1周围(两物体附着的距离取决于它们的初始位置的距离)
_attach = [[UIAttachmentBehavior alloc] initWithItem:_view1 attachedToItem:_view2];
_attach.damping = 0.1; //弹力
_attach.frequency = 1.0; //频率
[_animator addBehavior:_gravity];
[_animator addBehavior:_collision];
[_animator addBehavior:_snap];
[_animator addBehavior:_attach];
//添加runloop便于绘制直线
_link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
[_link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
//此方法会在程序绘制每帧时调用一次,再调用backView的drawRect方法绘制线条
-(void)update
{
_backView.point1 = _view1.center;
_backView.point2 = _view2.center;
[_backView setNeedsDisplay];
}
//屏幕触摸事件,利用吸附行为让圆形物体跟随用户手指移动
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint pt = [[touches anyObject] locationInView:self.view];
//要先移除原来的吸附行为, 不然物体无法运动
[_animator removeBehavior:_snap];_snap = [[UISnapBehavior alloc] initWithItem:_view1 snapToPoint:pt];
_snap.damping = 1.0;
[_animator addBehavior:_snap];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint pt = [[touches anyObject] locationInView:self.view];
[_animator removeBehavior:_snap];
_snap = [[UISnapBehavior alloc] initWithItem:_view1 snapToPoint:pt];
_snap.damping = 1.0;
[_animator addBehavior:_snap];
}
_backView内代码:
@property(nonatomic, assign) CGPoint point1;
@property(nonatomic, assign) CGPoint point2;
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor purpleColor].CGColor);
CGContextSetLineWidth(context, 4.0);
CGContextMoveToPoint(context, _point1.x, _point1.y);
CGContextAddLineToPoint(context, _point2.x, _point2.y);
CGContextStrokePath(context);
}