AnimationCircle

AnimationCircle

  • 用四條曲線拼接出小球的形狀拯坟,逆時(shí)針開始眶诈,分別是弧AB瘸恼,弧BC,弧CD册养,弧DA,每條弧都是兩個(gè)弧頂點(diǎn)加上兩個(gè)控制點(diǎn)压固,一共四個(gè)點(diǎn)繪制的三次貝塞爾曲線球拦。
  • 界面布局如圖所示
界面布局圖.png
  • 創(chuàng)建繼承自CALayerCircleLayer類,具體代碼如下
    //  CircleLayer.h
    #import <QuartzCore/QuartzCore.h>
    @interface CircleLayer : CALayer
    /** 滑塊的進(jìn)度值 */
    @property(nonatomic, assign)CGFloat progress;
    @end
    
    //  CircleLayer.m
    #import "CircleLayer.h"
    #import <UIKit/UIKit.h>
    
    // 移動(dòng)點(diǎn)的枚舉
    typedef enum MovingPoint {
        POINT_D,
        POINT_B,
    } MovingPoint;
    
    // 宏定義
    #define outsideRectSize 90
    
    @interface CircleLayer()
    
    /** 外接矩形 */
    @property(nonatomic, assign)CGRect outsideRect;
    
    /** 記錄上一次的progress帐我,方便做差得出滑動(dòng)方向 */
    @property(nonatomic, assign)CGFloat lastProgress;
    
    /** 實(shí)時(shí)記錄滑動(dòng)方向 */
    @property(nonatomic, assign)MovingPoint movePoint;
    
    @end
    
    @implementation CircleLayer
    
    // 初始化滑塊的滑動(dòng)值
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            self.lastProgress = 0.5;
        }
        return self;
    }
    
    // 初始化動(dòng)畫的Layer
    - (instancetype)initWithLayer:(CircleLayer *)layer{
        self = [super initWithLayer:layer];
        if (self) {
            self.progress = layer.progress;
            self.outsideRect = layer.outsideRect;
            self.lastProgress = layer.lastProgress;
        }
        return self;
    }
    
    // 繪制小球
    -(void)drawInContext:(CGContextRef)ctx {
    
        // 外接矩形頂點(diǎn)和控制點(diǎn)的距離坎炼,當(dāng)它為正方形邊長的1/3.6倍時(shí),畫出來的圓弧完美貼合圓形
        CGFloat offset = self.outsideRect.size.width / 3.6;
    
        // 外接矩形頂點(diǎn)需要移動(dòng)的距離
        CGFloat movedDistance = (self.outsideRect.size.width * 1 / 6) * fabs(self.progress - 0.5) * 2;
    
        // 外接矩形的中心點(diǎn)坐標(biāo)
        CGPoint rectCenter = CGPointMake(self.outsideRect.origin.x + self.outsideRect.size.width / 2, self.outsideRect.origin.y + self.outsideRect.size.height / 2);
    
        // 外接矩形頂點(diǎn)的坐標(biāo)
        CGPoint pointA = CGPointMake(rectCenter.x, self.outsideRect.origin.y + movedDistance);
        CGPoint pointB = CGPointMake(self.movePoint == POINT_D ? rectCenter.x + self.outsideRect.size.width / 2 : rectCenter.x + self.outsideRect.size.width / 2 + movedDistance * 2, rectCenter.y);
        CGPoint pointC = CGPointMake(rectCenter.x, rectCenter.y + self.outsideRect.size.height / 2 - movedDistance);
        CGPoint pointD = CGPointMake(self.movePoint == POINT_D ? self.outsideRect.origin.x - movedDistance * 2 : self.outsideRect.origin.x, rectCenter.y);
    
        // 外接矩形控制點(diǎn)的坐標(biāo)
        CGPoint c1 = CGPointMake(pointA.x + offset, pointA.y);
        CGPoint c2 = CGPointMake(pointB.x, self.movePoint == POINT_D ? pointB.y - offset : pointB.y - offset + movedDistance);
        CGPoint c3 = CGPointMake(pointB.x, self.movePoint == POINT_D ? pointB.y + offset : pointB.y + offset -movedDistance);
        CGPoint c4 = CGPointMake(pointC.x + offset, pointC.y);
        CGPoint c5 = CGPointMake(pointC.x - offset, pointC.y);
        CGPoint c6 = CGPointMake(pointD.x, self.movePoint == POINT_D ? pointD.y + offset - movedDistance : pointD.y + offset);
        CGPoint c7 = CGPointMake(pointD.x, self.movePoint == POINT_D ? pointD.y - offset + movedDistance : pointD.y - offset);
        CGPoint c8 = CGPointMake(pointA.x - offset, pointA.y);
    
        // 繪制外接虛線矩形
        UIBezierPath *rectPath = [UIBezierPath bezierPathWithRect:self.outsideRect];
        CGContextAddPath(ctx, rectPath.CGPath);
        CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
        CGContextSetLineWidth(ctx, 1.0);
        CGFloat dash[] = {5.0, 5.0};
        CGContextSetLineDash(ctx, 0.0, dash, 2);
        CGContextStrokePath(ctx);
    
        // 圓的邊界
        UIBezierPath *ovalPath = [UIBezierPath bezierPath];
        [ovalPath moveToPoint:pointA];
        [ovalPath addCurveToPoint:pointB controlPoint1:c1 controlPoint2:c2];
        [ovalPath addCurveToPoint:pointC controlPoint1:c3 controlPoint2:c4];
        [ovalPath addCurveToPoint:pointD controlPoint1:c5 controlPoint2:c6];
        [ovalPath addCurveToPoint:pointA controlPoint1:c7 controlPoint2:c8];
        [ovalPath closePath];
    
        CGContextAddPath(ctx, ovalPath.CGPath);
        CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
        CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);
        CGContextSetLineDash(ctx, 0, NULL, 0);
        CGContextDrawPath(ctx, kCGPathFillStroke);
    
        // 標(biāo)記出每個(gè)點(diǎn)并連線
        CGContextSetFillColorWithColor(ctx, [UIColor yellowColor].CGColor);
        CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
        NSArray *points = @[[NSValue valueWithCGPoint:pointA], [NSValue valueWithCGPoint:pointB], [NSValue valueWithCGPoint:pointC], [NSValue valueWithCGPoint:pointD], [NSValue valueWithCGPoint:c1], [NSValue valueWithCGPoint:c2], [NSValue valueWithCGPoint:c3], [NSValue valueWithCGPoint:c4], [NSValue valueWithCGPoint:c5], [NSValue valueWithCGPoint:c6], [NSValue valueWithCGPoint:c7], [NSValue valueWithCGPoint:c8]];
        [self drawPoint:points withContext:ctx];
    
        // 連接輔助線
        UIBezierPath *helperline = [UIBezierPath bezierPath];
        [helperline moveToPoint:pointA];
        [helperline addLineToPoint:c1];
        [helperline addLineToPoint:c2];
        [helperline addLineToPoint:pointB];
        [helperline addLineToPoint:c3];
        [helperline addLineToPoint:c4];
        [helperline addLineToPoint:pointC];
        [helperline addLineToPoint:c5];
        [helperline addLineToPoint:c6];
        [helperline addLineToPoint:pointD];
        [helperline addLineToPoint:c7];
        [helperline addLineToPoint:c8];
        [helperline closePath];
    
        CGContextAddPath(ctx, helperline.CGPath);
    
        CGFloat dash2[] = {2.0, 2.0};
        CGContextSetLineDash(ctx, 0.0, dash2, 2);
        CGContextStrokePath(ctx);
    }
    
    // 在某個(gè)point位置畫一個(gè)點(diǎn)拦键,方便觀察運(yùn)動(dòng)情況
    -(void)drawPoint:(NSArray *)points withContext:(CGContextRef)ctx {
    
        for (NSValue *pointValue in points) {
            CGPoint point = [pointValue CGPointValue];
            CGContextFillRect(ctx, CGRectMake(point.x - 2, point.y - 2, 4, 4));
        }
    }
    
    // 設(shè)置滑塊的移動(dòng)位置
    -(void)setProgress:(CGFloat)progress {
    
        _progress = progress;
    
        // 外接矩形在左側(cè)谣光,B點(diǎn)動(dòng)
        if (progress <= 0.5) {
            self.movePoint = POINT_B;
            NSLog(@"B點(diǎn)動(dòng)");
        } else {
            self.movePoint = POINT_D;
            NSLog(@"D點(diǎn)動(dòng)");
        }
        self.lastProgress = progress;
    
        CGFloat origin_x = self.position.x - outsideRectSize / 2 + (progress - 0.5) * (self.frame.size.width - outsideRectSize);
        CGFloat origin_y = self.position.y - outsideRectSize / 2;
    
        self.outsideRect = CGRectMake(origin_x, origin_y, outsideRectSize, outsideRectSize);
    
        [self setNeedsDisplay];
    }
    
    @end
    
    
  • 創(chuàng)建繼承自UIViewCircleView類,具體代碼如下
    //  CircleView.h
    
    #import <UIKit/UIKit.h>
    #import "CircleLayer.h"
    
    @interface CircleView : UIView
    
    /** 圓的layer層 */
    @property(nonatomic, strong)CircleLayer *circleLayer;
    
    @end
    
    //  CircleView.m
    
    #import "CircleView.h"
    
    @implementation CircleView
    
    +(Class)layerClass {
        return [CircleLayer class];
    }
    
    -(instancetype)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            self.circleLayer = [CircleLayer layer];
            self.circleLayer.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
            self.circleLayer.contentsScale = [UIScreen mainScreen].scale;
            [self.layer addSublayer:self.circleLayer];
        }
        return self;
    }
    
    @end
    
  • 控制器代碼如下所示
    //  ViewController.m
    #import "ViewController.h"
    #import "CircleView.h"
    
    @interface ViewController ()
    
    /** 滑塊 */
    @property (weak, nonatomic) IBOutlet UISlider *mySlider;
    /** 滑塊的值 */
    @property (weak, nonatomic) IBOutlet UILabel *currentValueLabel;
    /** 圓視圖 */
    @property(nonatomic, strong)CircleView *cv;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        [self.mySlider addTarget:self action:@selector(valuechange:) forControlEvents:UIControlEventValueChanged];
    
        self.cv = [[CircleView alloc] initWithFrame:CGRectMake(self.view.frame.size.width / 2 - 320 / 2, self.view.frame.size.height / 2 - 320 / 2, 320, 320)];
        [self.view addSubview:self.cv];
    
        // 首次進(jìn)入
        self.cv.circleLayer.progress = _mySlider.value;
    }
    
    // 滑塊值改變
    -(void)valuechange:(UISlider *)sender {
    
        self.currentValueLabel.text = [NSString stringWithFormat:@"Current: %f", sender.value];
        self.cv.circleLayer.progress = sender.value;
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    
    
  • 運(yùn)行結(jié)果如圖所示
運(yùn)行結(jié)果圖.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末芬为,一起剝皮案震驚了整個(gè)濱河市萄金,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌媚朦,老刑警劉巖氧敢,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異询张,居然都是意外死亡孙乖,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來唯袄,“玉大人弯屈,你說我怎么就攤上這事×悼剑” “怎么了资厉?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長梅掠。 經(jīng)常有香客問我酌住,道長,這世上最難降的妖魔是什么阎抒? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任酪我,我火速辦了婚禮,結(jié)果婚禮上且叁,老公的妹妹穿的比我還像新娘都哭。我一直安慰自己,他們只是感情好逞带,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布欺矫。 她就那樣靜靜地躺著,像睡著了一般展氓。 火紅的嫁衣襯著肌膚如雪穆趴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天遇汞,我揣著相機(jī)與錄音未妹,去河邊找鬼。 笑死空入,一個(gè)胖子當(dāng)著我的面吹牛络它,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播歪赢,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼化戳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了埋凯?” 一聲冷哼從身側(cè)響起点楼,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎白对,沒想到半個(gè)月后盟步,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡躏结,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年却盘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡黄橘,死狀恐怖兆览,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情塞关,我是刑警寧澤抬探,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站帆赢,受9級特大地震影響小压,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜椰于,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一怠益、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瘾婿,春花似錦蜻牢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至笛谦,卻和暖如春抱虐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饥脑。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工梯码, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人好啰。 一個(gè)月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像儿奶,于是被迫代替她去往敵國和親框往。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349

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

  • 玩轉(zhuǎn)貝塞爾曲線 歷史:由法國雷諾汽車的工程師皮諾爾·貝塞爾發(fā)明闯捎,應(yīng)用于雷諾汽車設(shè)計(jì)原理鋪墊:給定 n+1個(gè)數(shù)據(jù)點(diǎn)椰弊,...
    百草紀(jì)閱讀 1,184評論 1 9
  • #define kBlackColor [UIColor blackColor] //.h //劃線 + (voi...
    CHADHEA閱讀 788評論 0 1
  • Quartz2D以及drawRect的重繪機(jī)制字?jǐn)?shù)1487 閱讀21 評論1 喜歡1一、什么是Quartz2D Q...
    PurpleWind閱讀 766評論 0 3
  • 前言 前段時(shí)間看到一個(gè)挺有趣的動(dòng)畫效果瓤鼻,于是就想著實(shí)現(xiàn)一下秉版,順便練下手,這里是第一篇教程茬祷,介紹了啟動(dòng)動(dòng)畫的制作清焕,示...
    Arthury閱讀 670評論 5 11
  • 我愛你 我不敢說 不想說給山川 也不想說給大地 卻被風(fēng)兒泄露了秘密 風(fēng)兒知道了 全世界就知道了 我愛你
    驚濤的詩閱讀 255評論 5 13