IOS下實現高性能畫板橡皮擦的辦法

摘要

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也會很高,相對來說,使用背景圖片來當橡皮擦的畫刷,性能是較好的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章