In my iOS app when a button is pressed an event is initiated and at the bottom of the screen appears a status message informing the user about a successful or failed operation.
The status message appear and disappear with the following code.
this one show the message
- (void) showMessage:(NSString*)text
{
CGRect frame = [[self view] frame];
if(statusView == nil)
{
messageViewWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, frame.size.height-29,
frame.size.width, 0)];
statusView = [[StatusMessageView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, 0)
Text:text
andShowIndicator:NO];
[messageViewWindow addSubview:statusView];
[messageViewWindow makeKeyAndVisible];
}
UILabel *label = [statusView getTextLabel];
UIImageView *imageView = [statusView getBackImageView];
CGSize stringSize = [text sizeWithFont:[Constants getLabelFont]];
int xCoordinate = (messageViewWindow.frame.size.width - stringSize.width)/2;
[UIView beginAnimations:nil context:nil];
messageViewWindow.frame = CGRectMake(0, frame.size.height-59, frame.size.width, 30);
statusView.frame = CGRectMake(0, 0, frame.size.width, 30);
label.frame = CGRectMake(xCoordinate,5,stringSize.width,20);
imageView.frame = CGRectMake(0, 0, frame.size.width, 30);
[UIView commitAnimations];
[NSTimer scheduledTimerWithTimeInterval:2.0f target:self selector:#selector(hideMessage) userInfo:nil repeats:NO];
}
and this one hides the message
- (void) hideMessage
{
UILabel *label = [statusView getTextLabel];
UIImageView *imageView = [statusView getBackImageView];
CGRect labelFrame = label.frame;
[UIView beginAnimations:nil context:nil];
messageViewWindow.frame = CGRectMake(0, [UIScreen mainScreen].applicationFrame.size.height-29, [UIScreen mainScreen].applicationFrame.size.width, 0);
statusView.frame = CGRectMake(0, 0, [UIScreen mainScreen].applicationFrame.size.width, 0);
label.frame = CGRectMake(labelFrame.origin.x, 0, labelFrame.origin.y, 0);
imageView.frame = CGRectMake(0, 0, [UIScreen mainScreen].applicationFrame.size.width, 0);
[UIView commitAnimations];
}
strange thing is that the message is shown and after two seconds dissapears, however the main window lost functionality, like the copy and paste ability.
Do you see something wrong in my methods? Is there any certain way, calling the "animations" code?
Since you are writing [messageViewWindow makeKeyAndVisible];, you have to write [self.view.window makeKeyAndVisible] in hideMessage to let the self.view.window handle all the userinteraction again.
This is because you use a UIWindow to display your view, which is not a good idea (it is not recommended to create UIWindows by yourself, as explained in the "Overview" paragraph of the documentation.
Moreover, you make your window the keywindow but don't restore the standard window at the end when you hide it, thus your problems with the events later.
And last, you use obsolete APIs for the animations, which is deprecated since iOS4 is out (and I guess you don't code for iOS3 or earlier), you should really use the new APIs that have been introducted 3 iOS versions ago now. Besides, it will avoid the overhead to create an NSTimer for that.
So you code can become:
- (void) showMessage:(NSString*)text
{
CGSize sz = self.view.window.frame.size;
CGRect hiddenFrame = CGRectMake(0, sz.height-29, sz.width, 0);
if(statusView == nil)
{
statusView = [[StatusMessageView alloc] initWithFrame:hiddenFrame
text:text
andShowIndicator:NO];
[self.window addSubview:statusView];
}
UILabel *label = [statusView getTextLabel];
UIImageView *imageView = [statusView getBackImageView];
CGSize stringSize = [text sizeWithFont:[Constants getLabelFont]];
int xCoordinate = (sz.width - stringSize.width)/2;
label.frame = CGRectMake(xCoordinate,5,stringSize.width,20);
imageView.frame = CGRectMake(0, 0, frame.size.width, 30);
[UIView animateWithDuration:1.f animations:^{
statusView.frame = CGRectMake(0, sz.height-59, frame.size.width, 30);
} completion:^{
// When show animation is done, schedule the start of the hide animation with a delay of 2 seconds
[UIView animateWithDuration:1.f delay:2.f options:0 animation:^{
statusView.frame = hiddenFrame;
} completion:nil];
}];
}
Related
I am trying to get a UIView to sit on top of the status bar, but currently have had no success. I have tried the following:
view.window?.windowLevel = UIWindowLevelStatusBar + 1 // view being a UIView() object
I have also tried:
let win: UIWindow = UIWindow( )
win.frame = CGRect( x: 0, y: 0, width: 100, height: Display.height )
win.windowLevel = UIWindowLevelStatusBar + 1
win.hidden = false
win.backgroundColor = UIColor.blueColor()
win.makeKeyAndVisible()
In all cases the status bar is still on top. Has anyone got this to work in Swift yet?
This is my simple solution (you can also use MTStatusBarOverlay - check git hub).
first initialise the window. Do that after you set makeKeyAndVisible on your main window.
self.syncMessageWindow = [[UIWindow alloc] initWithFrame:messageRect];
self.syncMessageWindow.clipsToBounds = YES;
self.syncMessageWindow.frame = messageRect;
self.syncMessageWindow.windowLevel = UIWindowLevelStatusBar+1.f;
self.syncMessageWindow.alpha = 1.f;
self.syncMessageView = [[UIView alloc] initWithFrame:messageRect];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 2, messageRect.size.width-20, 16)];
[label setTag:100];
[label setTextAlignment:NSTextAlignmentCenter];
[label setFont:[UIFont fontWithName:#"HelveticaNeue" size:12.0]];
[label setTextColor:[UIColor whiteColor]];
[self.syncMessageView addSubview:label];
[self.syncMessageWindow addSubview:self.syncMessageView];
[self.syncMessageWindow setRootViewController:[UIApplication sharedApplication].delegate.window.rootViewController];
[self.syncMessageWindow makeKeyAndVisible];
self.syncMessageWindow.hidden = YES;
than show the message
if(self.syncMessageWindow.hidden == YES) {
self.syncMessageWindow.hidden = NO;
[self.syncMessageView setBackgroundColor:color];
[self.syncMessageView setAlpha:1.0];
[self.syncMessageView setFrame:CGRectMake(0, -20, self.syncMessageView.frame.size.width, self.syncMessageView.frame.size.height)];
[self.syncMessageWindow setWindowLevel:UIWindowLevelStatusBar+1];
[((UILabel*)[self.syncMessageView viewWithTag:100]) setText:message];
[UIView animateWithDuration:.3 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.syncMessageView.frame = CGRectMake(0, 0, self.syncMessageView.frame.size.width, self.syncMessageView.frame.size.height);
} completion:^(BOOL finished) {
[UIView animateWithDuration:.3 delay:2.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.syncMessageView.frame = CGRectMake(0, -20, self.syncMessageView.frame.size.width, self.syncMessageView.frame.size.height);
} completion:^(BOOL finished) {
[self.syncMessageWindow setWindowLevel:UIWindowLevelNormal];
self.syncMessageWindow.hidden = YES;
}];
}];
}
Why don't you hide the status bar? Then you can put the view at the top. See How to hide iOS status bar.
I don't think it is possible to cover the status bar with another view, because all content is behind the status bar by default.
How can I implement marquee effect animation in UIImage.
I have a image of cloud (320*480). I need to animation it continuously left from right without any lagging and disappearing. Below is a sample of html.
http://www.quackit.com/html/codes/html_marquee_code.cfm
2nd from top(Continuous scrolling text:).
Please help
UIImage *clouds = [UIImage imageNamed:#"Clouds"];
UIImageView *cloudView = [[UIImageView alloc] initWithImage:clouds];
CGRect origin = CGRectMake(320, 0, clouds.size.width, clouds.size.height);
CGRect destination = CGRectMake(0, 0, clouds.size.width, clouds.size.height);
cloudView.frame = origin;
[self.view addSubview:cloudView];
[UIView animateWithDuration:5 delay:0 options:UIViewAnimationOptionRepeat | UIViewAnimationOptionCurveLinear animations:^{
cloudView.frame = destination;
} completion:nil];
Do this:
-(void)marqueeEffect
{
imgView.frame = CGRectMake(self.view.frame.origin.y,50,320,480); //right frame
//increase time duration as per requirement
[UIView animateWithDuration:3.0
delay: 0.0
options: UIViewAnimationCurveEaseOut
animations:^{
imgView.frame = CGRectMake(-imgview.frame.size.width,50,320,480); //left frame
}
completion:^(BOOL finished){
[self performSelector:#selector(marqueeEffect)];
}];
}
TRY THIS EXAMPLE , ITS FOR UILABEL:
int x;
#synthesize label;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
label=[[UILabel alloc]initWithFrame:CGRectMake(300, 400, 150, 30)];
label.text=#"WWW.SONGS.PK";
label.backgroundColor=[UIColor clearColor];
x=300;
[NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:#selector(clickme) userInfo:nil repeats:YES];
}
-(void)clickme
{
x--;
label.frame=CGRectMake(x, 400, 150, 30);
if( x==-150)
{
x=300;
}
[self.view addSubview:label];
}
Just wondering why and need to solve it. i have this searchbar looks like this.
which clicked will move up to the top and expend to 0,0,320,searchbar's height.
which clicked Cancel, it should resize back to 33,55,270, searchbar's height. but it doesn't
the searchDisplayControllerDidEndSearch will work to resize back, however there is a 1 sec lag that user could see the changes. any body why in searchDisplayControllerWillEndSearch the animation resize wound't work ?.
thanks for the comments and feedback.
- (void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
[UIView animateWithDuration:.1
animations:^{
controller.searchResultsTableView.frame = frogTableView.frame;
searchDisplayController.searchResultsTableView.frame = frogTableView.frame;
searchDisplayController.searchBar.frame = CGRectMake(32,
55,
270,
searchDisplayController.searchBar.frame.size.height);
searchBar.frame = CGRectMake(32,
55,
270,
searchBar.frame.size.height);
frogTableView.frame = CGRectMake(frogTableView.frame.origin.x,
121,
frogTableView.frame.size.width,
frogTableView.frame.size.height);
notePad.frame = CGRectMake(notePad.frame.origin.x,
45,
notePad.frame.size.width,
notePad.frame.size.height);
searchDisplayController.searchResultsTableView.frame = frogTableView.frame;
}
completion:^(BOOL finished){
//whatever else you may need to do
}];
}
I had the same trouble after I started to use UISearchBar with UISearchDisplayController. The solution I came up with is to place a search bar on a view:
UIView * searchBarSubview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, MENU_WORK_AREA_WIDTH, SEARCH_BAR_HEIGHT)] ;
searchBarSubview.autoresizesSubviews = YES;
searchBarSubview.backgroundColor = [UIColor clearColor];
UISearchBar * globalSearchBar = [[[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, MENU_WORK_AREA_WIDTH, SEARCH_BAR_HEIGHT)] autorelease];
globalSearchBar.tintColor = [UIColor blackColor];
globalSearchBar.delegate = self;
[globalSearchBar setBackgroundImage:[UIImage alloc]];
and resize the view instead of search bar in searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
// Slide in to the final destination
searchBarSubview.frame = CGRectMake(0, 0, MENU_WORK_AREA_WIDTH, SEARCH_BAR_HEIGHT);
[UIView commitAnimations];
I am displaying two images in my iPhone app, one on top, one on the bottom. They cover the entire screen. The user, with a swipe gesture, can change either of the images, depending on where the swipe started.
I want the image to change with an animated transition. It currently works without animation, or with the entire screen transitioning. Is it possible to make the transition occur over part of the screen?
I load the images for the first time (in viewDidLoad) thus:
// top image
UIImage *topImage = [UIImage imageNamed:#"top1.png"];
CGRect topframe = CGRectMake(0.0f, 0.0f, 320.0f, 240.0f);
UIImageView *topView = [[UIImageView alloc] initWithFrame:topframe];
topView.image = topImage;
[self.view addSubview:topView];
[topView release];
// bottom image
UIImage *bottomImage = [UIImage imageNamed:#"bottom1.png"];
CGRect bottomframe = CGRectMake(0.0f, 240.0f, 320.0f, 240.0f);
UIImageView *bottomView = [[UIImageView alloc] initWithFrame:bottomframe];
bottomView.image = bottomImage;
[self.view addSubview:bottomView];
[bottomView release];
When I detect a swipe, and detect which of the two images are to be changed, I call a routine like this one:
- (void)changeTopImage:(NSString *)newImage {
UIImage *topImage = [UIImage imageNamed:newImage];
CGRect topframe = CGRectMake(0.0f, 0.0f, 320.0f, 240.0f);
UIImageView *topView = [[UIImageView alloc] initWithFrame:topframe];
topView.image = topImage;
[self.view addSubview:topView];
[topView release];
}
Essentilly, I'm continually loading images on top of each other. Is that the best way to do it, especially in terms of memory management?
Everything else I've tried, using techniques such as below, make the entire screen transition:
[UIView beginAnimations:nil context:nil];
...
[UIView commitAnimations];
Thanks for any leads on which way I should be going on this.
well, an easy way could be this (repeat for the bottomImage):
don't release topView when you load it the first time in your method,
but declare it in your .h file,
and use a tempView too:
#interface YourClass: UIViewController{
UIImageView *topView;
UIImageView *tempView;
}
this way you can call them to move them and remove them when you load a new image
then in .m:
EDIT: some correction (see coco's comments):
[a] [b] line 4 = [c] line 11:
- (void)changeTopImage:(NSString *)newImage {
UIImage *topImage = [UIImage imageNamed:newImage];
//CGRect topframe = CGRectMake(0.0f, 0.0f, (320.0f + 320), 240.0f);
CGRect topframe = CGRectMake((0.0f + 320), 0.0f, 320.0f, 240.0f);
tempView = [[UIImageView alloc] initWithFrame:topframe];
//topView.image = topImage;
tempView.image = topImage;
[self.view addSubview:tempView];
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
[UIView beginAnimations:#"animation" context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
tempView.center = topView.center;
// do this to push old topView away, comment next line if wanna new image just cover it
//topView.center = CGPointMake(topView.x - 320, topView.y);
topView.center = CGPointMake(topView.center.x - 320, topView.center.y);
// call a method when animation has finished:
[UIView setAnimationDidStopSelector:#selector(endOfAnimation:finished:context:)];
[UIView commitAnimations];
}
- (void)endOfAnimation:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
[topView removeFromSuperview];
topView = tempView;
[tempView release];
tempView = nil;
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
}
- (void)dealloc {
if (tempView != nil) {
[tempView release];
}
[topView release];
[super dealloc];
}
I want to add some text which is a long text lets say a story and I want it to be presented in a moving up fashion. That is it will be displayed in a box and the text will be moved line by line to show the whole story. So one line gets out of the box from top and other comes from the bottom. Like a HTML marquee behavior.
You should look into whether or not UIScrollView's contentOffset property is animatable using UIView animation blocks.
If it's not, then you could try using an NSTimer and in its function, either set the contentOffset or call [scrollView scrollRectToVisible:desiredContentFrame animated:YES]; where desiredContentFrame.origin.y is just a little bit lower than what you previously had it at (depending on the scroll speed you want). Then play around with the firing frequency of your timer and the desiredContentFrame.origin.y's delta to see what looks best and has the best performance.
Here's a quick hack showing both ways:
- (void)startAnimTimer
{
currentRect = CGRectMake(0, 0, 1, 1);
[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(doScroll) userInfo:nil repeats:YES];
}
- (void)startAnimUIView
{
[UIView beginAnimations:#"scrollUIViewAnim" context:nil];
[UIView setAnimationDuration:20.0];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint newContentOffset = CGPointMake(0, scrollView.contentSize.height);
scrollView.contentOffset = newContentOffset;
[UIView commitAnimations];
}
- (void)loadView {
[super loadView];
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(5, 5, 200, 200)];
scrollView.contentSize = CGSizeMake(200, 1000);
scrollView.backgroundColor = [UIColor magentaColor];
CGFloat y = 10;
CGFloat yDelta = 21;
for(int i = 0; i < 47; i++)
{
// Add some UILabels to the scrollview just so we can see it animating
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, y, 180, 20)];
label.text = [NSString stringWithFormat:#"Cheezburger %d", i];
[scrollView addSubview:label];
[label release];
y += yDelta;
}
[self.view addSubview:scrollView];
// Comment out one of these
//[self startAnimTimer];
[self startAnimUIView];
}
- (void)doScroll
{
CGFloat scrollDelta = 1.0f;
CGRect newRect = CGRectMake(0, currentRect.origin.y + scrollDelta, currentRect.size.width, currentRect.size.height);
// Scroll the scrollview to the next position
[scrollView scrollRectToVisible:newRect animated:YES];
currentRect = newRect;
}
This method may help (or not):
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
If not, just make a big UILabel and animate its frame using a CABasicAnimation.
I think you want to look at the Scroll View (UIScrollView) in the iPhone SDK.
http://developer.apple.com/IPhone/library/documentation/UIKit/Reference/UIScrollView_Class/Reference/UIScrollView.html
Depending on your implementation, you may not be able to use it "out of the box" but it should provide the functionality you seem to be describing. I'm not sure it will do the auto-scroll thing but that should be pretty easy to implement... maybe.... But, I'm still confident it could be done.