首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

iOS Core Text 實現文本編輯功能:從觸摸交互到排版渲染完整流程

     編輯:關於C

功能架構概覽

本方案實現基於 Core Text 的富文本編輯器,核心流程:

  1. 手勢識別:觸摸劃定矩形區域
  2. 臨時編輯視圖:彈出鍵盤接收輸入
  3. 鍵盤適配:視圖上移避免遮擋
  4. Core Text 排版渲染:將編輯內容轉為屬性字符串繪製

核心類職責

類職責
TextTool處理觸摸事件、管理臨時 UITextView、鍵盤通知響應
TextDrawingInfo封裝 Core Text 繪製所需數據(路徑、文本、屬性、顏色、字體)
DoodleView畫布視圖,管理 drawables 數組,統一調度繪製

關鍵流程詳解

1. 觸摸劃定矩形區域


// touchesBegan: 記錄起始點
// touchesMoved: 空實現(由 drawTemporary 繪製預覽矩形)
// touchesEnded: 核心邏輯
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    // 1. 計算最終矩形 rect
    // 2. 過濾過小矩形 (距離 < 50pt)
    // 3. 創建半透明遮罩 backgroundShade (tag=SHADE_TAG)
    // 4. 創建 UITextView,frame = rect
    // 5. 註冊鍵盤通知 (WillShow/DidShow/WillHide/DidHide)
    // 6. 計算鍵盤遮擋距離 viewSlideDistance
    // 7. 設置 delegate,成為第一響應者彈出鍵盤
}

2. 鍵盤動畫適配


- (void)keyboardWillShow:(NSNotification *)note {
    // 根據方向調整 view.frame.origin (x/y ±= viewSlideDistance)
    [UIView beginAnimations:@"viewSlideUp" context:NULL];
    // ... 修改 frame ...
    [UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification *)note {
    // 反向動畫恢復位置
}

關鍵點:預先計算 viewSlideDistance 確保輸入框不被鍵盤遮擋,支持四種設備方向。

3. 編輯結束與 Core Text 渲染


- (void)textViewDidEndEditing:(UITextView *)textView {
    // 1. 創建 TextDrawingInfo 封裝:路徑、文本、顏色、字體
    // 2. 加入 doodleView.drawables
    // 3. 清理:移除遮罩、textView、註銷通知
    // 4. 觸發重繪
}

4. Core Text 繪製核心 TextDrawingInfo.draw


- (void)draw {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    // 1. 創建屬性字符串
    NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:self.text];
    [attrStr addAttribute:(NSString *)kCTForegroundColorAttributeName
                    value:(id)self.strokeColor.CGColor
                    range:NSMakeRange(0, self.text.length)];

    // 2. 創建 Framesetter -> Frame
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrStr);
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attrStr.length), self.path.CGPath, NULL);
    CFRelease(framesetter);

    // 3. 坐標系翻轉 (Core Text Y軸向上,UIKit Y軸向下)
    CGContextSaveGState(ctx);
    CGContextTranslateCTM(ctx, 0, self.path.bounds.origin.y);
    CGContextScaleCTM(ctx, 1, -1);
    CGContextTranslateCTM(ctx, 0, -(self.path.bounds.origin.y + self.path.bounds.size.height));

    // 4. 繪製並釋放
    CTFrameDraw(frame, ctx);
    CGContextRestoreGState(ctx);
    CFRelease(frame);
}

關鍵技術難點解析

坐標系翻轉

Core Text 繼承自 Mac OS X,坐標系原點在左下角(Y向上);UIKit 原點在左上角(Y向下)。繪製前必須通過 CGContextScaleCTM(ctx, 1, -1) 翻轉 Y 軸,並配合平移使內容位置正確。

屬性字符串構建

  • kCTForegroundColorAttributeName:文字顏色(CGColor)
  • kCTFontAttributeName:字體(CTFontRef)
  • kCTUnderlineStyleAttributeName:下劃線樣式
  • kCTParagraphStyleAttributeName:段落樣式(行間距、換行模式)

段落樣式配置


// 行間距
CTParagraphStyleSetting lineSpacing = {
    .spec = kCTParagraphStyleSpecifierLineSpacingAdjustment,
    .value = &spacing,  // CGFloat
    .valueSize = sizeof(CGFloat)
};
// 換行模式
CTParagraphStyleSetting lineBreak = {
    .spec = kCTParagraphStyleSpecifierLineBreakMode,
    .value = &mode,  // CTLineBreakMode
    .valueSize = sizeof(CTLineBreakMode)
};
CTParagraphStyleRef style = CTParagraphStyleCreate(settings, 2);
[attrStr addAttribute:(NSString *)kCTParagraphStyleAttributeName value:(id)style range:NSMakeRange(0, attrStr.length)];
CFRelease(style);

替代方案:CATextLayer

對於簡單場景,可直接使用 CATextLayer 避免手動 Core Text 繪製:


CATextLayer *layer = [CATextLayer layer];
layer.string = attributedString;  // 直接支持 NSAttributedString
layer.frame = CGRectMake(...);
[self.view.layer addSublayer:layer];

優勢:自動處理坐標系、動畫友好、代碼極簡。劣勢:複雜排版(多欄、環繞、自定義截斷)能力弱於 Core Text。

工程化建議

  • 內存管理:Core Text 對象 (CTFrameRef, CTFramesetterRef) 需手動 CFRelease
  • 性能優化:緩存 CTFramesetterRef 避免重複創建;大文本考慮分頁/虛擬化
  • 編輯體驗:支持選中、複製粘貼、撤銷重做、輸入法標記文本處理
  • 無障礙:實現 UIAccessibility 協議支持 VoiceOver

總結

本方案展示了從底層觸摸交互到高級排版渲染的完整鏈路。Core Text 雖學習曲線陡峭,但提供了最精細的文本佈局控制能力,是實現專業級文本編輯器、排版引擎的基石。理解其坐標系、屬性字符串、Framesetter/Frame 模型是掌握 Core Text 的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved