I try to rotate and move a UIImage.
Here is my code :
im = [[UIImageView alloc ] initWithFrame:CGRectMake(160, 240, 100, 100)];
im.image = [UIImage imageNamed:#"image.png"];
[view addSubview:im];
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1.0/30.0 target:self selector:#selector(actionIm) userInfo:nil repeats:YES];
-(void) actionIm
{
[im setFrame:CGRectMake(im.frame.origin.x+1 , im.frame.origin.y+1 ,100, 100)];
im.transform=CGAffineTransformMakeRotation (mRotation);
mRotation+=0.1;
}
The result is a very strange behaviour : If I use only the rotation, it works. If I use only the move, it works. But both uses give a strange result (the IUImage "jump" bizzarly).
I red a lot of things about rotation, frame, bounds, center... but nothing that can solve my problem.
Thank you.
Try moving the center instead of changing the frame. I believe setting the frame when the rotation is not Identity does something different.
Related
What I mean by this is, if I have a UILabel that I created, how can I make it change periodically within the view of the screen to a random point? Would I use something like arc4random, or something like a random CGPointMake?
I would have it change every second or so using something like this
Text = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(RandomText) userInfo:nil repeats:YES] ;
but i'm just not sure how to get it to "spawn" in a random place, if possible, and then to remove the other one.
A simpler version would also be, If I just made say, 4 different UILabels, how could I make it appear randomly on one of the 4, and then remove after the time interval? I assume I could use something like
int randomNumber = rand() % 4;
and then put a switch in there, but i'm not sure if that would be the correct way to do it either.
Do you have a single label that you want to move to different points on the screen? Or are you adding multiple labels?
Are you using auto-layout or not? (If you're using auto-layout then you can't just move the label around - instead you need to modify it's position constraints. That gets a little more complicated.)
As to how to move it around, I would suggest using arc4random_uniform to calculate a new location for the label's center.
You could put code like the following into your timer method. In the code below, "view" is the view that contains your label.
The code below keeps the label fully visible on-screen by moving the center no closer to the edges of it's parent view than half the label's width&height.
CGFloat newX = arc4random_uniform(view.bounds.width - label.bounds.width) +
label.bounds.width/2;
CGFloat newY = arc4random_uniform(view.bounds.height - label.bounds.height) + label.bounds.height/2;
label.center = CGPointMake(newX, newY);
If you want the label to move to it's new location in an animation you could use the UIView method animateWithDuration:animations to change the center point in an animation block.
Again, if you're using AutoLayout, you'll need to attach center X and center Y constraints as outlets, and change their value settings to move the label.
Interesting. Maybe this helps. This is just a prototype; by no way a production code. Hope this helps. Consider label,screenHeight and screenWidth as instance level variables.
- (void)viewDidLoad
{
[super viewDidLoad];
label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 20, 20)];
label.backgroundColor = [UIColor blackColor];
[self.view addSubview:label];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:#selector(createRandomPoint:)
userInfo:nil
repeats:YES];
screenHeight = [UIScreen mainScreen].bounds.size.height;
screenWidth = [UIScreen mainScreen].bounds.size.width;
}
-(void) createRandomPoint:(id)sender {
int randX = arc4random() % screenWidth;
int randY = arc4random() % screenHeight;
label.center = CGPointMake(randX, randY);
}
I have a custom view (a small indicator derived from UIView with a rotation animation) which has basically a heart icon (UIImageView) on middle and a few balls (another UIImageView) rotating around it using layer animation. Here is my code:
-(void)performInitialization{
self.backgroundColor = [UIColor clearColor];
CGRect frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
[imageView setImage:[UIImage imageNamed:#"RedHeart"]];
balls = [[UIImageView alloc] initWithFrame:frame];
[balls setImage:[UIImage imageNamed:#"AngularBalls"]];
[self addSubview:imageView];
[self addSubview:balls];
[balls.layer beginRotating];
}
...where my category on CALayer has:
-(void)beginRotatingWithAngularVelocity:(float)velocity{
CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
rotationAnimation.fillMode = kCAFillModeForwards;
rotationAnimation.removedOnCompletion = YES;
rotationAnimation.repeatCount = 999999;
rotationAnimation.duration = velocity;
rotationAnimation.cumulative = YES;
rotationAnimation.fromValue = [NSNumber numberWithFloat:0];
rotationAnimation.toValue = [NSNumber numberWithFloat:M_PI * 2];
[self addAnimation:rotationAnimation forKey:ROTATION_KEY];
}
-(void)beginRotating{
[self beginRotatingWithAngularVelocity:0.7];
}
performInitialization is called in the init[WithFrame|WithCoder] method of my view. I have one of these views in my storyboard's main view and the view animates perfectly. If I put several instances of my custom view into that main view, they all animate perfectly too. There is no problem if I put my view into any view on that storyboard. However, when I put that same view into a view from a nib, it won't animate. The same code, the same settings in IB (copy pasted to make sure everything is the same), but the view is still, stuck on the initial view as if there was no animation attached to the layer). Why would that happen? How can I make that animation work on nibs?
UPDATE: The problem appears to be related to having the animation on view's initializer. In some occasions, I am animating right inside initialization, but sometimes, after it is loaded (e.g. user clicked something and something is downloading). The problem appears to be consistent with the former case. My previous fallacy about being about storyboard vs. nibs apparently is just coincidence. I've updated the title accordingly.
Initialization is too early. You need to wait until the view is in your interface (signaled to the view by didMoveToWindow. Until then, the view is not part of the rendering tree (which is what does the drawing/animation of its layers).
I'm adding a background effect to my app by rotating an UIImageView using:
- (void) viewDidLoad {
rotateAngle = 0;
[NSTimer scheduledTimerWithTimeInterval:.05 target:self selector:#selector(bgEffect) userInfo:nil repeats:YES];
}
- (void) bgEffect{
rotateAngle += .01;
CGAffineTransform rotate = CGAffineTransformMakeRotation( rotateAngle );
[_bgImage setTransform:rotate];
}
The weird problem with that is it affects some of my UI elements by shifting them. It doesn't affect all UI elements, just some. I tried to change the hierarchy, but no luck. I don't understand what the problem is. Can someone help me?
Try turning off Auto-Layout in your Storyboard.
I'm new to iOS programming and i've got a question:
I want to make a kind of custom progress bar. I've created 2 UIViews, one above the other and animated the front UIView with this code:
[UIView animateWithDuration:1.5f delay:1.0f options:UIViewAnimationOptionCurveEaseInOut animations:^{
[barCima setFrame:CGRectMake(10, 300, value, 30)];
}
completion:nil];
But now, I would like to do something more. I want that while the width bar is growing, a UILabel appears with the current value. Example: I set de value to 300. While the animation is occurring, the UILabel is showing the progress until it reaches the 300 (1, 2, 3, 4, 5, 6, 7,...,300).
You need an NSTimer that fires every one second or so, and a counter. Whenever the NSTimer fires, the counter is incremented, and UILabel's text will be updated. It should look like this
int _counter; // An instance var
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerFired) userInfo:nil repeats: YES];
// Be sure you call [self.timer invalidate] when you don't need it anymore
...
-(void)timerFired {
++ _counter;
self.label.text = [NSString stringWithFormat:#"%i", _counter];
}
Good luck thought I don't know what you use such a progress bar for!
I am making a driving game for the iOS, where a car (UIView) is put on top of the google maps ios api. I am having trouble detecting collisions with the car and the grey buildings that appear on the map.
I have been trying to do it by pixel color i.e. checking if the pixel color, just ahead of the car, is the color of a buildings roof (grey). There is no direct access to an iPhones pixel color, so I am using the google maps screenshot method to get an image and get the pixel color from that. The problem is, is that I can only take a screen shot of the screen I just left. I am using
mapImage = [GMSScreenshot screenshotOfMainScreen];. I have also tried getting the window and screen and calling mapImage = [GMSScreenshot screenshotOfScreen:topWindow.screen]; Both have the same effect.
What is a solution to this problem? Can you think of a better way of handling collisions for this situation? Does reverse geocoding have the ability to detect the tops of buildings vs streets?
Thanks for any and all help!
EDIT:
Images:
Interface Builder: Left is the main menu, right is the game. The Ui image view in the upper left corner is set as the current screen shot image for referencing purposes. This how I knew It was off
Game Play, As you can see, it is only presenting the previous menu.
My viewdidLoad function: Not much other than this thats related to getting the image.
- (void)viewDidLoad
{
[super viewDidLoad];
cameraPosition = CLLocationCoordinate2DMake(42.271291, -83.729918);
moveDistance = .00055;
cA = [UIColor colorWithRed:.937255 green:.921569 blue:.886275 alpha:1];
camera = [GMSCameraPosition cameraWithLatitude:cameraPosition.latitude
longitude:cameraPosition.longitude
zoom:19
bearing:0
viewingAngle:0];
mapView_ = [GMSMapView mapWithFrame:CGRectMake(0, 0, 480, 300) camera:camera];
mapView_.myLocationEnabled = NO;
[self.view addSubview:mapView_];
car_ = [[Car alloc] initWithFrame:CGRectMake(240, 150, 13, 29) withImage:[UIImage imageNamed:#"carA-01.png"]];
[self.view addSubview:car_];
[self.view addSubview:controllerView];
updateClock = [NSTimer scheduledTimerWithTimeInterval:(1/20)
target:self
selector:#selector(update)
userInfo:nil
repeats:YES];
crashClock = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(checkCrash)
userInfo:nil
repeats:YES];
UIWindow *topWindow = [[UIApplication sharedApplication].windows objectAtIndex:0];
mapImage = [GMSScreenshot screenshotOfScreen:topWindow.screen];
// mapImage = [GMSScreenshot screenshotOfMainScreen];
}
Are you getting a new screenshot every frame (or on some interval), eg from your update callback?
The GMSMapView doesn't render immediately when you create or make changes to it - it renders later on its next update. Therefore when you take the screenshot in viewDidLoad you're probably getting what was on the screen at the time that the map view was added, ie the initial menu.