iOS動畫篇:自定義View

bsgh5998 8年前發布 | 13K 次閱讀 Quartz 2D iOS開發 移動開發

引言

在iOS動畫篇:核心動畫中講到如何給一個視圖添加動畫效果,但是其僅局限在系統控件的具有動畫效果的屬性。假設現在我們要做一個空心圓形的進度條,隨著進度的變化具有對應的動畫效果,這時候就需要去自定義一個圓形的View,并實現其形狀隨進度屬性的變化而變化,使用Quartz2D就可以輕松滿足此需求。

什么是Quartz2D

Quartz2D是iOS和OSX中的一個二維繪圖引擎,這組API具有許多強大的功能,如:圖形的繪制、透明層、陰影、顏色管理、反鋸齒、PDF文檔的管理等等。

本文主要介紹了Quartz2D主要相關概念,描述其中的圖形繪制部分(通過路徑繪制圖形),以實現自定義View。本文不對Quartz2D的基礎過多提及,如果讀者需要更深入了解Quartz2D,可以Google"Quartz2D編程指南"研讀Quartz2D系列譯文。

相關概念

使用Quartz2D來繪制圖形,需要知道的相關概念:

1、Core Graphics

Core Graphic是一套基于C的框架,用于一切繪圖操作,UIKit就是基于Core Graphic實現的,因此它可以實現比UIKit更底層的功能。

Core Graphic

Core Graphic使用Quartz2D作為繪圖引擎,因此Quartz2D其實是Core Graphic的一部分,這兩個名詞密不可分。

2、圖形上下文

畫畫需要畫布,Core Graphics工作是的“畫布”就是圖形上下文,它決定圖形繪制成什么樣子,并繪制到哪里去。在“畫布”中,每個連續的繪制操作都可以看成添加一個“圖層”到畫布上,在運行中我們可以通過額外的繪制操作來疊加更多“圖層”來形成復雜的圖形。

推薦使用UIView自動為我們準備好的圖形上下文,因為自定義上下文會降低內存的使用效率,導致性能下降。當需要我們調用UIGraphicsGetCurrentContext()來獲取圖形上下文。

3、路徑

相信很多人都臨摹過書法,在一張薄薄的紙上照著書法家的筆跡來書寫,這個“筆跡”就可以看成路徑,通過確定的路徑,可以確定繪圖的形狀、渲染的區域等等。

通過創建路徑并加入到上下文中渲染就能繪制出想要的圖形。

創建路徑有以下三種方式:

1.使用CGContextRef創建,如CGContextAddArc

這種方式是直接對圖形上下文進行操作,常用的方法有:

CGContextBeginPath //開始畫路徑
   CGContextMoveToPoint //移動到某一點
   CGContexAddLineToPoint //畫直線
   CGContexAddCurveToPoint //畫餅圖
   CGContexAddEllipseInRect //畫橢圓
   CGContexAddArc //畫圓
   CGContexAddRect //畫方框
   CGContexClosePath //封閉當前路徑

2.使用CGPathRef創建,如CGPathAddArc

使用方法一繪制路徑后將清空圖形上下文,如果我們想保存路徑來復用,可以使用Quartz提供的CGPath函數集合來創建可復用的路徑對象。

常用的函數如下:

CGPathCreateMutable
   CGPathMoveToPoint
   CGPathAddLineToPoint
   CGPathAddCurveToPoint
   CGPathAddEllipseInRect
   CGPathAddArc
   CGPathAddRect
   CGPathCloseSubpath

這些函數和上面方法一的一一對應,可代替之使用。

CGContextAddPath:添加一個新的路徑

3.使用UIBezierPath創建,如bezierPathWithOvalInRect

UIBezierPath存在于UIKit中,是對路徑繪制的封裝,和CGContextRef類似,優點是更面向對象,我們可以像操作普通對象一樣對其進行操作。

在自定義View的時候,一般使用UIBezierPath來創建路徑就能基本滿足我們的需求,推薦使用。

UIBezierPath的常用方法如下:

