1. 程式人生 > >iOS開發必會的坐標系探究

iOS開發必會的坐標系探究

繪制圖形 背景 參考 一段 efi develop dev graphic ram

歡迎大家前往騰訊雲+社區,獲取更多騰訊海量技術實踐幹貨哦~

本文由落影發表於雲+社區專欄

前言

app在渲染視圖時,需要在坐標系中指定繪制區域。 這個概念看似乎簡單,事實並非如此。

When an app draws something in iOS, it has to locate the drawn content in a two-dimensional space defined by a coordinate system. This notion might seem straightforward at first glance, but it isn’t.

正文

我們先從一段最簡單的代碼入手,在drawRect中顯示一個普通的UILabel; 為了方便判斷,我把整個view的背景設置成黑色:

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    CGContextRef context = UIGraphicsGetCurrentContext();
    NSLog(@"CGContext default CTM matrix %@", NSStringFromCGAffineTransform(CGContextGetCTM(context)));
    UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 28)];
    testLabel.text = @"測試文本";
    testLabel.font = [UIFont systemFontOfSize:14];
    testLabel.textColor = [UIColor whiteColor];
    [testLabel.layer renderInContext:context];
}

這段代碼首先創建一個UILabel,然後設置文本,顯示到屏幕上,沒有修改坐標。 所以按照UILabel.layer默認的坐標(0, 0),在左上角進行了繪制。

技術分享圖片UILabel繪制

接著,我們嘗試使用CoreText來渲染一段文本。

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    CGContextRef context = UIGraphicsGetCurrentContext();
    NSLog(@"CGContext default matrix %@", NSStringFromCGAffineTransform(CGContextGetCTM(context)));
    NSAttributedString *attrStr = [[NSAttributedString alloc] initWithString:@"測試文本" attributes:@{
                                                                                                  NSForegroundColorAttributeName:[UIColor whiteColor],
                                                                                                  NSFontAttributeName:[UIFont systemFontOfSize:14],
                                                                                                  }];
    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef) attrStr); // 根據富文本創建排版類CTFramesetterRef
    UIBezierPath * bezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 100, 20)];
    CTFrameRef frameRef = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), bezierPath.CGPath, NULL); // 創建排版數據
    CTFrameDraw(frameRef, context);
}

首先用NSString創建一個富文本,然後根據富文本創建CTFramesetterRef,結合CGRect生成的UIBezierPath,我們得到CTFrameRef,最終渲染到屏幕上。 但是結果與上文不一致:文字是上下顛倒。

技術分享圖片CoreText的文本繪制

從這個不同的現象開始,我們來理解iOS的坐標系。

坐標系概念

在iOS中繪制圖形必須在一個二維的坐標系中進行,但在iOS系統中存在多個坐標系,常需要處理一些坐標系的轉換。 先介紹一個圖形上下文(graphics context)的概念,比如說我們常用的CGContext就是Quartz 2D的上下文。圖形上下文包含繪制所需的信息,比如顏色、線寬、字體等。用我們在Windows常用的畫圖來參考,當我們使用畫筆

iOS開發必會的坐標系探究