QQ粘性布局


整體思路:

手指移動,按鈕跟著移動.按鈕跟著手指移動.移動時底部有一個圓,

根據(jù)上面的大圓按鈕拖動的距離,小圓的半徑在變小.移動時中間有一塊不規(guī)則的填充區(qū)域.

手指移動超出一定的范圍,填充效果消失,當手指松開時.判斷當前大圓距離與小圓之間的距離.

如果小于60就讓大圓回來原來的位置.下次拖動時,同樣具有填充效果.

如果大于60,手指松開時,播放一個動畫.動畫完成時, 刪除動畫按鈕.

實現(xiàn)步驟:

1.自定義大圓控件(UIButton)可以顯示背景圖片携御,和文字

按鈕定義的時候要在初始方法中,把它的基本屬性設(shè)置好.在開始加載的時候設(shè)置.

基本屬性包括顏色,圓角,文字顏色,大小.

實現(xiàn)代碼:

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.讓大圓控件隨著手指移動而移動

添加手勢.同樣也是在初始化方法當中進行設(shè)置.

注意不能根據(jù)形變修改大圓的位置,只能通過center,因為全程都需要用到中心點計算际邻。

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

添加手勢代碼為:

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

[self addGestureRecognizer:pan];

手勢實現(xiàn)方法為:

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];

當手指拖動大圓時,小圓的半徑會根據(jù)拖動的距離進行減小.所以要計算出兩個圓之間的距離.

計算完畢后.讓小圓的原始半徑每次都減去一個距離比例.重新設(shè)置尺寸大小.和小圓的半徑.

計算兩個圓之間距離是一個功能單獨抽出來.

方法為:

- (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;

}

在手指拖動方法計算兩個圓之間的距離, 根據(jù)拖動的距離讓小圓的半徑增大減小.

實現(xiàn)代碼為:

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

取出小圓的半徑

注意這里是取出小圓最初的寬度,由于每次拖動的時候都會去修改小圓的寬高.所以這里不能直接用小圓的寬度

這里用的是大圓的寬度,開始小圓和大圓的寬度是一樣的.

大圓在移動時,大圓的寬高沒有發(fā)現(xiàn)變化,所以可以拿到大圓的寬高

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

讓小圓的半徑每次減去一個距離比例

smallR = smallR - distance / 10.0;

每次移動時,重新設(shè)置小圓的寬高

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

重新設(shè)置小圓的圓角

self.smallCircle.layer.cornerRadius = smallR;

4.添加粘性效果

中間的粘性效果其實就是一塊填充區(qū)域.只要把這個填充區(qū)域的路徑給求出來就行了.

中間的路徑通過確定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θ);

創(chuàng)建路徑,把這些點連接到一起

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];

以上是根據(jù)兩個圓求出不規(guī)則的矩形

求出路徑后,要把路徑填充起來.但是不能夠直接給填充到當前的按鈕之上.按鈕是可以拖動的.

繪制東西,當超出它的范圍以外就不會再繪制.

所以要把路徑添加到按鈕的父控件當中, 但是當前是一個路徑,是不能夠直接添加到父控件當中的.

可能過形狀圖層添加.

形狀圖層會根據(jù)一個路徑生成一個形狀.把這個形狀添加到當前控件的圖片父層就可以了.

添加時需要注意:

形狀圖層之有一個,所以不能夠在手指拖動方法當中添加.由于當手指拖動的距離超過某個范圍后,形狀圖片會被移除.

下一次再去移動時, 還會有填充的路徑.所以把創(chuàng)建形狀圖層搞成一個懶加載的形式,

如果發(fā)現(xiàn)下一次被刪除時,再重新創(chuàng)建.

形式為:

-(CAShapeLayer *)shap{

if (_shap == nil) {

創(chuàng)建形狀圖層

CAShapeLayer *shap = [CAShapeLayer layer];

設(shè)置形狀圖層的填充顏色

shap.fillColor = [UIColor redColor].CGColor;

self.shap = shap;

把形狀圖層添加到當前按鈕的父層當中.

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

_shap = shap;

}

return _shap;

}

在手指移動方法當中,給形狀圖層賦值路徑就可以了.

5.粘性業(yè)務(wù)邏輯處理

在手指移動方法判斷兩個圓之間的距離, 如果發(fā)現(xiàn)兩個圓之間的距離超過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.手指停止拖動業(yè)務(wù)邏輯

移動后手指松開時判斷兩個圓之間的距離,如果兩個圓之間的距離小于60時,讓大圓復位.小圓顯示.

手指松開時,如果兩個圓之間的距離大于60時.播放一個動畫.動畫播放完畢時.把當前按鈕從父控件當中移除.

播放一個動畫.

創(chuàng)建一個UIImageView,尺寸和當前按鈕一樣大.

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

創(chuàng)建動畫圖片

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];

}

設(shè)置動畫圖片數(shù)組

imageV.animationImages = imageArray;

設(shè)置動畫執(zhí)行時長

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轉(zhuǎn)自動布局

不然會出現(xiàn)按鈕回原位的情況.

self.view.translatesAutoresizingMaskIntoConstraints = NO;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吝秕,一起剝皮案震驚了整個濱河市土涝,隨后出現(xiàn)的幾起案子砌梆,更是在濱河造成了極大的恐慌救巷,老刑警劉巖壶熏,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異浦译,居然都是意外死亡棒假,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門精盅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來帽哑,“玉大人,你說我怎么就攤上這事叹俏∑拚恚” “怎么了?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵粘驰,是天一觀的道長屡谐。 經(jīng)常有香客問我,道長蝌数,這世上最難降的妖魔是什么愕掏? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮顶伞,結(jié)果婚禮上饵撑,老公的妹妹穿的比我還像新娘。我一直安慰自己唆貌,他們只是感情好滑潘,可當我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著挠锥,像睡著了一般众羡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蓖租,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天粱侣,我揣著相機與錄音,去河邊找鬼蓖宦。 笑死齐婴,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的稠茂。 我是一名探鬼主播柠偶,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼情妖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了诱担?” 一聲冷哼從身側(cè)響起毡证,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蔫仙,沒想到半個月后料睛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡摇邦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年恤煞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片施籍。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡居扒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出丑慎,到底是詐尸還是另有隱情喜喂,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布竿裂,位于F島的核電站夜惭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏铛绰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一产喉、第九天 我趴在偏房一處隱蔽的房頂上張望捂掰。 院中可真熱鬧,春花似錦曾沈、人聲如沸这嚣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姐帚。三九已至,卻和暖如春障涯,著一層夾襖步出監(jiān)牢的瞬間罐旗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工唯蝶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留九秀,地道東北人。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓粘我,卻偏偏與公主長得像鼓蜒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容