QQ粘性布局


整体思路:

手指移动,按钮跟着移动.按钮跟着手指移动.移动时底部有一个圆,

根据上面的大圆按钮拖动的距离,小圆的半径在变小.移动时中间有一块不规则的填充区域.

手指移动超出一定的范围,填充效果消失,当手指松开时.判断当前大圆距离与小圆之间的距离.

如果小于60就让大圆回来原来的位置.下次拖动时,同样具有填充效果.

如果大于60,手指松开时,播放一个动画.动画完成时, 删除动画按钮.

实现步骤:

1.自定义大圆控件(UIButton)可以显示背景图片,和文字

按钮定义的时候要在初始方法中,把它的基本属性设置好.在开始加载的时候设置.

基本属性包括颜色,圆角,文字颜色,大小.

实现代码:

self.backgroundColor = [UIColor redColor];

self.layer.cornerRadius = self.bounds.size.width * 0.5;

self.titleLabel.font = [UIFont systemFontOfSize:12];

[self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];

2.让大圆控件随着手指移动而移动

添加手势.同样也是在初始化方法当中进行设置.

注意不能根据形变修改大圆的位置,只能通过center,因为全程都需要用到中心点计算。

tansform并没有修改center,它修改的是Frame.

添加手势代码为:

UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];

[self addGestureRecognizer:pan];

手势实现方法为:

CGPoint transP = [pan translationInView:self];

CGPoint center = self.center;

center.x += transP.x;

center.y +=transP.y;

self.center = center;

注意要做复位,相对于上一次.

[pan setTranslation:CGPointZero inView:self];

3.在拖动的时候,添加一个小圆控件在原来大圆控件的位置

在初始化方法中添加小圆

注意:添加小圆时不能够直接添加在当前按钮上,因为按钮是可以移动的,如果直接添加在按钮,它会跟着按钮一起移动.

所以以把小圆添加到按钮父控件当中.添加时注意,要把小圆添加到按钮底部.不然会把按钮给盖起来.

UIView *smallCircle = [[UIView alloc] init];

smallCircle.frame = self.frame;

smallCircle.layer.cornerRadius = self.layer.cornerRadius;

smallCircle.backgroundColor = self.backgroundColor;

self.smallCircle = smallCircle;

[self.superview insertSubview:smallCircle belowSubview:self];

当手指拖动大圆时,小圆的半径会根据拖动的距离进行减小.所以要计算出两个圆之间的距离.

计算完毕后.让小圆的原始半径每次都减去一个距离比例.重新设置尺寸大小.和小圆的半径.

计算两个圆之间距离是一个功能单独抽出来.

方法为:

- (CGFloat)distanceWithSmallCircle:(UIView *)smallView bigCircle:(UIView *)bigCircle{

X轴的便宜量

CGFloat offsetX = bigCircle.center.x - smallView.center.x;

Y轴的便宜量

CGFloat offsetY = bigCircle.center.y - smallView.center.y;

CGFloat distance = sqrt(offsetX * offsetX + offsetY * offsetY);

return distance;

}

在手指拖动方法计算两个圆之间的距离, 根据拖动的距离让小圆的半径增大减小.

实现代码为:

CGFloat distance = [self distanceWithSmallCircle:self.smallCircle bigCircle:self];

取出小圆的半径

注意这里是取出小圆最初的宽度,由于每次拖动的时候都会去修改小圆的宽高.所以这里不能直接用小圆的宽度

这里用的是大圆的宽度,开始小圆和大圆的宽度是一样的.

大圆在移动时,大圆的宽高没有发现变化,所以可以拿到大圆的宽高

CGFloat smallR = self.bounds.size.width * 0.5;

让小圆的半径每次减去一个距离比例

smallR = smallR - distance / 10.0;

每次移动时,重新设置小圆的宽高

self.smallCircle.bounds = CGRectMake(0, 0, smallR * 2, smallR * 2);

重新设置小圆的圆角

self.smallCircle.layer.cornerRadius = smallR;

4.添加粘性效果

中间的粘性效果其实就是一块填充区域.只要把这个填充区域的路径给求出来就行了.

中间的路径通过确定6个点.把这些点连接出来就行.

求点为:

x1,y1分别是小圆的圆心

x2,y2分别是大圆的圆心

r1代表小圆的半径

r2代表大圆的半径

d是两个圆之间的距离

y轴的偏移量 / 两个圆之间的距离

cosθ = (y2 - y1) / d;

x轴的偏移量 / 两个圆之间的距离

