4

何日もの間、問題に苦しんでいます。ここで答えが得られることを願っています。このリンクを使用して、フリーハンドの描画をスムーズにしました。このコードでは、線の幅と色を設定できましたが、元に戻るでうまく機能しているこのリンクを使用して元に/やり直し機能を含めると、非常に難しいと感じていますが、フリーハンドでの描画はスムーズではありません。

いくつかの調査とコーディングの後で、私はそれが元に戻る/やり直しを妨げると思う描画のキャッシングであることを知ることになっています。

最初のリンクに「CachedLIView.h/m」というファイルがあります。これを使用して元に戻る/やり直しを含めようとすると、次の方法で見つかりました。

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event // (2)
{
    UITouch *touch = [touches anyObject];
    CGPoint p = [touch locationInView:self];
    [path addLineToPoint:p];

    [self drawBitmap]; // (3)
    [self setNeedsDisplay];

    [path removeAllPoints]; //(4)
}

このメソッドはdrawBitMapを呼び出しています。このメソッドは、ユーザーが指を離すたびに一時的な画像を実際に生成し、同時に「パス」からポイントを削除します。

- (void)drawBitmap // (3)
{
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0);
    [[UIColor blackColor] setStroke];
    if (!incrementalImage) // first draw; paint background white by ...
    {
        UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds]; // enclosing bitmap by a rectangle defined by another UIBezierPath object
        [[UIColor greenColor] setFill];
        [rectpath fill]; // filling it with white
    }
    [incrementalImage drawAtPoint:CGPointZero];
    //[path stroke];
    for (UIBezierPath *_path in pathArray)
        [_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
    incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}

元に戻す/やり直しができるように、すべてのパスを配列に保存しています。(2番目のリンクからこのアイデアを採用しました)。

以下は、元に戻る/やり直しを含めるために変更したこのファイルの完全なコードです。

    #import "CachedLIView.h"

@implementation CachedLIView
{
    UIBezierPath *path;
    UIImage *incrementalImage; // (1)
}

- (id)initWithFrame:(CGRect)frame // (1)
{
    if (self = [super initWithFrame:frame])
    {
        [self setMultipleTouchEnabled:NO]; // (2)
        //        [self setBackgroundColor:[UIColor whiteColor]];
//                path = [[UIBezierPath alloc] init];
//                [path setLineWidth:3];

        pathArray=[[NSMutableArray alloc]init];
        bufferArray=[[NSMutableArray alloc]init];
        [self drawBitmap];
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
    NSLog(@"in drawrect pathArray[count]: %d", pathArray.count);

    [incrementalImage drawInRect:rect]; // (3)

    //[[UIColor blackColor] setStroke];
    //[path stroke];
    for (UIBezierPath *_path in pathArray)
        [_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    path = [[UIBezierPath alloc] init];
    path.lineWidth = 3;

    UITouch *touch = [touches anyObject];
    CGPoint p = [touch locationInView:self];
    [path moveToPoint:p];

    [pathArray addObject:path];

}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint p = [touch locationInView:self];
    [path addLineToPoint:p];


    [self setNeedsDisplay];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event // (2)
{
    UITouch *touch = [touches anyObject];
    CGPoint p = [touch locationInView:self];
    [path addLineToPoint:p];

    [self drawBitmap]; // (3)
    [self setNeedsDisplay];

    [path removeAllPoints]; //(4)
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self touchesEnded:touches withEvent:event];
}

- (void)drawBitmap // (3)
{
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0);
    [[UIColor blackColor] setStroke];
    if (!incrementalImage) // first draw; paint background white by ...
    {
        UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds]; // enclosing bitmap by a rectangle defined by another UIBezierPath object
        [[UIColor greenColor] setFill];
        [rectpath fill]; // filling it with white
    }
    [incrementalImage drawAtPoint:CGPointZero];
    //[path stroke];
    for (UIBezierPath *_path in pathArray)
        [_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
    incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}

