你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS編程技術 >> iOS之QQ粘性布局

iOS之QQ粘性布局

編輯:IOS編程技術

整體思路徑:
手指移動,按鈕跟著移動.按鈕跟著手指移動.移動時底部有一個圓,
根據上面的大圓按鈕拖動的距離,小圓的半徑在變小.移動時中間有一塊不規則的填充區域.
手指移動超出一定的范圍,填充效果消失,當手指松開時.判斷當前大圓距離與小圓之間的距離.
如果小於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;

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved