摘要
IOS下使用CAShapeLayer+UIBezierPath實現互動畫板時橡皮擦的實現方式。
背景
要在IOS端做一個在線教育DEMO,集成音視頻互動、PPT白板互動、聊天等功能。
畫板實現
IOS畫板有很多實現,主要有
- DrawRect+UIBezierPath:實現比較簡單,橡皮擦也好實現,但是CPU較高,內存消耗大。
- CAShapeLayer+UIBezierPath:性能較好,使用GPU繪製,內存佔用也小,但是橡皮擦比較難實現。
- GLES:比較底層,開發要求較高。
綜合以上各個方式的特點,產品中比較合適的方案是CAShapeLayer+UIBezierPath,繪製辦法很簡單:
- 爲了支持多方不同的線色、線寬,每一筆都創建一個新的CAShapeLayer,每一筆都是覆蓋繪製;
- 使用UIBezierPath描述路徑,並將path傳遞給CAShapeLayer;
- 調用UIView.layer的addSublayer,將CAShapeLayer繪製到當前View上;
- 緩存CAShapeLayer,在需要撤銷一筆的時候只需要調用CAShapeLayer的removeFromSuperlayer,在需要重畫一筆的時候重新調用UIView.layer的addSublayer。
橡皮擦實現
橡皮擦本質上跟畫線是一樣的動作,只是線色是背景色,如果沒有背景圖片,只需要把線色設置成背景色就可以實現橡皮功能。但是在有背景圖片的場景下會比較麻煩,單一背景色會覆蓋背景圖片。這個時候需要把背景色設置成背景圖片,但是需要進行一定的變換,否則橡皮擦的背景圖片會發生翻轉,以下是核心代碼:
//創建一個新的Context
UIGraphicsBeginImageContext(self.frame.size);
//獲得當前Context
CGContextRef context = UIGraphicsGetCurrentContext();
//CTM變換,調整座標系,*重要*,否則橡皮擦使用的背景圖片會發生翻轉。
CGContextScaleCTM(context, 1, -1);
CGContextTranslateCTM(context, 0, -self.bounds.size.height);
//圖片適配到當前View的矩形區域,會有拉伸
[image drawInRect:self.bounds];
//獲取拉伸並翻轉後的圖片
UIImage *stretchedImg = UIGraphicsGetImageFromCurrentImageContext();
//將變換後的圖片設置爲背景色
[self setBackgroundColor:[[UIColor alloc] initWithPatternImage:stretchedImg]];
//View的圖層設置爲原始圖片,這裏會自動翻轉,經過這步後圖層顯示和橡皮背景都設置爲正確的圖片。
self.layer.contents = (_Nullable id)image.CGImage;
UIGraphicsEndImageContext();
代碼和註釋已經說明一切,CAShapeLayer+UIBezierPath的橡皮擦實現實際上也比較簡單,只要知道原理。
另外有人的實現方式是把所有的CAShapeLayer圖層合併成一張圖片,然後在合併後的圖片裏使用UIBeizerPath的strokeWithBlendMode:kCGBlendModeClear進行混色,這也是一種辦法,但是混色佔用的CPU也會很高,相對來說,使用背景圖片來當橡皮擦的畫刷,性能是較好的。