zoukankan      html  css  js  c++  java
  • QQ粘性布局

    05-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;
  • 相关阅读:
    ubuntu11.04安装NetBeans 7.0中文显示乱码或者方框问题的解决(JRE中文字体设置)
    我在CSDN上的博客地址!
    ubuntu11.04手工安装flash插件
    漫谈ubuntu 的安装,兼论操作系统安装方式的进步!
    ubuntu 11.04下android开发环境的搭建!
    网络流24题(09)方格取数问题(最大点权独立集 + 最小割最大流)
    POJ 3273 Monthly Expense(二分搜索巧妙利用)
    网络流24题(10)餐巾计划问题(最小费用最大流)
    网络流24题(05)魔术球问题(最小路径覆盖 + 最大流)
    网络流24题(06)最长递增子序列问题(最多不相交路径 + 最大流)
  • 原文地址:https://www.cnblogs.com/zhoudaquan/p/5062275.html
Copyright © 2011-2022 走看看