iphonexcodeuiviewresolutionresolution-independence

My vector sprite renders in different locations in simulator and device


I'm implementing a subclass of UIView that displays a gauge dial with a sprite for the indicator. It has angle property that I can vary to make the needle point to different angles. It works, but on the same values for the position of the needle make it show up in different locations on the phone and the simulator. It's an iPhone 4, so I'm sure the double resolution thing is behind this, but I don't know what to do about it. I tried setting the UIView's layer's contentScaleFactor but that fails. I thought UIView got the resolution thing for free. Any suggestions?

I should note that the NSLog statements report 150 for both .frame.size. dimensions, in both the simulator and the device.

Here's the .m file

UPDATE: In the simulator, I found how to set the hardware to iPhone 4, and it looks just like the device now, both are scaling and positioning the sprite at half size.

UPDATE 2: I made a workaround. I set the .scale of my sprite equal to the UIView's contentScaleFactor and then use it to dived the UIView in half if it's a lo-res screen and the full width if it's hi-res. I still don't see why this is necessary, as I should be working in points now, not pixels. It must have something to do with the custom drawing code in the Sprite or VectorSprite classes.

I'd still appreciate some feedback if anyone has some...


#import "GaugeView.h"

@implementation GaugeView

@synthesize needle;

#define kVectorArtCount 4

static CGFloat kVectorArt[] = {
    3,-4,
    2,55,
    -2,55,
    -3,-4
};

- (id)initWithCoder:(NSCoder *)coder {
 if (self = [super initWithCoder:coder]) {
    needle = [VectorSprite withPoints:kVectorArt count:kVectorArtCount];
    needle.scale = (float)self.contentScaleFactor; // returns 1 for lo-res, 2 for hi-res
    NSLog(@"  needle.scale = %1.1f", needle.scale);
    needle.x = self.frame.size.width / ((float)(-self.contentScaleFactor) + 3.0); // divisor = 1 for hi-res, 2 for lo-res
    NSLog(@"  needle.x = %1.1f", needle.x);
    needle.y = self.frame.size.height / ((float)(-self.contentScaleFactor) + 3.0);
    NSLog(@"  needle.y = %1.1f", needle.y);
    needle.r = 0.0;
    needle.g = 0.0;
    needle.b = 0.0;
    needle.alpha = 1.0; }
 }
 self.backgroundColor = [UIColor clearColor];
 return self;
}

- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        // Initialization code
    }
    return self;
}


// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
 CGContextRef context = UIGraphicsGetCurrentContext();
 CGContextSaveGState(context);

 CGAffineTransform t0 = CGContextGetCTM(context);
 t0 = CGAffineTransformInvert(t0);
 CGContextConcatCTM(context, t0);

 [needle updateBox];
 [needle draw: context];
}    

- (void)dealloc {
    [needle release];
    [super dealloc];
}


@end

Solution

  • I believe the answer is that iOS takes care of the resolution scaling automatically in drawRect methods, but in custom drawing code, you have to do it yourself.

    In my example, I used the UIView's contentsScaleFactor to scale my sprite. In the future, in my custom draw method (not shown) I'll query [UIScreen mainScreen] scale and scale accordingly there.