思路
- 控件结构
- 封装思路
- 细节注意
- 使用方法
1.控件结构
继承自UIButton, 对系统的按钮进行进一步的分装,主要是由一个圆形的UIView - smallCircle
、按钮本身
和一个CAShapeLayer图层
构成。
2.封装思路
根据btn的frame,创建一个大小相同的圆形UIView-samillCircle, 并且将其添加到btn的父控件上。
给按钮本身添加拖动手势和点击事件,在拖动手势监听时获取btn手势的偏移量,根据偏移量改变按钮本身的center坐标,使得btn跟随手势拖动而移动。
根据btn和smallCircle的center计算出两个圆的中心点的间距d, 根据间距改变smallCircle的半径(随着d越大,半径越小), 并且根据手势拖动描绘shapeLayer图层(根据手势坐标计算不规则图层的路径,这里用到UIBezierPath曲线路径), 通过对两个圆形区域的控制点A、B、C、D、O、P点描绘path路径,最后将路径赋值给图层,达到每次手势拖动不规则图层都会展示不同的矩形效果。
当间距达到最大间距kMaxDistance时,隐藏smallCircle,并且销毁不规则矩形。当手指抬起,判断间距d是否小于最大间距,若小于最大间距,则位置还原,若大于最大间距,则显示消失动画之后移除btn,调用delegate的
viscousButtonDismissed
方法处理事件。同时,在点击btn时也可以展示btn消失动画以及代理事件,可以通过实现代理对按钮的事件进行后续逻辑功能处理。
3.细节注意
这里不能用绘图方法
drawRect
去代替图层shapeLayer的实现,因为如果采用绘图,绘图内容只要超过当前控件就不会显示,但是当前形变必须显示在控件之外。如采用代码创建该按钮的实例进行使用,由于我们是在初始化方法initWithFrame和awakeFromNib中去调用setUp方法进行内容的初始化,包括对小圆smallCircle的创建和添加。但是这样一来,代码创建就会出现获取不到superView的问题,导致self.superView addSubview: samllCircle无效,和xib创建不同的是因为程序外部是在初始化之后才添加到父控件上,而xib是由内到外一层一层的添加控件,在当前按钮创建出来之前父控件已经存在。因此我们发现苹果提供一个
didMoveToSuperview
方法,改方法会在父控件addSubView完成之后调用,故我们将添加小圆的步骤在该方法中执行。
/**
* @brief 在父控件addSubview后调用
*/
- (void)didMoveToSuperview {
[super didMoveToSuperview];
// 设置小圆的位置和尺寸
self.smallCircle.center = self.center;
self.smallCircle.bounds = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.height);
self.smallCircle.layer.cornerRadius = self.bounds.size.height / 2;
}
- 为防止xib中引用的self按钮会会默认使用自动布局,使用代码关闭自动布局,使得按钮和xib引用达到相同的效果。
// 取消父控件xib的自动布局 self.superview.translatesAutoresizingMaskIntoConstraints = NO;
4.使用方法
xib使用
拖动一个UIButton控件到父控件上,将MRViscousButton文件中的MRViscousButton.h和MRViscousButton.m文件复制到项目中,更改UIButton的class为MRViscousButton即可。- 代码创建
MRViscousButton *btn = [[MRViscousButton alloc] initWithFrame:CGRectMake(100, 150, 30, 30)];
// 设置代理
btn.delegate = self;
[btn setTitle:@"24" forState:UIControlStateNormal];
[btn setBackgroundColor:[UIColor redColor]];
[self.view addSubview:btn];
// 设置动画图片
NSMutableArray *arrM = [NSMutableArray array];
for (int i = 1; i < 9; i++) {
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"%d", i]];
[arrM addObject:image];
}
btn.images = arrM;
# pragma mark - <MRViscousButtonDelegate>
- (void)viscousButtonDismissed:(MRViscousButton *)btn {
NSLog(@"%@ - 代理回调方法", btn);
}
效果图
Demo地址: github