-->

Smoother freehand drawing experience (iOS)

2020-07-24 05:09发布

问题:

I am making a math related activity in which the user can draw with their fingers for scratch work as they try to solve the math question. However, I notice that when I move my finger quickly, the line lags behind my finger somewhat noticeably. I was wondering if there was some area I had overlooked for performance or if touchesMoved simply just doesn't come enough (it is perfectly smooth and wonderful if you don't move fast). I am using UIBezierPath. First I create it in my init method like this:

myPath=[[UIBezierPath alloc]init];
myPath.lineCapStyle=kCGLineCapSquare;
myPath.lineJoinStyle = kCGLineJoinBevel;
myPath.lineWidth=5;
myPath.flatness = 0.4;

Then in drawRect:

- (void)drawRect:(CGRect)rect
{
    [brushPattern setStroke];
    if(baseImageView.image)
    {
        CGContextRef c = UIGraphicsGetCurrentContext();
        [baseImageView.layer renderInContext:c];
    }

    CGBlendMode blendMode = self.erase ? kCGBlendModeClear : kCGBlendModeNormal;
    [myPath strokeWithBlendMode:blendMode alpha:1.0];
}

baseImageView is what I use to save the result so that I don't have to draw many paths (gets really slow after a while). Here is my touch logic:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
    [myPath moveToPoint:[mytouch locationInView:self]];

}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{    
    UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
    [myPath addLineToPoint:[mytouch locationInView:self]];
    [self setNeedsDisplay];
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{    
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0f);
    CGContextRef c = UIGraphicsGetCurrentContext();
    [self.layer renderInContext:c];

    baseImageView.image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    [myPath removeAllPoints];
    [self setNeedsDisplay];
}

This project is going to be released as an enterprise app, so it will only be installed on iPad 2. Target iOS is 5.0. Any suggestions about how I can squeeze a little more speed out of this would be appreciated.

回答1:

Of course you should start by running it under Instruments and look for your hotspots. Then you need to to make changes and re-evaluate to see their impact. Otherwise you're just guessing. That said, some notes from experience:

  • Adding lots of elements to a path can get very expensive. I would not be surprised if your addLineToPoint: turns out to be a hotspot. It has been for me.
  • Rather than backing your system with a UIImageView, I would probably render into a CGLayer. CGLayers are optimized for rendering into a specific context.
  • Why accumulate the path at all rather than just rendering it into the layer at each step? That way your path would never be more than two elements (move, addLine). Typically the two-stage approach is used so you can handle undo or the like.
  • Make sure that you're turning off any UIBezierPath features you don't want. In particular, look at the section "Accessing Draw Properties" in the docs. You may consider switching to CGMutablePath rather than UIBezierPath. It's not actually faster when configured the same, but it's default settings turn more things off, so by default it's faster. (You're already setting most of these; you'll want to experiment a little in Instruments to see what impact they make.)


回答2:

http://mobile.tutsplus.com/tutorials/iphone/ios-sdk_freehand-drawing/

This link exactly shows how to make a curve smoother . This tutorial shows it step by step. And simply tells us how we can add some intermediate points (in touchesMoved method) to our curves to make them smoother.