@property(nonatomic) CGFloat lineWidth; //線的寬度
@property(nonatomic) CGLineCap lineCapStyle; //起點和終點樣式
@property(nonatomic) CGLineJoin lineJoinStyle; //轉角樣式
//創建path

  • (instancetype)bezierPath; //矩形
  • (instancetype)bezierPathWithRect:(CGRect)rect; //以矩形框為切線畫圓
  • (instancetype)bezierPathWithOvalInRect:(CGRect)rect; //帶圓角的矩形框
  • (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius; // rounds all corners with the same horizontal and vertical radius //畫圓弧
  • (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise; //移動到某一點
  • (void)moveToPoint:(CGPoint)point; //添加直線
  • (void)addLineToPoint:(CGPoint)point; //帶一個基準點的曲線
  • (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint; //帶兩個基準點的曲線
  • (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2; //封閉路徑
  • (void)closePath; //添加新的路徑
  • (void)appendPath:(UIBezierPath *)bezierPath; //渲染
  • (void)fill;
  • (void)stroke;</code></pre>

    4、渲染

    繪畫的最后一步,它之于繪圖的意義如畫畫的最后上顏料一樣。

    渲染分為兩種方式:

    1)填充Fill:將路徑內部填充渲染

    2)描邊Stroke:不填充,只對路徑進行渲染

    5、繪圖狀態棧

    圖形上下文包含一個繪圖狀態棧,默認為空。

    1)保存圖形狀態時,將創建當前圖形狀態的一個副本并入棧。

    2)還原圖形狀態時,將棧頂的圖形狀態推出棧并替換當前圖形狀態。

    使用:調用CGContextSaveGState來保存,CGContextRestoreGState來還原。

    繪圖的核心步驟

    在view上繪制一個圖形的方式有很多種,表現形式可能不一樣,但其實質步驟都是一樣的:

    1)獲取上下文

    2)繪制路徑

    3)添加路徑到上下文

    4)修改圖形狀態參數

    5)渲染上下文

    下面我們以畫一個圓形來演示其實現步驟:

    1)使用CGContextRef創建路徑

     //獲取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //繪制路徑: 圓形(中心坐標200、200、半徑100、起點弧度0、終點弧度2PI、畫的方向0逆1正)
    CGContextAddArc(ctx, 200, 200, 100, 0, M_PI * 2, 0);
    //修改圖形狀態參數
    CGContextSetRGBStrokeColor(ctx, 0.5, 0.5, 0.9, 1.0);//筆顏色
    CGContextSetLineWidth(ctx, 10);//線條寬度
    //渲染上下文
    CGContextStrokePath(ctx);

    2)使用CGPathRef創建路徑

     //獲取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //創建可變路徑
    CGMutablePathRef path = CGPathCreateMutable();
    //添加圓形到路徑中(所在路徑、不進行變換操作、中心坐標200、200、起點弧度0、終點弧度2PI、畫的方向0逆1正)
    CGPathAddArc(path, NULL, 200, 200, 100, 0, M_PI * 2, 1);
    //將路徑添加到上下文
    CGContextAddPath(ctx, path);
    //修改圖形狀態參數
    CGContextSetRGBStrokeColor(ctx, 0.5, 0.5, 0.9, 1.0);//筆顏色
    CGContextSetLineWidth(ctx, 10);//線條寬度
    //渲染上下文
    CGContextStrokePath(ctx);

    3)使用UIBezierPath創建路徑

     //創建路徑
    UIBezierPath * path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 200, 200)];
    //修改圖形狀態參數
    [[UIColor colorWithRed:0.5 green:0.5 blue:0.9 alpha:1.0] setStroke];//筆顏色
    [path setLineWidth:10];//線條寬度
    //渲染
    [path stroke];

    以上三種方式都可以實現繪制,通過比較我們可以發現使用UIBezierPath創建路徑的形式是最簡潔且最直觀的,推薦使用UIBezierPath,在以后的動畫中我們也將更多地應用UIBezierPath到動畫的實現中。

    自定義view的步驟

    只需簡單兩步即可:

    步驟一:新建一個類,繼承UIView類。

    步驟二:重載drawRect方法,在這個方法中進行繪圖。

    以自定義一個圓形View為例:

    1)新建CircleView類,繼承UIView類

     

    2)在CircleView.m中重載drawRect方法

      - (void)drawRect:(CGRect)rect {
    }

    3)畫一個圓

      - (void)drawRect:(CGRect)rect {
        UIBezierPath * path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 200, 200)];
        [[UIColor colorWithRed:0.5 green:0.5 blue:0.9 alpha:1.0] setStroke];
        [path setLineWidth:10];
        [path stroke];
    }

    4)創建CircleView的實例添加到視圖中

    - (void)viewDidLoad {
        [super viewDidLoad];
        CircleView * cricleView = [[CircleView alloc]initWithFrame:self.view.bounds];
        [self.view addSubview:cricleView];
    }

    5)效果圖

     

    成功畫了一個圓形,現在只差怎樣讓它“動起來”了!

    思考

    1、Quartz2D的坐標系和UIView的坐標系有什么不同?

    2、繪制圖形時不同路徑使用不同的狀態參數渲染需要怎樣操作?

    3、怎樣使用CALayer來自定義View?

     

    來自: http://www.cocoachina.com/ios/20160518/16293.html

     

 本文由用戶 bsgh5998 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!