#pragma mark - undo/redo
-(void)undoButtonClicked
{
    if([pathArray count]>0){
        UIBezierPath *_path=[pathArray lastObject];
        [bufferArray addObject:_path];
        [pathArray removeLastObject];

        [self drawBitmap];
        [self setNeedsDisplay];
    }
}

-(void)redoButtonClicked
{
    if([bufferArray count]>0){
        UIBezierPath *_path=[bufferArray lastObject];
        [pathArray addObject:_path];
        [bufferArray removeLastObject];

        [self drawBitmap];
        [self setNeedsDisplay];
    }
}
@end

.hファイルは次のとおりです。

#import <UIKit/UIKit.h>

@interface CachedLIView : UIView
{
    NSMutableArray *pathArray;
    NSMutableArray *bufferArray;
    UIBezierPath *myPath;

}
-(void)undoButtonClicked;
-(void)redoButtonClicked;
@end

私を助けてください。私が間違っていること。pathArrayカウントは正しく機能しています。ただし、画面に元に戻す/やり直しの効果を表示することはできません。

4

2 に答える 2

2

コード全体を取得することはできませんが、そのようなものを実装する方法を提案できます。

手描きでのやり直しと元に戻すにはcapture image render、タッチ開始またはタッチ終了と の時点で実行できますmanage stack of that renders。次に、要件(やり直し/元に戻す)に従って、キャッシュメモリからそのレンダリングを使用します。手順は次のようになります。

1) ボードに触れたときにレンダリングをキャプチャして保存します。そのシーケンスをキャッシュで管理します。

  • したがって、タッチを開始するたびに、画像をキャプチャして順番に保存する必要があります。

2) その時点で元に戻すを押すと、最後のレンダリングが取得され、それがボードに置き換えられます。

3) やり直すには、現在置き換えられているレンダリングよりも高いレンダリングが利用可能かどうかを確認できます。最後に更新されたレンダリングでそのボタンを有効または無効にできることを意味します。

4) 画像の保存が完了したら、キャッシュを空にすることを忘れないでください。これにより、次の描画のためにスタックを管理できます。


  • この考えがわからない場合はお知らせください。
于 2012-12-06T13:46:42.373 に答える
1

最後に、元に戻す/やり直し機能を使用してスムーズに描画できるようになりました。問題を引き起こしていたのはdrawBitMapメソッドでした..

この [self drawBitmap] メソッドの呼び出しをどこでも削除 (コメント) しました。

touchesEnded および undo/redo メソッドでこのメソッドを呼び出していました。ユーザーが画面から指を離すたびにキャッシング(描画を高速化するため)を行うため、この方法を使用する必要はないと感じました。新しい画像が作成されて画面に配置され、古い画像が削除され、ユーザーは自分が連続して描く。しかし、このキャッシュは、本当にパフォーマンスを改善したいという極端な状況でのみ必要です (メモリ不足になり、描画が見苦しくなった場合)。

そこで、このキャッシング メカニズムを後の段階で保存し、削除することにしました。元に戻す/やり直し機能が機能しない理由を見つけることはできませんでしたが、新しい画像をキャッシュして画面に配置したとき (ユーザーが指を離したとき)、問題が発生していたと思います。最後にキャッシュされたイメージを保持する必要があります (元に戻す/やり直すため)。

後の段階でキャッシュを使用し、コードの最適化も試みます。

[myPath removeAllPoints] も忘れずに削除してください。touchesEnded: method からのこの行、そうでなければ、指を離すとすぐに描画が消えてしまいます。

これが誰かを助けることを願っています。これが touchesEnded: 変更されたメソッドです。

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event // (2)
{
       UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[path addLineToPoint:p];

    //[self drawBitmap]; // CAUSES PROBLEM IF UNCOMMENTED AND UNDO/REDO WILL STOP WORKING..
    [self setNeedsDisplay];


    //[myPath removeAllPoints];// LINE GETS DRAWN BUT VANISHED WHEN TOUCH LIFTED OFF FROM SCREEN..
    ctr = 0;
}

後で、この機能を SmoothedBIView に追加したところ、非常にうまく機能しました。

于 2012-12-11T11:52:17.047 に答える