日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

iOS开发 QQ粘性动画效果

發布時間:2025/5/22 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS开发 QQ粘性动画效果 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

QQ(iOS)客戶端的粘性動畫效果

時間?2016-02-17 16:50:00??博客園精華區 原文??http://www.cnblogs.com/ziyi--caolu/p/5195615.html 主題?iOS開發

qq的app中要是有新的聯系人發消息過來,相應聯系人的cell右邊會有一個紅色的圓圈表示消息條數。如果去觸碰那個圓圈,可以發現它竟然會跟著手指的移動而移動。

在一定范圍內,手指離開屏幕,會發現紅色圓圈會自動彈性的回到原來的位置。而如果超出一定距離,這個圓圈會做一個銷毀的動畫,從而從view上移除掉。?

產品要求公司的App也要有效果,并花了些時間去學習它的實現過程,發現其實原理還是比較簡單的。

(由于mac制作gif圖片實在過于麻煩,所以效果只能是看看圖片。)

Demo的github地址:https://github.com/wzpziyi1/QQ-Goo

這是實現過程中的一些效果圖片:

經過分析,可以發現,是兩個圓和一個不規則矩形位置、大小的變化。一開始,小的圓圈和大的圓圈的center是相同的,當移動大圓的時候,小圓的半徑隨著大圓離小圓的距離變遠而變小,當大圓距離小圓一定距離時,將小圓隱藏掉,中間的不規則矩形remove掉。

那么,不規則矩形怎么表示呢?可以利用Core Graphics在drawRect方法里面繪制不規則矩形的path,然后利用顏色fill就行。不規則矩形是隨著大圓的移動而不斷變化的,如果在drawRect方法里面繪制,那么在移動過程中不斷調用setNeedsDisplay方法進行重繪。這是種可行的方案,我所用的也大致是這種思路。

不過,我沒有在drawRect方法里面繪制,而是利用了CAShapeLayer,將不規則矩形的path繪制在shapeLayer里面,這樣在移動大圓的過程中不斷更新CAShapeLayer的path即可。

當然,難點并在在這里。而是不規則矩形的各個點的位置。要繪制這個不規則矩形,需要知道六個點的位置:

有了這些點的坐標,那么就可以用UIBezierPath來繪制相應的路徑,代碼如下:

