views:

4512

answers:

4

I'm developing an iPhone app that moves a UIView layer between other UIView layers based upon the accelerometer.

If the topmost layer is the one that's moving based upon the accelerometer, no problem. If I add a UIView on top of it, the movement is extremely delayed. If I add a second UIView on top of it, the movement stops.

The updateInterval is 60, and I'm using UIView's drawAtPoint: method to move the layer.

My question: is there a UIView property, such as opaque, clipsToBounds, etc. that needs to be enabled for accurate accelerometer based movement of a sandwiched UIView to occur?

Thanks in advance for any assistance you can provide.

+2  A: 

Each time you use drawAtPoint: you are forcing the UIView to be re-rendered into the graphics layer. This is expensive.

UIView already has a -frame property that defines its location and size. Updating just the location allows the graphics hardware to move already composited layers around.

I'm not sure what you mean by "sandwiching", but I'm assuming it is placing the layers at different z-indexes? If so, I'm assuming that the middle (layer you are moving) and top layers would have to be transparent, and the bottom layer should be opaque to be performant.

Let me know if that's not what you were looking for…

Dan Keen
A: 

Thanks Dan.

Yes that's what I meant by "sandwiching." And yes, the bottom layer is opaque and the layers above are transparent PNGs.

I'm having difficulty accessing the frame property of a UIView. Here's some of the code from my Object2D class:

- (id)initWithImage:(NSString*)imageName
{
    if (self = [super init])
    {
        position = [[Point2D alloc] init];
        vector = [[Vector2D alloc] init];
     imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:@"png"]; 
     myImageObj = [[UIImage alloc] initWithContentsOfFile:imagePath]; 
        size.width = myImageObj.size.width;
        size.height = myImageObj.size.height;
    }

    return self;
}

And here's the class' original draw: method that is called from the ViewController class:

- (void)draw
{
    [myImageObj drawAtPoint:CGPointMake( position.X, position.Y ) ];
    [ self setNeedsDisplay ];
}

I've tried various ways to access the frame property, to no avail:

    myImageObj.frame = CGRectMake(position.X, position.Y, size.width, size.height);
    myImageObj.CGImage.frame.y = position.Y;

Looking in the API docs suggest that the first way will work but it doesn't.

Do you know how to access the frame property of a UIView?

Thanks in advance.


+4  A: 

You can't set individual frame parameters directly. You must create a new CGRect and set the frame to that CGRect. There are different ways to change the parameters of a CGRect once you have created it.

CGRect myNewFrame = someView.frame;

myNewFrame.origin.x = 1.0;

myNewFrame.size = CGSizeMake(100.0f, 50.0f);

someView.frame = myNewFrame;

The idea is to set the CGRect how you want it and then set the view's frame property to that CGRect, then your good.

As far as the UIView... You may have a few problems. First, as said above the drawAtPoint method is expensive. Second, and maybe worse, you have several transparent images. Transparency is one of the most expensive operations on the iPhone, in fact, there is a test in Instruments just for that. You should avoid transparency at all costs. A few transparent PNGs with a redraw all during rotation will most likely give you app hiccups.

My next advice would be to consider if you need the View in the middle of the transparencies, maybe another layer could do the job. if you need touch functionality, you can use the view at the root of the layer hierarchy to handle touches. In other words from back to front you have this:
UIView CALayer UIView CALayer CALayer

but you could just have this: UIView (now handle all touches) CALayer CALayer (previously a view) CALayer CALayer

This will also help as CALayers have less overhead than UIViews.

Hope this helps.

Corey Floyd
A: 

I think you're misunderstanding how UIViews work. First, you want to create UIImageViews to host your UIImages. Then you want to add them to one superview using its addSubview: method. Finally, you want to change your middle UIImageView's frame property (within a beginAnimations / commitAnimations block if you want it smoothly animated) to make it move to your new position.

If you place your UIImage within an encapsulating UIImageView, it's cached as a texture on the GPU and any change in the position of the UIImageView will be hardware-accelerated. drawAtPoint:, as Dan pointed out, is horribly expensive and should be avoided if you can. You're on the right track with your myImageObj.frame = CGRectMake code, it just needs to be applied to a UIImageView, not a UIImage.

For a simple three-layer structure, unless you have massive images, even images with lots of transparency will animate smoothly. I've done this for dozens of transparent UIViews (which are only very light wrappers around CALayers) without a performance hitch.

As an aside, if your Point2D and Vector2D classes are just wrappers for 2-D coordinates, you might want to look into replacing those with CGPoint structs. There are a lot of supporting functions around that lightweight data type.

Brad Larson