2019-05-28画板-消去-注釈-取り消し復元などの機能実現ソリューション

4331 ワード

ネット上の資料を調べてまとめた:1.画板機能の実現案は多くの種類がある:DrawRect+UIBezierPath:実現は比較的簡単で、消しゴムも実現できるが、CPUが高く、メモリ消費が大きい.CAShapeLayer+UIBezierPath:性能が良く、GPUを使って描画し、メモリ占有量も小さいが、消しゴムは実現しにくい.
以上の各方式の特徴を総合して、製品の中で比較的に適当な方案はCAShapeLayer+UIBezierPathで、描画方法はとても簡単です:1.複数の異なる線色、線幅をサポートするために、各ペンは新しいCAShapeLayerを作成し、各ペンはオーバーライドペイントです.2.UIBezierPathを使用してパスを記述し、pathをCAShapeLayerに渡す.UIViewを呼び出す.LayerのaddSublayerは、CAShapeLayerを現在のViewに描画します.3.キャッシュCAShapeLayerは、ペンを取り消す必要があるときにCAShapeLayerのremoveFromSuperlayerを呼び出すだけで、ペンを書き直す必要があるときにUIViewを再呼び出す.layerのaddSublayer.
私は原文の作者のやり方と一致した.
2.消去機能消しゴムは本質的に線を引くのと同じ動作ですが、線色は背景色で、背景画像がなければ、線色を背景色に設定するだけで消しゴム機能を実現できます.しかし、背景画像のあるシーンでは面倒で、単一の背景色では背景画像が上書きされます.この場合、背景色を背景画像に設定する必要がありますが、一定の変換が必要です.そうしないと、消しゴムの背景画像が反転します.
//CTM  ,     ,*  *,                 。
 CGContextScaleCTM(context, 1, -1);
 CGContextTranslateCTM(context, 0, -self.bounds.size.height);
//swift     
context?.scaleBy(x: 1, y: -1)
//Changes the scale of the user coordinate system in a context.     x y   :(x1,y1)   (x1*sx,y1*sy)
//  sx =1 sy =-1, (x1,y1)  (x1,-y1)
context?.translateBy(x: 0, y: -self.bounds.size.height)
//Changes the origin of the user coordinate system in a context.         

パネルの背景色のコアコードを設定します.
 //      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();

注意:私たちはただ画板の座標系を変えただけで、画板の表示内容はimageの元の内容です.CAShapeLayer+UIBezierPathの消しゴム実装は、実際には画板の背景色に色を設定すれば簡単です.もう一つの解決策は、すべてのCAShapeLayerレイヤーを1枚の画像に統合し、統合後の画像にUIBeizerPathのstrokeWithBlendMode:kCGBledModeClearを使用して混色することも方法ですが、混色が占めるCPUも高く、相対的にバックグラウンド画像を使用して消しゴムのブラシにすると、性能が優れています.
備考:この文章はCGcontextRef、UIBezierPath、CGMutablePathRefをよく紹介しています
対応方法は次のとおりです.
属性の紹介
CGContextRef
UIBezierPath
CGMutablePathRef
開始点を設定
CGContextMoveToPoint
moveToPoint
CGPathMoveToPoint
中間点を追加
CGContextAddLineToPoint
addLineToPoint
CGPathAddRect
長方形を描く
CGContextAddRect
bezierPathWithRect
CGPathAddRect
円を描く
CGContextAddEllipseInRect
bezierPathWithOvalInRect
CGPathAddEllipseInRect
扇形を描く
CGContextAddArc
addArcWithCenter
CGPathAddArcToPoint
にじきょくせん
CGContextAddQuadCurveToPoint
addQuadCurveToPoint
CGPathAddQuadCurveToPoint
さんだんきょくせん
CGContextAddCurveToPoint
addCurveToPoint
CGPathAddCurveToPoin
備考:CAShapeLayerはカスタムパターンのアニメーション効果を作成できますが、ここでは詳しくは説明しません.
3.コメント機能描画文字はCGcontextでのみ開くことができます.UImitが提供する方法で描画する.メソッドの説明:
  • drawAtPoint:どの位置に描くかwithAttributes:テキストのスタイル.[str drawAtPoint:CGPointZero withAttributes:nil];
  • drawInRect:テキストをどの領域に描画するかwithAttributes:テキストのスタイル.[str drawInRect:rect withAttributes:nil];
  • 2.drawAtPoint: drawInRect:   ?
    drawAtPoint:       
    drawInRect:      
    
        //1.        
        NSString * str = @"                              ";
    
        //2.       ,  Attribute  
        NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
        //      
        dict[NSFontAttributeName] = [UIFont systemFontOfSize:45];
        //      
        dict[NSForegroundColorAttributeName] = [UIColor yellowColor];
        //        
        dict[NSStrokeWidthAttributeName] = @5;
        //       
        dict[NSStrokeColorAttributeName] = [UIColor greenColor];
        //       
        NSShadow * shadow = [[NSShadow alloc] init];
        shadow.shadowColor = [UIColor cyanColor];
        shadow.shadowOffset = CGSizeMake(10, 10);
        shadow.shadowBlurRadius = 10;
        dict[NSShadowAttributeName] = shadow;
    
        //3.        view  layer 
        [str drawAtPoint:CGPointZero withAttributes:nil];
        [str drawInRect:rect withAttributes:dict];
    

    リファレンスリンク
    このシナリオのスクリーンショットを使用すると、layerではなく画像が生成されるため、元に戻す処理とは異なります.
    スタックの管理方法と同様に、リストアスキームを取り消します.ここでは省略します.