Hi everyone I'm french so scuse me for my english. well what I want to do is to create every second a new image at a random position, but a random position outside the screen, and(very important) near of the screen sides(the upper side or left side or right or down). like that when I want to animate them, there will be created outside the screen but just around the sides. How can I do this please ?
So basically, my understanding about your question is that you one goal: You want to animate an object via translation.
So the animation goes from outside the visible screen to the viewable.
Here's an approach:
1. You need to determine what are the limits of your "Outside" screen. Depending on the size of your UIImageView frame, 100 px padding is fine I think. So that would be x: (-100, 420), y: (-100, 580).
Generate random number. arc4random() is better than rand() in this case.
Create a method that will be called by an NSTimer in which the UIImageView's are created.
Don't forget to properly manage your UIImageView's. Frequent creating objects without releasing will cause your app to crash. If possible, reuse them instead of creating them each time the method is called.
What this code does is use random:min:max to generate a random x and y value between the desired min and max range. In the onTimer function we allocate a new UIImageView object and then set its center property to be a random location off the screen. If the generated random number inside the if statment is less than 5 then the view will be added to either to the left or top of the screen, otherwise it will be added to the right or bottom.
/*****************************************************************************
Generates a pseudo random CGPoint point value within the min and max range.
*****************************************************************************/
-(CGFloat)rand:(CGFloat)min:(CGFloat)max{
float difference = max - min;
return (((CGFloat) rand()/(CGFloat)RAND_MAX) * difference) + min;
}
-(void)viewDidLoad{
//setup a timer property in your view controller header file
timer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:#selector(onTimer)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}
-(void)onTimer{
UIImagView *myRandomImageView;
myRandomImageView = [[UIImageView alloc] initWithImage:#"MyRandomImage.png"];
if([rand:1:10] > 5)
//put the image view to top or left side of the screen
myRandomImageView.center = CGPointMake([rand:-100,-200], [rand:-100,-200]);
else
//put the image view to the bottom or right side of the screen
myRandomImageView.center = CGPointMake([rand:420,520], [rand:580,680]);
//dont forget that the values I have eneter here to be passed to the rand:min:max
//function are meant to serve as a guide and that you should enter your own values to
//achieve the desired random view positioning off screen.
[self.view addSubview:myRandomImageView];
[myRandomImageView release]
}
Related
I am new in iOS developement.When I press the stopwatch start button I want to display the timer like counter token effect.I have attached image for your reference.I have done to display secs and minutes but I dont know, How animate autoscroll effect? How can I do this?
When the counter is moving it shouldn't jump from one number to another number, instead it should move from one number to next number smoothly, just like the petrol pump meter. Thanks
I have done something like this before - this code is not necessarily clean, but it does the job.
You want to create twoUILabels in your .h file:
IBOutlet UILabel *figureLabel1;
IBOutlet UILabel *figureLabel2;
Then you want to create a BOOL so that we can tell which UILabel is visible to the user.
BOOL firstLabel;
So lets imagine that the initial label (showing the number 1) is figureLabel1 and the future UILabel to be displayed (showing the number 2) is figureLabel2. However when the counter adds one, then the figureLabel2 moves up and takes the figureLabel1's place. Then, while the figureLabel1 is hidden, it takes the place of figureLabel2 when figureLabel1 was visible.
See here:
// Check what label is showing
if (firstLabel == YES) {
// Following code the hide and move the figureLabel1
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate: self]; //or some other object that has necessary method
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
// Slowing fade out the figureLabel1
[figureLabel1 setAlpha:0];
// Move the figureLabel1 up and out of the way
[figureLabel1 setFrame:CGRectMake(20, 108, 287, 55)];
[UIView commitAnimations];
// Following code the show and move the figureLabel2
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
// Slowing fade in the figureLabel2
[figureLabel2 setAlpha:1];
// Move the figureLabel2 up and into position
[figureLabel2 setFrame:CGRectMake(20, 141, 287, 55)];
[UIView commitAnimations];
// Update BOOL for next label
firstLabel = NO;
} else {
// Exactly the same but opposite
}
As I said, this is not pretty but it shows the basic concept. All the best!
You need to manually scroll tableView instead of scrollToRowAtIndexPath because this animation uses its own timer interval and its very difficult or we can say impossible to change its time interval.
So, I am Implementing an API for such kind of problems and made a demo app for you with smooth scrolling as you want.
You need to use an outer timer that fires every 1 second and an internal timer that will fire every 0.03 sec as my tableRow Height is 30 I calculated internal timer interval as :---
Move 30 pixels for 1 sec , then
Move 1 pixel for 0.33 sec inside internal timer.
The Internal timer will invalidate and fire every 1 second as initialized within outer timer.
And internal timer will perform the movement of cell.
dial4 is a tableView
Have a look at my code.
#define rowHeight 30
-(void)startCounter
{
outertimer=[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(snapCell) userInfo:nil repeats:YES];
}
-(void)stopCounter
{
[outertimer invalidate];
}
-(void)snapCell
{
NSLog(#"Initialize Internal timer %i",secLsb);
secLsb++;
if (secLsb==10) {
[dial4 setContentOffset:CGPointMake(0, 0) animated:NO];
secLsb=0;
NSLog(#"dial content offset y is %f",dial4.contentOffset.y);
}
[internaltimer invalidate];
internaltimer=[NSTimer scheduledTimerWithTimeInterval:0.03
target:self
selector:#selector(automaticScroll)
userInfo:nil
repeats:YES];
}
-(void)automaticScroll
{
NSLog(#"val is & y ======== %f",dial4.contentOffset.y);
[dial4 setContentOffset:CGPointMake(dial4.contentOffset.x,dial4.contentOffset.y+1) animated:NO];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return rowHeight;
}
Have a look at Time Counter
From image it can be assume that you are trying to get an effect like count-down timer. Have a look at countdown timer here. It may helps you somehow.
Enjoy Programming !!
Refer both links for your output. It helps you
UIPickerView that looks like UIDatePicker but with seconds
and
How can I make my UIPickerView show labels after the selected value?
Thanks.
Several good ideas here so far, but I'll add another.
First, be sure to set the container view (your blue rectangle) to clip children, using the Clip Subviews checkbox in Interface Builder.
Second, add a set of child views with images of each numeral for each digit to be presented (4 * 10 = 40 child views in your case). Use tags in IB so you can easily access each one. Set the initial bounds to just below your bottom margin.
Call UIView animateWithDuration. In the animations block, set the new digit view's frame to appear in the clipped parent view's bounds, and set the old digit view's frame to just above the container's bounds. Since both view's frame changes are animated in the same block, this will create the effect of the new digit sliding up into place as the old digit slides out the top.
In the completion block, set the old digit's frame back to the original position below the container view.
With this approach, you can play with the duration and the timing curves, so that you cam emulate the pause that occurs with each digit fully displayed between transitions.
A similar approach can also be used with CALayer, or with sprites, but UIViews are lightweight, perform well, and easiest to assemble in Interface Builder.
I am using a UIToolbar in iOS and am trying to get a new button to 'arrive' by sliding in from the right. Is there a way to directly access the 'position' of the button on the bar? I currently have a messy workaround that is getting close to the desired effect, but i was hoping there was a way to move them using Core Animation, so i could implement the 'EaseInEaseOut' type timing functions. Any ideas?
- (void) testPart1 {
[NSTimer scheduledTimerWithTimeInterval:(0) target:self selector:#selector(testPart2:) userInfo:[NSNumber numberWithInt:500] repeats:NO];
}
- (void) testPart2:(NSTimer*)sender {
int countdown = [sender.userInfo integerValue];
theSpace.width = 10+(int)countdown;
itemTestButton.width = 49;
itemTestButton.width = 50;
countdown -= 5;
if(countdown>0)
[NSTimer scheduledTimerWithTimeInterval:(0.004) target:self selector:#selector(testPart2:) userInfo:[NSNumber numberWithInt:countdown] repeats:NO];
}
The premise here was using an NSTimer to change the width of a Fixed Space Bar Button item, and count down to zero. I found I had to change the width of an actual button to make it work, otherwise no 'animation' would occur. It's messy I know, someone must have a cleaner way.
I would suggest adding a plain UIView as a subview of the UIToolbar that is rendered exactly as the bar button would be (you could get this by calling renderInContext: on an existing button) and then animate that view into the proper position. In the completion block of that animation you could then set the real button and removeFromSuperview the animation view, and it will look indistinguishable to the user.
Is it possible to create two button shown as below image? It may seem like you should use UIButton or UIImageView but if i click to area 1, it stills acts as clicked to button 1. Button 2 should be fired when I click to the area 1 as well!
Failing the above responses being acceptable, you could implement a custom subclass of UIButton that overrides pointInside:withEvent:.
Assuming your view is exactly square and the graphic exactly circular and filling the entire square, an example might be:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
// check that the point is at least inside the normal rect
if(![super pointInside:point withEvent:event]) return NO;
// we'll assume a square view with an exact circle inside, so
// the radius of the circle is just half the width
CGFloat radius = self.bounds.size.width*0.5f;
// the point (radius, radius) is also the centre of the view, so...
CGFloat squareOfDistanceFromCentre =
(radius - point.x)*(radius - point.x) +
(radius - point.y)*(radius - point.y);
// if the point is too far away, return NO
if(squareOfDistanceFromCentre > radius*radius) return NO;
// otherwise we've exhausted possible reasons for answering NO
return YES;
}
You can make circular button by cutting the layer and set radius of you button.
[[button layer] setCornerRadius:8.0f];
you can also try with change radius.
Yes, of course is possible.
You can connect a single action with more than one selector through IB.
You can also call directly the method fired by button2 from inside the method fired by button1.
It quite tricky, but possible:
You can use only one button, but put some verification after event touchUpInside. You should calculate if this touch point are inside the circle of "button1". For this task you need to have some mathematic knowledge - How do I calculate a point on a circle’s circumference?
Set userInteractionEnabled to NO for the smaller Button 1. All events will go to the larger Button 2.
I have created two round rect buttons for this purpose, one of them is long and thin, and the other one is more wide. Together they build a shape like a chubby plus sign, which is pretty close to a circle, considering apple accepts 44 px as the minimum confortably pressable size. If you want the image to change, set another image to its imageView for highlighted state and connect several actions (touchup wont be sufficient if you want to immitate buttons highlighted state on the image view)of the two buttons. Alternatively you can add observers and alter highlighted state of the imageview according to the buttons
A clean way to deal with pointInside on a circular button is this:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
if (![super pointInside:point withEvent:event])
{
return NO;
}
BOOL isInside = (pow((point.x-self.frame.size.width/2), 2) + pow((point.y - self.frame.size.height/2), 2) < pow((self.frame.size.width/2), 2)) ? YES:NO;
return isInside;
}
You can ditch the 'isInside' variabe, but this way is easier to test.
Is it possible to pan a UIImageView and when it intersects with the frame of another UIImageView, have that other UIImageView be pushed around by the other UIImageView without just passing over it? I hope that makes sense!
If it is possible, could you give me some ideas on how I'd go about implementing this?
I imagine it would go something like...
If frame intersects frame from left or right on the x/y axis, have the other frame move in that same direction with same distance as the pushing frame. While that logic somewhat makes sense to me, I'm not sure how I'd implement that in code.
I'd really appreciate any advice you can offer.
So, you're only concerned with left / right panning...
Let's assume you have 2 UIImageViews, a & b, as subviews of some other UIView and defined as class members of some class.
You can get help detecting panning gestures (dragging touches) on each of these views by creating instances of UIPanGestureRecognizer and adding them to each UIImageView using method addGestureRecognizer:
When creating each UIPanGestureRecognizer, you need to designate a selector to receive the gesture events. Let say it's called didMove:
Now, some sample code:
- (void) didMove:(UIPanGestureRecognizer*)recognizer {
UIView* view = [recognizer view];
// Remember our UIImageViews are class members called, a & b
//
UIView* otherView = view == a ? b : a;
if (recognizer.state == UIGestureRecognizerStateBegin
|| recognizer.state == UIGestureRecognizerStateChanged) {
// Moving left will have a negative x, moving right positive
//
CGPoint translation = [recognizer translationInView:view.superview];
view.center = CGPointMake(view.center.x + translation.x, view.center.y);
// Reset so we always track the translation from the current view position
//
[recognizer setTranslation:CGPointZero inView:view.superview];
if (CGRectIntersectsRect(view.frame, otherView.frame)) {
// Translate by the same number of points to keep views in sync
//
otherView.center = CGPointMake(otherView.center.x + translation.x, otherView.center.y);
}
}
}
It may not be exactly what you need, but it should give you a good idea how it could be done.
Sounds like you'd better use something like Cocos2D with it's sprites, intersections and some basic physics...
You can do it like this,
First, Create an UIImageView and assign an UIImage to it.
Second, When the user swipes or makes any gesture just change the coordinates of the card by setting its frame again.
Since u want the card to slide away, you have to change the x coordinate to a negative value such that it slides off from the view.
The above said code of reframing the imageview should be given within a UIView setAnimation group of methods...with a required delay.
To achieve the push effect have a method called within the the same animation block of codes which creates a new imageview (having same name as that of first imageview) and keep it out of the view. That is beyond the width of the screen. (dont forget to release the card which was pushes away previously)
Then subsequently again make a new frame for this imageview such that it appears in the centre of the screen....When above three steps of code are put within the animation block of code for UIView or UIImageView with a delay time , u will achieve the required effect.
Hope this helps....
happy coding....
Hi everyone I'm french so scuse me for my english.My problem is the following: I have an image in the center of the screen called viewToRotate, then I have an image called flakeView that is created outside of the screen and then it is moving to the center, and every second a Timer does this(create a flakeView outside the screen and then move it to the center of the screen).
What I wanted to do was : if flakeView and viewToRotate collide reduce the alpha of viewToRotate to 0.5. But when flakeView appears on the screen the action of reducing the alpha is called without the collision of viewToRotate and flakeView, so they collide before they touches. I don't know why. How can I solve this please . Here is the code :
UIImageView* flakeView = [[[UIImageView alloc] initWithImage:flakeImage] autorelease];
// use the random() function to randomize up our flake attributes
int startY = round(random() % 320);
// set the flake start position
flakeView.center = CGPointMake(490, startY);
flakeView.alpha = 1;
// put the flake in our main view
[self.view addSubview:flakeView];
[UIView animateWithDuration:7
animations:^{
// set the postion where flake will move to
flakeView.center = viewToRotate.center;
}];
}
-(void)checkCollision{
if(CGRectIntersectsRect(flakeView.frame, viewToRotate.frame) == 1)
{
viewToRotate.alpha=0.5;
}
}
I would not suggest using a timer on viewDidLoad. I believe that you should set the timer at some other function. Even if you do not use viewDidLoad for anything else.
The other thing is the UIView animations. Even if you have a timer at every 60fps the attributes of the animated objects are not changed by the animation. So before you create the animation you set those properties once. And when you create the animation you set the same properties for the second time. And that's it. From now on while the animation is running if you do checks on the properties you will always get the second values.
To have a working code one option is to create the UIView animations (and perform the property checks) for every step at a certain time interval. Or use OpenGL.
Before getting too deep into this issue, please also make sure that your viewToRotate.frame is actually sized the way you expect it (see my comment).
Once you are certain about those attributes, you might want to check the collision on the current presentationLayer of your animated objects and not on their original state.
UIView.layer.presentationLayer
Returns a copy of
the layer containing all properties as
they were at the start of the current
transaction, with any active
animations applied.
So you might adapt your collision detection like this:
-(void)checkCollision
{
if(CGRectIntersectsRect(flakeView.layer.presentationLayer.frame, viewToRotate.layer.presentationLayer.frame) == 1)
{
viewToRotate.alpha=0.5;
}
}
Also consider using the CoreAnimation Layer method hitTest: instead of your handmade collision detection.
hitTest: Returns the farthest
descendant of the receiver in the
layer hierarchy (including itself)
that contains a specified point.
These are the following things you would want to check.
Dont init with image, use init with frame and then do
flakeView.image = ----; Because your image could be wide enough
initially , and hence colliding from the time you initialize.
Try alternatives to .center, like .frame.size.x , because I have had
problems with .center as well
You could probably NSLog the bounds of both ur imageviews before and
after reducing alpha