- (UIBezierPath *)pathWithBigCircleView:(UIView *)bigCircleView smallCircleView:(UIView *)smallCircleView {CGPoint bigCenter = bigCircleView.center;CGFloat x2 = bigCenter.x;CGFloat y2 = bigCenter.y; CGFloat r2 = bigCircleView.bounds.size.width / 2; CGPoint smallCenter = smallCircleView.center; CGFloat x1 = smallCenter.x; CGFloat y1 = smallCenter.y; CGFloat r1 = smallCircleView.bounds.size.width / 2; // 獲取圓心距離 CGFloat d = [self distanceWithPointA:bigCenter pointB:smallCenter]; //Θ:(xita) CGFloat sinθ = (x2 - x1) / d; CGFloat cosθ = (y2 - y1) / d; // 坐標系基于父控件 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 / 2 * sinθ , pointA.y + d / 2 * cosθ); CGPoint pointP = CGPointMake(pointB.x + d / 2 * sinθ , pointB.y + d / 2 * cosθ); UIBezierPath *path = [UIBezierPath bezierPath]; // A [path moveToPoint:pointA]; // AB [path addLineToPoint:pointB]; // 繪制BC曲線 [path addQuadCurveToPoint:pointC controlPoint:pointP]; // CD [path addLineToPoint:pointD]; // 繪制DA曲線 [path addQuadCurveToPoint:pointA controlPoint:pointO]; return path; }

在實現過程中,我是自定義UIButton的,需要注意的是,在監聽button的拖動時,最好是給它添加UIPanGestureRecognizer手勢,而不要在touchesBegin方法里面去判斷它的移動位置,因為Touches系列方法會屏蔽button的點擊。

自定義的這個button默認就是大圓,包含一個小圓(UIView)屬性,但是這個小圓并不是添加在自定義的這個button(也就是大圓)里面,而是在button的superView上。因為小圓并不需要隨著大圓位置的改變而改變位置,相應的,shapeLayer也是添加在button(大圓)的父控件上。

給大圓添加了pan手勢,在pan:方法里面隨之改變小圓的大小和繪制shapeLayer的path。

當pan手勢狀態為End的時候,需要判斷大圓與小圓的距離有沒有超出最大距離,如果超過,那么添加一個gif圖片,播放銷毀大圓的過程。如果沒有被銷毀,那么大圓需要復位,相應代碼:?

#import "ZYGooView.h"#define kMaxDistance 100@interface ZYGooView () @property (nonatomic, weak) UIView *smallCircleView; @property (nonatomic, assign) CGFloat smallCircleR; @property (nonatomic, weak) CAShapeLayer *shapeLayer; @end @implementation ZYGooView - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self commitInit]; } return self; } - (void)awakeFromNib { [self commitInit]; } - (void)commitInit { self.layer.cornerRadius = self.frame.size.width * 0.5; self.layer.masksToBounds = YES; self.smallCircleR = self.frame.size.width * 0.5; self.smallCircleView.bounds = self.bounds; self.smallCircleView.center = self.center; self.smallCircleView.layer.cornerRadius = self.smallCircleView.frame.size.width * 0.5; [self addGesture]; } #pragma mark ----懶加載方法 - (UIView *)smallCircleView { if (_smallCircleView == nil) { UIView *view = [[UIView alloc] init]; view.backgroundColor = self.backgroundColor; [self.superview addSubview:view]; [self.superview insertSubview:view atIndex:0]; _smallCircleView = view; } return _smallCircleView; } - (CAShapeLayer *)shapeLayer { if (_shapeLayer == nil) { CAShapeLayer *shapeLayer = [CAShapeLayer layer]; shapeLayer.path = [self pathWithBigCircleView:self smallCircleView:self.smallCircleView].CGPath; shapeLayer.fillColor = self.backgroundColor.CGColor; [self.superview.layer addSublayer:shapeLayer]; [self.superview.layer insertSublayer:shapeLayer atIndex:0]; _shapeLayer = shapeLayer; } return _shapeLayer; } #pragma mark ----其他方法 - (void)addGesture { UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; [self addGestureRecognizer:recognizer]; } - (void)pan:(UIPanGestureRecognizer *)recognizer { CGPoint point = [recognizer translationInView:self.superview]; CGPoint center = self.center; center.x += point.x; center.y += point.y; self.center = center; //復位 [recognizer setTranslation:CGPointZero inView:self]; CGFloat distance = [self distanceWithPointA:self.smallCircleView.center pointB:self.center]; if (distance == 0) return; CGFloat newR = self.smallCircleR - distance / 15.0; NSLog(@"%f", newR); self.smallCircleView.bounds = CGRectMake(0, 0, newR * 2, newR * 2); self.smallCircleView.layer.cornerRadius = newR; if (distance > kMaxDistance || newR <= 0) { self.smallCircleView.hidden = YES; [self.shapeLayer removeFromSuperlayer]; self.shapeLayer = nil; } if (distance <= kMaxDistance && self.smallCircleView.hidden == NO) { self.shapeLayer.path = [self pathWithBigCircleView:self smallCircleView:self.smallCircleView].CGPath; } if (recognizer.state == UIGestureRecognizerStateEnded) { if (distance <= kMaxDistance) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.03 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.shapeLayer removeFromSuperlayer]; self.shapeLayer = nil; }); [UIView animateWithDuration:0.4 delay:0 usingSpringWithDamping:0.6 initialSpringVelocity:0 options:UIViewAnimationOptionCurveLinear animations:^{ self.center = self.smallCircleView.center; } completion:^(BOOL finished) { self.smallCircleView.hidden = NO; }]; } else { UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.bounds]; [self addSubview:imageView]; NSMutableArray *images = [NSMutableArray array]; for (int i = 1; i <= 8; i++) { NSString *imageName = [NSString stringWithFormat:@"%d", i]; UIImage *image = [UIImage imageNamed:imageName]; [images addObject:image]; } imageView.animationImages = images; imageView.animationDuration = 0.6; imageView.animationRepeatCount = 1; [imageView startAnimating]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self removeFromSuperview]; }); } } } - (CGFloat)distanceWithPointA:(CGPoint)pointA pointB:(CGPoint)pointB { CGFloat dx = pointB.x - pointA.x; CGFloat dy = pointB.y - pointA.y; return sqrt(dx * dx + dy * dy); } - (UIBezierPath *)pathWithBigCircleView:(UIView *)bigCircleView smallCircleView:(UIView *)smallCircleView { CGPoint bigCenter = bigCircleView.center; CGFloat x2 = bigCenter.x; CGFloat y2 = bigCenter.y; CGFloat r2 = bigCircleView.bounds.size.width / 2; CGPoint smallCenter = smallCircleView.center; CGFloat x1 = smallCenter.x; CGFloat y1 = smallCenter.y; CGFloat r1 = smallCircleView.bounds.size.width / 2; // 獲取圓心距離 CGFloat d = [self distanceWithPointA:bigCenter pointB:smallCenter]; //Θ:(xita) CGFloat sinθ = (x2 - x1) / d; CGFloat cosθ = (y2 - y1) / d; // 坐標系基于父控件 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 / 2 * sinθ , pointA.y + d / 2 * cosθ); CGPoint pointP = CGPointMake(pointB.x + d / 2 * sinθ , pointB.y + d / 2 * cosθ); UIBezierPath *path = [UIBezierPath bezierPath]; // A [path moveToPoint:pointA]; // AB [path addLineToPoint:pointB]; // 繪制BC曲線 [path addQuadCurveToPoint:pointC controlPoint:pointP]; // CD [path addLineToPoint:pointD]; // 繪制DA曲線 [path addQuadCurveToPoint:pointA controlPoint:pointO]; return path; } @end

?

轉載于:https://www.cnblogs.com/diweinan/p/6230533.html

總結

以上是生活随笔為你收集整理的iOS开发 QQ粘性动画效果的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 性av网站 | 能免费看18视频网站 | 亚洲精品一区中文字幕乱码 | 性色在线 | 99热日本| 久久加久久 | av中文字幕一区二区 | 性做久久久久久久久久 | 青青青国产 | 天天综合在线视频 | 黑人操日本女优 | 天堂中文字幕免费一区 | 在线观看亚洲免费视频 | 综合五月 | 怎么可能高潮了就结束漫画 | 日本在线高清 | 蜜桃传媒一区二区亚洲av | 在线观看一区视频 | 青娱乐福利视频 | 亚洲激情小视频 | 国产精品卡一 | 性史性dvd影片农村毛片 | 国产精品成人在线观看 | 激情爱爱网站 | 狠狠cao日日穞夜夜穞av | 精品国产三级片在线观看 | 成人网av | 国产av成人一区二区三区 | 日韩精品无码一区二区三区久久久 | 亚洲中文字幕一区在线 | 老外一级黄色片 | 香港三级在线视频 | 国产天堂第一区 | 国产精品视频一二三 | 国产综合在线播放 | 亚洲AV无码成人国产精品色 | 一本色道久久综合精品婷婷 | 亚洲乱码精品 | 亚洲成人黄色小说 | 国产在线观看免费高清 | 国产精品成av人在线视午夜片 | 毛毛毛片 | 国产一区二区三区免费观看 | 香蕉免费在线视频 | 日本韩国在线观看 | 国产伦精品一区二区三区视频孕妇 | 亚洲综合性 | 国产内射老熟女aaaa∵ | 国产欧美日韩 | 男人吃奶视频 | 三级黄色生活片 | 国产一级一片免费播放 | 对白刺激国产子与伦 | 咪咪色影院 | 色av免费| 欧美一区二区三区四区在线观看 | 亚洲人人插 | 黄色网址网站 | 欧美污污视频 | www视频在线观看网站 | 在线黄色免费 | 亚洲自拍偷拍视频 | 在线久草 | 午夜精品一区二 | 免费成人深夜夜行p站 | 成人免费视频一区二区 | 中国黄色a级片 | 久久香蕉综合 | 在线播放亚洲 | 亚州黄色网址 | 激情综合网五月激情 | 97性视频| 综合伊人 | 色婷婷久久一区二区三区麻豆 | 不卡av片 | www.-级毛片线天内射视视 | 丝袜综合网 | 午夜寂寞影院在线观看 | 99国产精品久久久久久久成人 | 午夜视频福利在线观看 | 妺妺窝人体色WWW精品 | 九九热精品视频在线播放 | 日本一区二区在线免费观看 | 欧美人妖老妇 | 九色91 | 日本少妇网站 | 久久久激情视频 | 亚洲欧美一区二区视频 | 日本亚洲天堂 | 亚洲美女自拍 | 亚洲国产日韩精品 | 91大神在线看 | 国产成人综合网 | 日本免费黄网站 | 秋霞成人午夜伦在线观看 | 成人午夜影院在线观看 | 91成人在线看 | 日本在线观看视频网站 | 国产深夜福利在线 |