東引甌越

不断学习, 与时俱进. - 始于2017

嗨,我是孙亚洲(@sunyazhou13),一名来自北国冰城的iOS开发者,也搞过一些mac.现居帝都北京.开发数年有余,没有为往圣续绝学深感惭愧.望诸位同仁多多指教.


使用Masonry约束实现简单的高级拖拽视图

前言

本文具有强烈的个人感情色彩,如有观看不适,请尽快关闭. 本文仅作为个人学习记录使用,也欢迎在许可协议范围内转载或使用,请尊重版权并且保留原文链接,谢谢您的理解合作. 如果您觉得本站对您能有帮助,您可以使用RSS方式订阅本站,这样您将能在第一时间获取本站信息.

背景

最近开发遇到一个上图的需求,做一个挂件能四处拖动并且上边还时不时的展示一个tips气泡的Label,在尽量使用少的代码来实现这个功能,作为我手一名iOS开发人员必须严格考究这个需求,显然这有点麻烦,一贯懒惰我的实在不想计算哪个边哪个角甚至滑动到哪里的frame,计算frame这既听起来可笑又觉的没什么技术含量. 为了让代码量少并且能满足需求,我选择使用Masonry来实现这个功能

开搞

首先我搞起之前我建议大家看下土土哥有趣的Autolayout示例1~5Masonry实现文章,本文也是参考土土哥的文章学习写出的,见笑了各位,个人认为土土哥的文章简直就是Masonry自动布局的样板教程,强烈建议入门的小伙伴或者高手经常复写.

下面的图是土土哥实现的demo

但我的问题是怎么保证那个tip的气泡label左右拖拽能辗转腾挪的允许logo图像之间有旷量移动

代码实现旷量移动

首先我们创建一个demo,很简单VC的demo就行 创建相关绿色背景视图和图像imageView以及tipLabel的气泡视图,具体代码我贴了出来,我就不啰嗦如何创建其它视图了xib拖拽一下就行了.

#import "ViewController.h"
#import <Masonry/Masonry.h>
@interface ViewController ()
@property (weak, nonatomic ) IBOutlet UIView *greenView;
@property (weak, nonatomic ) IBOutlet UIImageView *widgetView;
@property (weak, nonatomic ) IBOutlet UILabel *bubbleTitleLabel;
@property (nonatomic, strong) MASConstraint *leftConstraint; //左侧约束变量
@property (nonatomic, strong) MASConstraint *topConstraint; //顶部约束变量
@end

这里可以看到有两个leftConstrainttopConstraint的约束全局变量,这两个就是实现拖拽的时候改变约束的偏移量来实现的.具体代码如下

CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
[self.widgetView mas_makeConstraints:^(MASConstraintMaker *make) {
// 设置边界条件约束,保证内容可见,优先级1000
make.left.greaterThanOrEqualTo(self.greenView.mas_left);
make.right.lessThanOrEqualTo(self.greenView.mas_right);
make.top.greaterThanOrEqualTo(self.greenView.mas_top);
make.bottom.lessThanOrEqualTo(self.greenView.mas_bottom);
self.leftConstraint = make.centerX.equalTo(self.greenView.mas_left).with.offset(screenWidth - 20).priorityHigh(); // 优先级要比边界条件低
self.topConstraint = make.centerY.equalTo(self.greenView.mas_top).with.offset(screenHeight - 100).priorityHigh(); // 优先级要比边界条件低
make.width.height.mas_equalTo(@100);
}];

上边的greaterThanOrEqualTolessThanOrEqualTo都是限制挂件的可滑动范围,而最后的make.centerX/Y.equalTo是限制挂件的默认位置,我让它默认在右下角,所以通过偏移量移动过去

注意:这里有个坑就是因为这个东西能四处滑动 所以基本需要锁定lefttop,我发现只有通过offset移动才能确定最初位置,如果equalTo直接写成xxxview的bottom或者right是滑动不了的,仔细思考一下masonry就知道为啥了.

然后添加手势并实现相关滑动事件即可实现滑动

UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panWithGesture:)];
[self.greenView addGestureRecognizer:pan];
...
- (void)panWithGesture:(UIPanGestureRecognizer *)pan {
CGPoint touchPoint = [pan locationInView:self.greenView];
self.leftConstraint.offset = touchPoint.x;
self.topConstraint.offset = touchPoint.y;
}

旷量Label的约束

[self.bubbleTitleLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.height.equalTo(@26);
make.bottom.equalTo(self.widgetView.mas_top);
make.left.greaterThanOrEqualTo(self.greenView.mas_left).offset(0);
make.right.lessThanOrEqualTo(self.greenView.mas_right).offset(0);
make.centerX.lessThanOrEqualTo(self.widgetView.mas_right).offset(10);
make.centerX.greaterThanOrEqualTo(self.widgetView.mas_left).offset(-10);
}];

想要实现旷量移动必须增加更多的约束限制

这里就增加了

make.centerX.lessThanOrEqualTo(self.widgetView.mas_right).offset(10);
make.centerX.greaterThanOrEqualTo(self.widgetView.mas_left).offset(-10);

这样就实现了 左右超过滑动便宜还依然控制着tip的label左右移动范围.

总结

经过工作中遇到的问题实例,学习了一些Masonry的技巧,希望和大家分享,demo我已放到下面 喜欢自行下载学习.

demo下载

更早的文章

UITraitCollection详解

前言 本文具有强烈的个人感情色彩,如有观看不适,请尽快关闭. 本文仅作为个人学习记录使用,也欢迎在许可协议范围内转载或使用,请尊重版权并且保留原文链接,谢谢您的理解合作. 如果您觉得本站对您能有帮助,您可以使用RSS方式订阅本站,这样您将能在第一时间获取本站信息. 先说问题 最近在适配iOS13 …

于  iOS开发, macOS开发 继续阅读