CoreAnimation | 核心動(dòng)畫(huà) | QQ氣泡拖拽 | 自定義下拉刷新

展示效果

實(shí)現(xiàn)效果

實(shí)現(xiàn)思路

  1. 2個(gè)圓(一個(gè)是固定圓衔蹲,一個(gè)是可拖動(dòng)的圓)
  2. 貝塞爾畫(huà)形狀
  3. 拖動(dòng)的時(shí)候固定圓的比例是縮小的
  4. 到一定距離的時(shí)候會(huì)斷開(kāi)
  5. 松開(kāi)手勢(shì)就會(huì)回彈到原地

事前準(zhǔn)備工作

  • 屬性的創(chuàng)建

@property (nonatomic, strong) UIView *view1;
@property (nonatomic, strong) UIView *view2;
@property (nonatomic, strong) CAShapeLayer *shapeLayer;
@property (nonatomic, assign) CGPoint oldViewCenter;
@property (nonatomic, assign) CGRect oldViewFram;
@property (nonatomic, assign) CGFloat r1;
  • 核心代碼

- (void)setup{
    UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.view.bounds) / 2, CGRectGetHeight(self.view.bounds) * 1/9, 40, 40)];
    view1.backgroundColor = [UIColor redColor];
    view1.layer.cornerRadius = 20;
    _view1 = view1;
    [self.view addSubview:view1];
    
    UIView *view2 = [[UIView alloc] initWithFrame:_view1.frame];
    view2.backgroundColor = [UIColor redColor];
    view2.layer.cornerRadius = 20;
    _view2 = view2;
    [self.view addSubview:view2];
    
    //添加label
    UILabel *numL = [[UILabel alloc] initWithFrame:_view2.bounds];
    numL.text = @"66";
    numL.textAlignment = NSTextAlignmentCenter;
    numL.textColor = [UIColor whiteColor];
    [_view2 addSubview:numL];
    
    //添加手勢(shì)
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
    [_view2 addGestureRecognizer:pan];
    
    //實(shí)例化CAShapeLayer
    _shapeLayer = [CAShapeLayer layer];
    _shapeLayer.fillColor = [UIColor redColor].CGColor;
//    [self.view.layer addSublayer:_shapeLayer];

    _oldViewFram = _view1.frame;
    _oldViewCenter = _view1.center;
    _r1 = CGRectGetWidth(_view1.frame)/2;
}
  • 避坑指南

  1. 需要保存原先中心點(diǎn)的位置
  2. 需要保存原先圓的大小,因?yàn)樵跀嚅_(kāi)的時(shí)候需要回到原來(lái)的樣子
  3. shapeLayer 是直接初始化添加呈础,在拖拽中改變path就可以了
  • 根據(jù)手勢(shì)判斷處理移動(dòng)View屬性狀態(tài)

- (void)panAction:(UIPanGestureRecognizer *)ges{
    if (ges.state == UIGestureRecognizerStateChanged) {
        //view2跟著移動(dòng)
        _view2.center = [ges locationInView:self.view];
        //
        if (_r1 < wift
            _view1.hidden = YES;
            [_shapeLayer removeFromSuperlayer];
        }else{
            //計(jì)算出6個(gè)關(guān)鍵點(diǎn)舆驶,然后畫(huà)貝塞爾曲線
            [self caculPoint];
        }
       
    }else if (ges.state == UIGestureRecognizerStateFailed || ges.state == UIGestureRecognizerStateEnded || ges.state == UIGestureRecognizerStateCancelled){
        [_shapeLayer removeFromSuperlayer];
        [UIView animateWithDuration:.5 delay:0 usingSpringWithDamping:.3 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            _view2.center = _oldViewCenter;
        } completion:^(BOOL finished) {
            _view1.hidden = NO;
            _r1 = _oldViewFram.size.width/2;
            _view1.frame = _oldViewFram;
            _view1.layer.cornerRadius = _r1;
        }];
    }
}
  • 避坑指南

  1. 因?yàn)樵诮Y(jié)束動(dòng)畫(huà)之后會(huì)需要很多點(diǎn)的復(fù)原問(wèn)題,所以我們?cè)陂_(kāi)始的時(shí)候就需要記錄
  2. [_shapeLayer removeFromSuperlayer]; 在取消和結(jié)束的時(shí)候還是需要移除layer的
    不然會(huì)出現(xiàn)畫(huà)的紅色背景還在的情況
  3. usingSpringWithDamping 彈簧阻力效果
  • 計(jì)算拖拽中的關(guān)鍵點(diǎn)

