i have a scrolview with paging it's a scrol view for slide with 4 picture it's work fine with user interaction so my question i want to set this scrolview scrol automatique without user interaction so like a banner for pub this is my code in view didload :
[UIScrollView beginAnimations:nil context:nil];
[UIScrollView setAnimationDuration:4.0];
[UIScrollView setAnimationDelay:4.0];
[scroller setContentOffset:CGPointMake(320, 98)];
[UIScrollView commitAnimations ];
in this whay the scrol automatic work but the probleme the scrol wait 4 s and after go to the seconde image and is stop and if i add this code
[UIScrollView beginAnimations:nil context:nil];
[UIScrollView setAnimationDuration:4.0];
[UIScrollView setAnimationRepeatAutoreverses:YES];
[UIScrollView setAnimationRepeatCount:INFINITY];
[UIScrollView setAnimationDelay:4.0];
[scroller setContentOffset:CGPointMake(320, 98)];
[UIScrollView commitAnimations ];
the scroller don't stop 4s after showing the second picture so in this case it's stop at first 4s after if the annimation begin don't stop never
so my question i want to do this :
image 1 ---showing fo 4 s -----image2 ----showing for 4s ----- image3 ----showing for 4s ----image 4 ----showing for 4 s ----- image 1 ---- showing for 4 s ...... like this automatique
so if someone can help me with example code or tutorial or any documentation it's will be very cool because i search in google and i find anything
I've made an example in an earlier answer of mine:
UITableView scroll smooth with certain speed?
This example will be quite relevant for you if you can decypher the changes you need to make.
The following is what you need to do:
At the moment you want to start the animation (which is prolly at the start or selection on the page even) you need to start the timer. Then at a certain custom interval you can fire a method that sets the contentOffset a little further to the right (change Y-value appropriately). When you came at the end of the pages or when you ran the target method x-times (which is ezily stored in a property/global val) you can invalidate the timer.
Look at the question I posted and you will find every piece of the puzzle there.
You will figure it out.
Good luck.
create an NSTimer with an interval of 4 seconds.
let this be the fire method:
- (void)timerFireMethod {
horOffSet = horOffSet + 320;
//CGFloat horOffSet is an instance variable of the ViewController.
//init as 0; I assume the width is 320. Any other width possible
[scroller setContentOffset:CGPointMake(horOffSet, 98) animated: YES];
if (horOffSet == 3*320) {
horOffSet = 0;
}
}
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 just upgraded my iPhone 4 from iOS 4.2.1 to 4.3.2, and to XCode 4.0.2, and I am encountering some bizarre issues with uiview animations. When I first launch my app, code like this executes perfectly:
[UIView beginAnimations:#"fadeAlphaIn" context:nil];
[UIView setAnimationDuration:0.5f];
viewClue.alpha = 1.0f;
[UIView commitAnimations];
But then, after dismissing a presenting and then dismissing a modal view by the standard method:
[self presentModalViewController:more animated:YES];
and
[self dismissModalViewControllerAnimated:YES];
the first animation no longer works. Instead of fading in, for example, the viewClue view simply jumps from alpha = 0 to alpha = 1. Similarly, other animations altering other views' frame property just force the frame to jump from the initial to final value without animation. These animations worked fine before the modal view was presented and dismissed.
I understand that others have experienced animation issues with the upgrade to iOS 4.3.2, but the way the modal view disrupts animation seems very odd. Has anyone else experienced this problem? Any ideas as to a solution? I'm thinking of just adding the modal view as a subview and animation it as it hides and appears, but using the standard modal view method would be much preferred.
Thanks for your help,
James
EDIT: Some more code showing how the app's map is animated
-(void) viewMapfunc
{
AudioServicesPlaySystemSound(soundID);
if(mapvisible){
[UIView animateWithDuration:0.5
delay:0.1
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
map.frame = CGRectMake(0, 350, 320, 27);
mapscroll.frame = CGRectMake(0, 27, 320, 0);
}
completion:nil];
mapvisible = NO;
viewMapLabel.text = #"View Map";
}else {
[UIView animateWithDuration:0.5
delay:0.1
options:UIViewAnimationOptionAllowUserInteraction
animations:^{
map.frame = CGRectMake(0, 50, 320, 300);
mapscroll.frame = CGRectMake(0, 27, 320, 300);
}
completion:nil];
mapvisible = YES;
viewMapLabel.text = #"Hide Map";
}
}
Try to check two things:
Do you commit all started animations? I got all kinds of strange effects after not committing one of them.
Do any animations take place in the same time? Especially with the same view.
Whether any animations take place right after changing properties. Something like:
-
view.alpha = 1;
[UIView beginAnimations:…];
view.alpha = 0;
[UIView commitAnimations:…];
In this example, view will not change it's alpha value from 1 to 0. It will change it instantly. To start an animation you have to extract animations block to another method and call it with performSelectorInMainThread:withObject:afterDelay:. Delay can be even 0.
I solved it by restarting my animation in my UIView subclass:
override func willMove(toWindow newWindow: UIWindow?) {
if newWindow != nil {
spinner.startSpinning() // Restart any animation here
}
}
In the end, I just removed all modal views and implemented them in other ways. For some reason, using modal views messed up animations. Makes no sense, but removing them fixed the problem. If anyone can enlighten me as to why this is going on, it might be nice for memory concerns...
I had the same issue. The root of my trouble was that my animation was being triggered by a notification, and I was adding an observer on each viewWillAppear, but forgot to remove in viewDidDisappear (remember that iOS 6 no longer calls viewDidUnload reliably).
Essentially, I was calling my animation function twice in quick succession, which was causing the visible irregularity. Hopefully this helps someone out down the line!
I've managed to solve this same issue in my own application.
I noticed while debugging that my UIImageViews which I was animating had different memory addresses before and after I pushed my modal view controller(s). At no other time did these UIImageViews switch their memory addresses.
I thought this might have been the root of the issue and it seems I was right.
My client's code had been allocating/initializing my View Controller's UIImageViews in
-viewDidAppear instead of in -viewDidLoad. Thus, every time I launched and dismissed a modal view controller my UIImageViews I was animating would get reinitialized.
Check for yourself if your map object's memory address is changing before and after you launch your modals, and if it is be sure to move your initialization logic to a more proper section of your code.
Hope this helps you!
Dexter
I was using UIView animateWithDuration: and I solved it by not using the completion block. This is code from a subclassed UIView. In the view controller's viewWillAppear: I set self.shouldAnimate to YES, and in the view controller's viewWillDisappear: I set self.shouldAnimate to NO.
-(void)continueRotate {
if (self.shouldAnimate) {
[self rotateRadarView:self.radarInner];
}
}
-(void)rotateRadarView:(UIView *)view {
[UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(continueRotate)];
[view setTransform:CGAffineTransformRotate(view.transform, M_PI_2)];
}completion:nil];
}
I'm developing an app that would display images and change them according to the user's action. I've created a subclass of UIView to contain an image, an index number and an array of image names. The code is like this:
#interface CustomPic : UIView {
UIImageView *pic;
NSInteger index;
NSMutableArray *picNames; //<-- an array of NSString
}
And in the implementation part, it has a method to change the image using a dissolve effect.
- (void)nextPic {
index++;
if (index >= [picNames count]) {
index = 0;
}
UIImageView *temp = pic;
pic.image = [UIImage imageNamed:[picNames objectAtIndex:index]];
temp.alpha = 0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration:0.25];
pic.alpha = 0;
temp.alpha = 1;
[UIView commitAnimations];
}
In the viewController, there are several CustomPic which would change the images depends on users' choice. The images would change as expected with the fade in/out effect, but the animation performance is really bad. I've tested it on an iPhone 3G, the Instruments shows that the animation is only 2-3FPS! I tried many methods to simplify and modify the codes but with no hope. Is there something wrong in my code or in my concept? Thanks for any help.
P.S. all the images are 320*480 PNGs with a max size of 15KB.
In that code snippet you are only using one UIImageView:
UIImageView *temp = pic;
So this line does nothing:
pic.alpha = 0;
To fade one image in and another image out, you need two instances of UIImageView.
To speed things up, you might want to load the next image ahead of time. Set a delegate for the animation, and when it completes load the image that will be displayed in the next call of nextPic.
Edit:
If the images are not transparent, try setting the pic.opaque = YES; so the view can ignore underlying views. If that is not an option, try having as few views as possible between the fading view and a full screen opaque view. At each step of the fade, the view must be composited with every underlying view until an opaque view is found.
If you have many transparent views under the fade, consider making a temporary composite of them all, the equivalent of flatten layers in photoshop, and placing the composite as an image in a full screen opaque view before starting the fade. It may delay starting the fade a moment, but the fade itself should be smoother.
Are you running iPhone OS 4 beta? I find the beta OS much slower on the older generation devices like iphone 3g
Try change
[UIView setAnimationDuration:0.25];
to
[UIView setAnimationDuration:0.025];
and see if that's something you are looking for...
With an animation duration of .25 of a second, you can be guaranteed to get < 4 FPS. What FPS are you targeting?
I'm seeing what appears to be interaction between separate animations, and I'd really appreciate any suggestions to eliminate this effect.
Basically:
I've got an iPhone app which includes a button 'a' on the root view. Tapping 'a' pushes a view on a navigation view controller stack, with a flip animation. The pushed view has a button to pop the view back to the root.
The underlying code:
- (IBAction)pushOneView{
TheAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight
forView:delegate.navigationController.view cache:NO];
[delegate.navigationController
pushViewController:oneViewController animated:NO];
[UIView commitAnimations];
}
This seems to work fine, and the animation is quite smooth.
The root view also includes a subview ('panelView'), and another button, 'b'.
panelView can display either of two other subviews--tapping 'b' swaps between those subviews, with a spin animation. The code:
-(IBAction)swapPanels{
UIViewController *coming;
UIViewController *going;
float rotation;
if (self.aPanel.view.superview == nil) {
coming = aPanel;
going = bPanel;
rotation = 3.14;
}
else {
coming = bPanel;
going = aPanel;
rotation = -3.14;
}
// First half of spin
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25];
CGAffineTransform swirlTransform = CGAffineTransformMakeRotation(rotation);
panelView.transform = swirlTransform;
[panelView setAlpha:0.1];
[UIView commitAnimations];
// Finish spin
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25];
CGAffineTransform secondTransform =
CGAffineTransformRotate(swirlTransform, rotation);
panelView.transform = secondTransform;
[panelView setAlpha:1];
[UIView commitAnimations];
// Swap the panels
[going.view removeFromSuperview];
[panelView insertSubview:coming.view atIndex:0];
}
This also seems to work fine. Each of the swappable panels contains a picker and some labels.
However, I notice that the 'a' transition becomes slow and jerky if the 'b' transition has been executed before it.
In other words, if I start the app, run 'a' back and forth several times, it runs smoothly. Then exercise 'b' back and forth a few times. Then try 'a' again...'a' is now jerky, and will remain so until an app restart.
This is 100% repeatable. It is subtle using the simulator, but quite obvious on a device.
I have tested for leaks--none are shown by leaks tool.
If the animation is removed from the 'b' operation (just comment-out the animation steps), the effect on 'a' is not observed after the 'b' subview swap is exercised.
If the pickers are removed from the swappable panel nibs, the effect is similarly eliminated.
If the 'a' animation transition is set to cache, then after 'b' it does not stutter in the middle, but seems to ignore animating, simply swapping the view (this may be a matter of perception).
In case I'm not clear: I am NOT triggering these separate operations at the same time. Animation 'a', after 'b' has been executed--and completed--is not the same as if 'b' had never been executed. Is there clean-up I should be doing after an animation? Is my subview-swapping code flawed? Or...?
Thanks in advance for any suggestions.
You do have two overlapping animations in your 'b' section. When you create an animation using a begin / commit block, it gets handed off to a background thread to perform. In your 'b' section, the two animations that should be sequential are actually being fired off at nearly the same time. This can cause bizarre behavior, possibly like what you are seeing.
I'd recommend adding a callback in your first animation to a delegate method using code like the following:
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(rotationAnimationFinished:finished:context:)];
within your first animation block in 'b' (the "First half of spin" part). Then you need to define the callback method within your class, in this case
- (void)rotationAnimationFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context;
Within that delegate method, which will be called when the first part of the spin animation has finished, place the remaining code from your 'b' method (everything after your "Finish spin" comment).
By separating apart these animations, that might prevent the weirdness you're seeing.
Brad's answer does seem to have lead me to a solution: the symptoms continued to suggest that something about running those 'b' animations left the system in a different state than when it started. Finally, it occurred to me that the transform property of the panelView was left set after the 'b' animations...and perhaps that impacted further animations of a superview containing panelView.
So I set up method as Brad suggested, to execute once the 'b' animations were complete--but all that method does is set the panelView transform back to the default: CGAffineTransformIdentity:
(void)spinFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context {
panelView.transform = CGAffineTransformIdentity;
}
With this in place, post-'b' executions of the 'a' animation appear to be back to normal. So thanks again, Brad, for your help here. It is much appreciated.
Okay, this is the code:
[lblMessage setText: txtEnter.text];
[lblMessage sizeToFit];
scrollingTextView.contentSize = lblMessage.frame.size;
float width = (lblMessage.frame.size.width) + (480);
[UIView beginAnimations:#"pan" context:nil];
[UIView setAnimationDuration:durationValue];
[UIView setAnimationRepeatCount:5];
scrollingTextView.contentOffset = CGPointMake(width,0);
[UIView commitAnimations];
//The scrolling text view is rotated.
scrollingTextView.transform = CGAffineTransformMakeRotation (3.14/2);
[self.navigationController setNavigationBarHidden:YES];
btnChange.transform = CGAffineTransformMakeRotation (3.14/2);
I have the user enter in some text, press a button and then a label is replaced with the text, turned 90 degrees in a scrollview on a page.
After a certain number of characters, for example say 20.. the animation just won't load. I can go back down until the animation will run.
Any ideas on where I am going wrong, or a better way of storing the text etc etc ?
Core Animation animations are performed on a separate thread. When you enclose the change in contentOffset in a beginAnimations / commitAnimations block, that change will be animated gradually. The scrolling text view rotation that occurs next, outside of the animation block, will be performed instantly. Since both are interacting with the same control on different threads, it's not surprising that you're getting weird behavior.
If you want to animate the rotation of the text in the same way as the contentOffset, move that line of code to within the animation block.
If you want to have the rotation occur after the offset change animation has completed, set up a callback delegate method. You can use code in the beginning of your animation block similar to the following:
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(contentOffsetAnimationHasFinished:finished:context:)];
which requires you to implement a delegate method like the following:
- (void)contentOffsetAnimationHasFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context;
{
// Do what you need to, now that the first animation has completed
}
EDIT (2/6/2009):
I just created a simplified version of your application, using only the sideways text scrolling, and find no problem with the animation on the device with any number of characters. I removed all extraneous calls to layout the buttons, etc., and only animate the text. Rather than apply the rotation transform to the scroll view every time you click the button, I have it start rotated and stay that way.
I thought it might be a layer size issue, as the iPhone has a 1024 x 1024 texture size limit (after which you need to use a CATiledLayer to back your UIView), but I was able to lay out text wider than 1024 pixels and still have this work.
A full Xcode project demonstrating this can be downloaded here. I don't know what your issue is, but it's not with the text animating code you present here.
Right, this code is working fine in the simulator, and works fine until i enter more than say 20 characters in txtEnter.text:
- (IBAction)updateMessage:(id)sender
{
//Animation coding
//Put the message in a resize the label
[lblMessage setText: txtEnter.text];
[lblMessage sizeToFit];
//Resize the scrolliew and change the width.
scrollingTextView.contentSize = lblMessage.frame.size;
float width = (lblMessage.frame.size.width) + (480);
scrollingTextView.transform = CGAffineTransformMakeRotation (3.14/2);
//Begin the animations
[UIView beginAnimations:#"pan" context:nil];
[UIView setAnimationDuration:durationValue];
[UIView setAnimationRepeatCount:5];
//Start the scrolling text view to go across the screen
scrollingTextView.contentOffset = CGPointMake(width,0);
[UIView commitAnimations];
//General hiding and showing points.
[txtEnter resignFirstResponder];
[btnChange setHidden:NO];
[txtEnter setHidden:YES];
[btnUpdate setHidden:YES];
[lblSpeed setHidden:YES];
[lblBackground setHidden:YES];
[backgroundColourControl setHidden:YES];
[speedSlider setHidden:YES];
[scrollingTextView setHidden:NO];
[backgroundImg setHidden:NO];
[toolbar setHidden:YES];
[self.navigationController setNavigationBarHidden:YES animated:YES];
//Depending on the choice from the segment control, different colours are loaded
switch([backgroundColourControl selectedSegmentIndex] + 1)
{
case 1:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES];
break;
case 2:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:YES];
break;
default: break;
}
btnChange.transform = CGAffineTransformMakeRotation (3.14/2);
}
I've tried your method Brad, but can't seem to get the (void) section to work properly.
What my app does its fill the label with a message and then rotates them all to act like it's in landscape mode. Then what it does it scroll the label within a scrollview to act like a scrolling message across the screen.