最近项目中遇到这样一个问题:
生成一张图片按钮,然后在图片父控件中拖拽.给图片添加一个pan手势,但发现在默认拖拽过程中,子控件可以超出父控件范围
而同事写的安卓版本子控件不超出父控件范围,因为安卓默认这样.产品经理要求与他保持一致
我的办法是:
实时获取子控件在父控件的坐标,并判断子控件的 x, y 是否超过父控件的范围,如果超过则让其停止拖拽
但遇到一个问题:
当拖拽速度比较慢时可以实现那个效果,当拖动比较快时会感觉到拖拽卡顿. 原因是拖拽和 获取子,控件坐标并判断方法 都是在主线程中执行的.后来 把获取子控件坐标并判断方法放在子线程中执行再回到主线程判断是否停止拖拽
虽然解决了问题,但是感觉太过于麻烦
最近在github上看别人代码时,无意中发现了更好的办法 -- 使用自动布局,给子控件添加约束(这里我使用 了Masonry框架),通过约束来改变子控件坐标而不是通过仿射变换来实现
注意:不要通过设置控件的transform属性值或者直接设置子控件的frame属性值(例如center)来让空间位移,否则拖动时子控件还是会超出父控件的
之前在拖拽子控件代码是
- (void)pan:(UIPanGestureRecognizer *)panGesture{
UIView *button = panGesture.view;
button.transform = CGAffineTransformTranslate(button.transform, [panGesture translationInView:panGesture.view].x, [panGesture translationInView:panGesture.view].y);
[panGesture setTranslation:CGPointZero inView:panGesture.view];
}
或是
- (void)pan:(UIPanGestureRecognizer *)panGesture{
UIView *button = panGesture.view;
CGPoint point = [panGesture translationInView:button];
CGPoint newCenter = CGPointMake(point.x + button.center.x, point.y + button.center.y);
button.center = newCenter;
[panGesture setTranslation:CGPointZero inView:button];
}
只有通过自动布局约束才能实现效果:
1. 先在子控件在创建时设置约束来控制其拖拽范围
[button mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(40, 40));
make.right.lessThanOrEqualTo(button.superview);
make.left.greaterThanOrEqualTo(button.superview);
make.top.greaterThanOrEqualTo(button.superview).offset(64);
make.bottom.right.lessThanOrEqualTo(button.superview);
}];
2. 在拖拽方法里使用约束更新子控件的坐标
- (void)pan:(UIPanGestureRecognizer *)panGesture{
UIView *button = panGesture.view;
CGPoint newCenter = CGPointMake([panGesture translationInView:button].x + button.center.x - button.superview.bounds.size.width / 2, + button.center.y + [panGesture translationInView:button].y - button.superview.bounds.size.height / 2);
[button mas_updateConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(newCenter).priorityLow();
}];
[panGesture setTranslation:CGPointZero inView:panGesture.view];
}
运行效果:
3.注意: 这种方法还是有局限性,当子控件调用transform属性放大或缩小时这种方法失效
- 子控件调用transform属性放大时: 子控件拖拽范围会超出父控件
- 子控件调用transform属性缩小时: 子控件拖拽范围会缩小