- (void)caculPoint{
    //1.求出2個(gè)中心點(diǎn)
    CGPoint center1 = _view1.center;
    CGPoint center2 = _view2.center;
    //2.計(jì)算2個(gè)中心點(diǎn)的距離
    CGFloat dis = sqrtf((center1.x - center2.x)*(center1.x - center2.x) + (center1.y - center2.y)*(center1.y - center2.y));
    //3.計(jì)算正弦余弦
    CGFloat sin = (center2.x - center1.x) / dis;
    CGFloat cos = (center1.y - center2.y) / dis;
    //4.計(jì)算半徑
    CGFloat r1 = CGRectGetWidth(_oldViewFram)/2 - dis/20;
    CGFloat r2 = CGRectGetWidth(_view2.bounds)/2;
    _r1 = r1;
    NSLog(@"%f",r1);
    //5.計(jì)算6個(gè)關(guān)鍵點(diǎn)
    CGPoint pA = CGPointMake(center1.x - cos*r1, center1.y - sin*r1);
    CGPoint pB = CGPointMake(center1.x + cos*r1, center1.y + sin*r1);
    CGPoint pD = CGPointMake(center2.x - cos*r2, center2.y - sin*r2);
    CGPoint pC = CGPointMake(center2.x + cos*r2, center2.y + sin*r2);
    CGPoint pP = CGPointMake(pB.x + dis/2*sin, pB.y - dis/2*cos);
    CGPoint pO = CGPointMake(pA.x + dis/2*sin, pA.y - dis/2*cos);
    //6.畫(huà)貝塞爾曲線
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:pA];
    [path addQuadCurveToPoint:pD controlPoint:pO];
    [path addLineToPoint:pC];
    [path addQuadCurveToPoint:pB controlPoint:pP];
    [path closePath];
    //7.修改_shapeLayer的path
    _shapeLayer.path = path.CGPath;
    [self.view.layer insertSublayer:_shapeLayer below:_view2.layer];

    //8.重新設(shè)置view的大小
    _view1.center = _oldViewCenter;
    _view1.bounds = CGRectMake(0, 0, _r1*2, _r1*2);
    _view1.layer.cornerRadius = _r1;
}
  • 避坑指南

  1. CGRectGetWidth(_oldViewFram)/2 - dis/20; 這里再次設(shè)置寬度的時(shí)候需要用到原先的那個(gè)值而钞,不然r1的值就會(huì)有問(wèn)題
  • 關(guān)鍵點(diǎn)計(jì)算圖示

6個(gè)關(guān)鍵點(diǎn)計(jì)算說(shuō)明(ABCDOP)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沙廉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子臼节,更是在濱河造成了極大的恐慌撬陵,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件官疲,死亡現(xiàn)場(chǎng)離奇詭異袱结,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)途凫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)垢夹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人维费,你說(shuō)我怎么就攤上這事果元。” “怎么了犀盟?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵而晒,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我阅畴,道長(zhǎng)倡怎,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任贱枣,我火速辦了婚禮监署,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘纽哥。我一直安慰自己钠乏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布春塌。 她就那樣靜靜地躺著晓避,像睡著了一般簇捍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上俏拱,一...
    開(kāi)封第一講書(shū)人閱讀 50,084評(píng)論 1 291
  • 那天暑塑,我揣著相機(jī)與錄音,去河邊找鬼锅必。 笑死梯投,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的况毅。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼尔艇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼尔许!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起终娃,我...
    開(kāi)封第一講書(shū)人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤味廊,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后棠耕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體余佛,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年窍荧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辉巡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蕊退,死狀恐怖郊楣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瓤荔,我是刑警寧澤净蚤,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站输硝,受9級(jí)特大地震影響今瀑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜点把,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一橘荠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧愉粤,春花似錦砾医、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)压恒。三九已至,卻和暖如春错邦,著一層夾襖步出監(jiān)牢的瞬間探赫,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工撬呢, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伦吠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓魂拦,卻偏偏與公主長(zhǎng)得像毛仪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子芯勘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

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