UIImageview won't update after changing the center - iphone

I am trying to create a small augmented reality application where I move an image on top of the camera capture. So the only thing I change is the center of the UIImageview:
[imageView1 setCenter:CGPointMake(x-16, 240)];
and the center gets updated but the position of the image on the screen stays the same.
after the center update, this gets called:
[self.imageView1 performSelectorOnMainThread:#selector(setImage:) withObject:testImage waitUntilDone:YES];
The funny thing is that in the first iteration it actually updates the position. But only the first time.
Any ideas?

Try:
imageView1.center = CGPointMake(imageView1.center.x-16, 240);

The accepted answer in this post (UIImageView not responding to centering) suggests that the problem is autolayout, which makes sense.
This post (Can I disable autolayout for a specific subview at runtime?) explains how to disable autolayout for specific elements.
Another answer suggest you add constraints (for x and y), create IBOutlets for these constrataints and update those to move the UI-element.

Related

Is it good choice to move a Sublayer around a view using UIPanGestureRecognizer?

I have a CALayer and as sublayer to this CALayer i have added an imageLayer which contains an image of resolution 276x183.
I added a UIPanGestureRecognizer to the main view and calculation the coordinates of the CALayer as follows:
- (void)panned:(UIPanGestureRecognizer *)sender{
subLayer.frame=CGRectMake([sender locationInView:self.view].x-138, [sender locationInView:self.view].y-92, 276, 183);
}
in viedDidLoad i have:
subLayer.backgroundColor=[UIColor whiteColor].CGColor;
subLayer.frame=CGRectMake(22, 33, 276, 183);
imageLayer.contents=(id)[UIImage imageNamed:#"A.jpg"].CGImage;
imageLayer.frame=subLayer.bounds;
imageLayer.masksToBounds=YES;
imageLayer.cornerRadius=15.0;
subLayer.shadowColor=[UIColor blackColor].CGColor;
subLayer.cornerRadius=15.0;
subLayer.shadowOpacity=0.8;
subLayer.shadowOffset=CGSizeMake(0, 3);
[subLayer addSublayer:imageLayer];
[self.view.layer addSublayer:subLayer];
It is giving desired output but a bit slow in the simulator. I have not yet tested it in Device. so my question is - Is it OK to move a CALayer containing an image??
Yes, it is OK to move a CALayer containing an image.
If all you want to do with the panning gesture is move the image, then instead of updating the whole frame, you should just update the layer's position property. Like thus:
- (void)panned:(UIPanGestureRecognizer *)sender {
subLayer.position=CGPointMake([sender locationInView:self.view].x, [sender locationInView:self.view].y);
}
Two things:
First, you can't draw ANY conclusions based on the performance of the simulator. Some things on the simulator are an order of magnitude faster than on a device, and other things are significantly slower. Animation is especially a mixed bag.
If you're doing performance-critical work, test it on the device, early and often.
Second, you can certainly animate a layer using a gesture recognizer, but that is an awfully round-about way to do it. Gesture recognizers are designed to work on views, and it's much easier and cleaner to tie the recognizer to a subview rather than a sub layer.
One of the big problems you will have with using a layer is hit-testing. If you let go of your image, then try to drag it some more, you'll have to have the gesture on the containing view, take the gesture coordinates and do hit testing on the layer. Ugh.
Take a look at the gesture based version of the touches sample app from Apple. It shows you how to cleanly move UIView objects around the screen using gestures.
Note that you can create a view that has custom layer content, and drag that around.

CA animation of a UIView inside a UITableView. Like the one on iTunes

I've been checking this site for many of my questions before but this is the first time I actually have to ask someting, so I hope I can make myself clear enough.
I have an App which is nearly finish. The main functionallity is in up and running. I'm only concern in making the whole App visually appealing. The App is maninly a database wich scientifical relevant data. I want the user to be able to store custom data in the DB and to do that I've created a "contact-like" view where the user can save some data. The view contains a table and inside this table, the cell have UITextFields. After entering the data, when the user presses a button, I want to animate the content of the textField to a cabinet-like icon. Very much like when you purchase something in the iTunes on a iOS device.
I've been able to do that animation in a "static" view (not a UITableView), playing around with starting point, end point and so on is a bit of a pain in the neck, but doable after all.
I'm doing the animation in a not really conventional way, I think, but actually very effecive. On the press of the button I create a UILabel, I set the text as the text of the textField and then I use viewAnimationWithDuration block to animate the label. Inside the block I also use Core Animation to animate the layer of the label over a path. Again, not conventional, but straight forward.
The problem I'm having is that I'm not able to create the label over the textField since it is in a UITableView. Mainly the problem is to know the position (or frame, or bounds, or position. I'm really confused already) of the textField and hence, the starting position of the path.
The code I'm using is as follows:
-(IBAction)saveCustom:(id)sender{
UILabel *imageViewForAnimation = [[UILabel alloc] initWithFrame:CGRectMake(l1, l2, l3, l4)];
imageViewForAnimation.text=label.text;
imageViewForAnimation.alpha = 1.0f;
imageViewForAnimation.backgroundColor=[UIColor clearColor];
imageViewForAnimation.textColor=[UIColor blackColor];
imageViewForAnimation.adjustsFontSizeToFitWidth=YES;
[self.view addSubview:imageViewForAnimation];
[UIView animateWithDuration:10.0
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
// Set up path movement Core Animation begins
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
CGPoint endPoint = CGPointMake(310, 380); // final point
CGMutablePathRef curvedPath = CGPathCreateMutable();
CGPoint rootViewPoint = [imageViewForAnimation convertPoint:imageViewForAnimation.center toView:taula];
CGPathMoveToPoint(curvedPath, NULL, rootViewPoint.x, rootViewPoint.y); // initial point
CGPathAddCurveToPoint(curvedPath, NULL, 100, 100, 100, 100, endPoint.x, endPoint.y);
pathAnimation.path = curvedPath;
CGPathRelease(curvedPath);
pathAnimation.fillMode=kCAFillModeForwards;
pathAnimation.removedOnCompletion=NO;
pathAnimation.duration=10.0f;
pathAnimation.delegate=self;
[imageViewForAnimation.layer addAnimation:pathAnimation forKey:#"savingAnimation"];
[imageViewForAnimation release];
//Core Animation ends
imageViewForAnimation.transform=CGAffineTransformMakeScale(0.60, 0.60);
// imageViewForAnimation.alpha=0.2;
}
completion:^(BOOL finished){
[imageViewForAnimation removeFromSuperview];
} ];
}
Any help on how to proceed will be much appreciated.
Thanks in advance!
UPDATE:
I went to the Apple Tech Talks in Berlin. In the labs they got, I asked an engineer about that. He wondered that the code I showed him didn't work. I emailed to him and he'll be back to me.
The key thing is to transform the coordinates from the table, to the view.
A UITableView shows a number of UITableViewCells. If you want to customize the controls displayed in a cell, you can add additional controls to the contentView of a UITableViewCell. Depending on how complicated your needs are, you would do this in the UITableViewDelegate or by subclassing UITableViewCell. Just be aware that adding subviews to contentView will likely interfere with the built-on controls (e.g. textLabel or detailTextLabel).
To position your additional controls or animation effects, you can check the bounds of the cell's contentView. Add your controls as subviews of contentView, animate them, and don't forget to remove them when you no longer need them.
Seems pretty conventional animation to me. And yes, effective.
As to a solution, you just need to save some state info when the user requests a save. And draw your animation label on top of the table. Should be no major problems there as long as you have a view available, super view of the table maybe?
Beyond that, how is your UI setup with respect to this table? How is the save custom activated (does the save all data or a specific field, do you have selected cell which you can access to pull the needed origin of your animation data)?
Also, don't forgot to release your UILabel after you add it as a subview, you are leaking it in the code above.

Changing frame of UIView's CALayer (self.view.layer.frame = ...) appears to have no effect

I'm sure I'm missing something basic here. I'm trying out the CALayers 'hello world' code from:
http://www.raywenderlich.com/2502/introduction-to-calayers-tutorial
Doing the very first example. New single view project in xcode 4.2. No change to the nib/storyboard. Import QuartzCore. Add the following code to ViewDidLoad in the ViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.layer.backgroundColor = [UIColor blueColor].CGColor;
self.view.layer.cornerRadius = 30.0;
self.view.layer.frame = CGRectMake(20, 20, 20, 20);
}
I run this (ipad 2 or ipad simulator) and get a full screen blue rectangle with rounded corners. What I hoped to get was a 20x20 blue rectangle offset by 20/20.
I'm clearly getting control over the views layer (as shown by the color and rounded corners). However, adjusting the frame seems to have no impact. I've NSLog'ed the frame before/after setting it, and it has changed. Is the frame of the root layer locked to the uiview frame?
I don't have a strong reason to change the views layers frame, I'm just trying to reason through what is going on. Hopefully this is an easy question...
Thanks!
Paul
Actually, the previous answer (you can't set uiview.layer.frame as it always fills the uiview) is close, but not quite complete. After reading the answer, I registered for the original site and to comment that the tutorial had issues. In doing so, I found that there were already comments that I hadn't seen in my first pass that addressed this. Using those, I started doing some testing.
The bottom line, if you move the self.view.layer.frame setting code from viewDidLoad to viewWillAppear, it works fine. That means that you can change the frame of the root layer of a view. However, if you do it in viewDidLoad it will be undone later.
However, the previous answer is still pretty close. I NSLog'ed the frame of the root layer and the frame of the view. Changing the root layer frame changes the view frame. So, the answer that the view.layer.frame always fills the view.frame is correct. However, setting the layer frame resets the view frame to match. (I'm guessing that uiview.frame property simply returns uiview.layer.frame...)
So, at some point in time between 2010 and today, something in the environment changed. Specifically, after viewDidLoad and before viewWillAppear the uiview/layer frame appears to be reset to the nib specified value. This overrides any changes in viewDidLoad. Changes made in viewWillAppear appear to stick.
Robin's answer got me on the right track, but I wanted to spell out the full answer.
The tutorial is wrong. Setting the frame of the view's main layer has no effect. The main layer is 'special' and will always fill the view's bounds. What you need to do is create a sublayer of the main layer like this:
- (void)viewDidLoad
{
[super viewDidLoad];
CALayer *newLayer = [[CALayer alloc] init];
newLayer.backgroundColor = [UIColor orangeColor].CGColor;
newLayer.cornerRadius = 20.0;
newLayer.frame = CGRectMake(100.0f, 100.0f, 200.0f, 200.0f);
[self.view.layer addSublayer:newLayer];
[newLayer release]; // Assuming you're not using ARC
}
Also, in your code a layer with width 20pt and height 20pt is too small to have rounded corners of 30pt anyway.

How do I use CGRectMake to size the background

Ok So I have this code, which allows me to put a background image in:
I would love to know how to size this, so on the iPhone 4 I can get a 320x480 size but make it nice with an image of 570.855.
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background_stream-570x855.jpg"]];
I have tried this:
UIImageView *image = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:#"background_stream-570x855.jpg"]];
[self.view sendSubviewToBack:streamBG];
image.frame = CGRectMake(0, 0, 320, 480);
Which works, however the problem is it's behind the view, so I can't see it. I could make the view clear, but it has objects on it that need to be displayed.
Any help would be most apretiated
There are multiple options to put Views at desired location.
[self.view sendSubviewToBack:streamBG]; //Sends subview to last position i.e. at the last
[self.view bringSubviewToFront:streamBG] //Brings subview to first position i.e. at the first.
[self.view insertSubview:streamBG atIndex:yourDesiredIndex];//Put at desired index.
This is not answer to your question, though it may help you to set your imageview to desired location.
Hope it helps.
To answer part of your question about sizing. You need to use 2 different images for your app if you want the full resolution of the retina display (iPhone4) You should provide a 320x480 image (i.e. myImage.png) for older iPhones and one at twice the resolution, 640x960, for the iPhone 4. Use the exact same name for the high res version but add an "#2x" to the end (i.e. myImage#2x.png). In your code all you ever have to call is the base name (i.e. myImage.png) the app will choose the correct image based on the hardware its running on. That will get you the best experience on your app.
On the other part about the background view visibility, you could make the background color clear ([UIColor clearColor]) on the view that is blocking it. That would leave the content visible in that view but the view its self would be clear. Alternatively you could just insert the background at a specific index as #Jennis has suggested instead of forcing it to the back.

How to determine image coordinates for a large cropped image within a UIImageView?

With regards to the iPhone SDK:
I have a 512 x 512 pixel .png image, and I want to display it within a 200 x 200 pixel UIImageView WITH cropping (at native resolution, without zooming, fitting, or rotation). Is there a way to determine the image's coordinates that are visible inside the UIImageView?
For example, if the image in the exact center of the UIImageView, then I want to know what the coordinates of the image are at UIImageView's (0,0) and (200,200) points, which will be (156,156) and (356,356), respectively for the image being displayed.
I plan on implementing "pan" and "zoom" functions at some point, but I want to know how to address this issue first. The UIImageView class reference did not seem helpful... I was hoping to avoid using a UIView, but if that is necessary I will go that route.
Thanks!
You're right about what you've seen from the UIImageView reference - there is no easy way to do that using UIImageView alone. You would need to take into account things like the contentMode of the UIImageView or limit yourself to only calculating the position for a single UIViewContentMode.
However, when you eventually get to implementing pan and zoom, you'll be using a UIScrollView with a UIImageView as a subview of that UIScrollView. At that point, it would be most sane to size your UIImageView initially to the size of whatever image you're display (could be dynamic). You can then determine where the image is by determining where the image view is, which is something you can accomplish much more simply and with just a bit of math.
Thanks for your help. Working out the pan/zoom features became trivial after implementing the UIScrollView. Implementing the UIScrollView let me determine the coordinates I needed with the myScrollView.bounds.origin.x and myScrollView.bounds.origin.y values... zooming still requires calculation - as you stated above, but I am on the right track now.
here is the code I used to make the UIScrollView (based on multiple sources available on the net and this site - Apple's ScrollViewSuite was particularly helpful. Here is the code I used in the (void)viewDidLoad section of my program, hopefully others can find it useful:
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[imageArray objectAtIndex:0]]; //imageArray is an array/stack of images...
[self setMyImage:tempImageView]; //myImage is of type UIImageView
[myImage setTag:100]; //set this to an 'arbitrary' value so that when I update the scrollview I can remove the current image...
[tempImageView release];
myScrollView.contentSize = CGSizeMake(myImage.frame.size.width, myImage.frame.size.height);
myScrollView.maximumZoomScale = 10.0;
myScrollView.minimumZoomScale = 0.15;
myScrollView.clipsToBounds = YES;
myScrollView.delegate = self;
[myScrollView addSubview:myImage];