sinθ = (x2 - x1) / d;

已知一个角,一个斜边

角的邻边 = 斜边 * cosθ

角的对边 = 斜边 * sinθ

CGPoint pointA = CGPointMake(x1 - r1 * cosθ, y1 + r1 * sinθ);

CGPoint pointB = CGPointMake(x1 + r1 * cosθ, y1 - r1 * sinθ);

CGPoint pointC = CGPointMake(x2 + r2 * cosθ, y2 - r2 * sinθ);

CGPoint pointD = CGPointMake(x2 - r2 * cosθ, y2 + r2 * sinθ);

CGPoint pointO = CGPointMake(pointA.x + d * 0.5 * sinθ, pointA.y + d * 0.5 * cosθ);

CGPoint pointP = CGPointMake(pointB.x + d * 0.5 * sinθ, pointB.y + d * 0.5 * cosθ);

创建路径,把这些点连接到一起

UIBezierPath *path = [UIBezierPath bezierPath];

AB

[path moveToPoint:pointA];

[path addLineToPoint:pointB];

BC(曲线)

[path addQuadCurveToPoint:pointC controlPoint:pointP];

CD

[path addLineToPoint:pointD];

DA(曲线)

[path addQuadCurveToPoint:pointA controlPoint:pointO];

以上是根据两个圆求出不规则的矩形

求出路径后,要把路径填充起来.但是不能够直接给填充到当前的按钮之上.按钮是可以拖动的.

绘制东西,当超出它的范围以外就不会再绘制.

所以要把路径添加到按钮的父控件当中, 但是当前是一个路径,是不能够直接添加到父控件当中的.

可能过形状图层添加.

形状图层会根据一个路径生成一个形状.把这个形状添加到当前控件的图片父层就可以了.

添加时需要注意:

形状图层之有一个,所以不能够在手指拖动方法当中添加.由于当手指拖动的距离超过某个范围后,形状图片会被移除.

下一次再去移动时, 还会有填充的路径.所以把创建形状图层搞成一个懒加载的形式,

如果发现下一次被删除时,再重新创建.

形式为:

-(CAShapeLayer *)shap{

if (_shap == nil) {

创建形状图层

CAShapeLayer *shap = [CAShapeLayer layer];

设置形状图层的填充颜色

shap.fillColor = [UIColor redColor].CGColor;

self.shap = shap;

把形状图层添加到当前按钮的父层当中.

[self.superview.layer insertSublayer:shap atIndex:0];

_shap = shap;

}

return _shap;

}

在手指移动方法当中,给形状图层赋值路径就可以了.

5.粘性业务逻辑处理

在手指移动方法判断两个圆之间的距离, 如果发现两个圆之间的距离超过60时

让底部的小圆隐藏.把路径移除

当小圆显示的时候才绘制填充路径

if (self.smallCircle.hidden == NO) {

UIBezierPath *path = [self pathWithSmallCircle:self.smallCircle bigCircle:self];

self.shap.path = path.CGPath;

}

当两个圆之间的距离超过60时.

if(distance > 60){

移除填充路径

[self.shap removeFromSuperlayer];

让底部的小圆隐匿

self.smallCircle.hidden = YES;

}

6.手指停止拖动业务逻辑

移动后手指松开时判断两个圆之间的距离,如果两个圆之间的距离小于60时,让大圆复位.小圆显示.

手指松开时,如果两个圆之间的距离大于60时.播放一个动画.动画播放完毕时.把当前按钮从父控件当中移除.

播放一个动画.

创建一个UIImageView,尺寸和当前按钮一样大.

UIImageView *imageV = [[UIImageView alloc] initWithFrame:self.bounds];

创建动画图片

NSMutableArray *imageArray = [NSMutableArray array];

for (int i = 0; i < 8 ; i++) {

NSString *imageName = [NSString stringWithFormat:@"%d",i+1];

UIImage *image = [UIImage imageNamed:imageName];

[imageArray addObject:image];

}

设置动画图片数组

imageV.animationImages = imageArray;

设置动画执行时长

imageV.animationDuration = 1;

开始动画

[imageV startAnimating];

把UIImageView添加到当前按钮上

[self addSubview:imageV];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)),

dispatch_get_main_queue(), ^{

[self removeFromSuperview];

});

注意:

在控制器加载完毕后,要取消Autoresizing转自动布局

不然会出现按钮回原位的情况.

self.view.translatesAutoresizingMaskIntoConstraints = NO;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容