How to animate UILabel? - objective-c

I'm using UILabel to display some dynamic text. Sometime its over lap the width of the label. I want to slide the text if the UILabel goes out of bound.
How do I do the sliding animation with UILabel? Any help?

Modifying my answer to address the short coming pointed out -
UILabel *label; //Previously initialized UILabel
float newX = 0.0;
float newY = 101.0f;
label.center = CGPointMake(newX, newY);
If you wanted to animate the movement, it's cake to add an animation block:
UILabel *label; //Previously initialized UILabel
float newX = 90.0f;
float newY = 101.0f;
[UIView transitionWithView:label
duration:0.5f
options:UIViewAnimationCurveEaseInOut
animations:^(void) {
label.center = CGPointMake(newX, newY);
}
completion:^(BOOL finished) {
// Do nothing
}];
Notice that we only animate the X coordinate as you want the label to slide.

When I had to do something similar, I did this.
Please notice that I'm tweening the alpha, not the position, but I hope this could help you:
[UIView animateWithDuration:0.3f animations:^{yourLabel.alpha = 0.f;}];

-(void)repeat{
[NSTimer scheduledTimerWithTimeInterval:8.0
target:self
selector:#selector(LabelAnimation)
userInfo:nil
repeats:YES];
}
-(void)LabelAnimation
{
NSArray *elements = [yourText componentsSeparatedByString:#","];
NSMutableArray *outputElements = [[NSMutableArray alloc] init];
for (int i=1;i<[elements count];i++)
[outputElements addObject:[elements objectAtIndex:i]];
NSString *outputString = [outputElements componentsJoinedByString:#","];
[UIView animateWithDuration:3.0f delay:0.2f options:UIViewAnimationOptionTransitionNone animations:^{
_header.labelHeaderName.text=outputString;
} completion:^(BOOL finished)
{
if (outputString.length == 0) {
_header.labelHeaderName.text=_strAddress(your saved address);
}
}];
}

Related

automatic UIScrollView with paging

I have a UIScrollView with paging enabled. However i want this scrollview to scroll right when a certain amount of time has passed. Is there a easy way to implement this or do i need to use a timer and programmatically scroll the scrollview?
Something like this website has in its header: http://denederlandsewateren.nl/ [notice the text "De Nederlandse Wateren" changes each x seconds]
You need a little method to help you scroll to the exact page, this is not implemented, but it's very simple, let's assume your scrollview is called myScrollview
This assumes you're scrolling horizontally, you can switch the code to fit your needs
-(void)scrollToPage:(NSInteger)aPage{
float myPageWidth = [myScrollView frame].size.width;
[myScrollView setContentOffset:CGPointMake(aPage*myPageWidth,y) animated:YES];
}
Then you setup a timer to call this method every 5 seconds for example, like this:
[[NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:#selector(scrollPages)
userInfo:Nil
repeats:YES] fire];
Next step is to create the method that will be fired by the timer and scroll to the next page, I called it -(void)scrollPages, it also requires that you have two global variables called currentPage and numberOfPages, both are of type NSInteger
-(void)scrollPages{
[self scrollToPage:currentPage%numberOfPages];
currentPage++;
}
If something doesn't make sense let me know !
Found this on stackoverflow
[scrollView setContentOffset:CGPointMake(x, y) animated:YES];
To do slideshows with UIScrollView, you arrange all images in the scroll view, set up a repeated timer, then -setContentOffset:animated: when the timer fires.
In your .h file create outlets for scrollview and paging
#property (weak, nonatomic) IBOutlet UIScrollView *sliderScrollView;
#property (weak, nonatomic) IBOutlet UIPageControl *sliderPageControll;
#property (nonatomic,strong) NSArray *sliderImagesArray;
#property (nonatomic,strong) NSString *sliderIndexString;
#property (nonatomic,strong) NSString *currentPageIndexString;
after that in your .m file
[self.sliderScrollView setPagingEnabled:YES];
[self.sliderScrollView setBounces:NO];
[self.sliderScrollView setAlwaysBounceVertical:NO];
[self.sliderScrollView setShowsHorizontalScrollIndicator:NO];
self.sliderScrollView.alwaysBounceVertical = NO;
NSArray *imagesArray = self.sliderImagesArray;
for (int i = 0; i < [imagesArray count]; i++){
CGFloat xOrigin = i * self.imageSliderScrollView.frame.size.width;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(xOrigin, 0, self.sliderScrollView.frame.size.width, self.sliderScrollView.frame.size.height)];
imageView.userInteractionEnabled = YES;
NSString *imgStr = [serviceImgArray objectAtIndex:i];
NSString *bikeStr = [NSString stringWithFormat:#"%#", imgStr];
NSURL *imageURL = [NSURL URLWithString:[bikeStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[imageView sd_setImageWithURL:imageURL
placeholderImage:[UIImage imageNamed:#"profilepic_bg"]];
[imageView setContentMode:UIViewContentModeScaleAspectFill];
[self.sliderScrollView addSubview:imageView];
}
// for adding autorotate scrolling
[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(autoStartSlide:) userInfo:nil repeats:YES];
self.sliderPageControll.numberOfPages = imagesArray.count;
self.sliderPageControll.currentPage = 0;
self.currentPageIndexString = [NSString stringWithFormat:#"%ld",(long)0];
[self.sliderScrollView setContentSize:CGSizeMake(self.sliderScrollView.frame.size.width * [imagesArray count], self.sliderScrollView.frame.size.height)];
if ([self.sliderPageControll respondsToSelector:#selector(setPageIndicatorTintColor:)]) {
self.sliderPageControll.currentPageIndicatorTintColor = [UIColor redColor];
self.sliderPageControll.pageIndicatorTintColor = [UIColor whiteColor];
}
CGRect frame = self.sliderScrollView.frame;
frame.origin.x = frame.size.width * [[NSString stringWithFormat:#"%#",self.sliderIndexString] integerValue];
frame.origin.y = 0;
[self.sliderScrollView scrollRectToVisible:frame animated:NO];
self.sliderPageControll.currentPage = [[NSString stringWithFormat:#"%#",self.sliderIndexString] integerValue];
after that implement scrollview delegate method
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
NSInteger scrollIndex = (NSInteger)(self.sliderScrollView.contentOffset.x / self.sliderScrollView.frame.size.width);
self.sliderPageControll.currentPage = scrollIndex;
self.currentPageIndexString = [NSString stringWithFormat:#"%ld",(long)self.sliderPageControll.currentPage];
}
Here implement your autotrotate method.
- (void)autoStartSlide:(id)sender {
if(pagger.numberOfPages > pagger.currentPage+1) {
[UIView animateWithDuration:0.5 animations:^{
slider.contentOffset = CGPointMake(slider.contentOffset.x + slider.frame.size.width, 0);
} completion:^(BOOL finished) {
}];
}
else {
slider.contentOffset = CGPointMake(slider.contentOffset.x - slider.frame.size.width, 0);
[UIView animateWithDuration:0.5 animations:^{
slider.contentOffset = CGPointMake(slider.contentOffset.x + slider.frame.size.width, 0);
} completion:^(BOOL finished) {
slider.contentOffset = CGPointMake(0, 0) ;
}];
}
}
Here is a Swift 5 Compatible one
var currentPage = 1;
var slideTimer : Timer?
ViewDidLoad
slideTimer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(scrollPages), userInfo: nil, repeats: true)
viewDidDisappear
slideTimer?.invalidate()
Functions
#objc func scrollPages() {
scrollToPage(page: CGFloat(currentPage%slides.count));
currentPage+=1;
}
func scrollToPage(page : CGFloat) {
let pageWidth = scrollView.frame.width
scrollView .setContentOffset(CGPoint(x: pageWidth * page, y: 0.0), animated: true)
}

How do I make a UILabel text to fade away after few seconds?

I have a UILabe for my matching card game that writs "Good match!" for example if you have a match, and I want to make it disappear after notifying the user with the message.
What method do that? can I make it fad away..? thanks.
This is my updateUI method:
-(void) updateUI {
for (UIButton *cardButton in self.cardButtons) {
Card *card = [self.game cardAtIndex:[self.cardButtons indexOfObject:cardButton]];
[cardButton setTitle:card.contents forState:UIControlStateSelected];
[cardButton setTitle:card.contents forState:UIControlStateSelected|UIControlStateDisabled];
cardButton.selected = card.isFaceUp;
cardButton.enabled = !card.unplayble;
if (card.unplayble) {
cardButton.alpha = 0.1;
}
self.scoreCounter.text = [NSString stringWithFormat:#"Score: %d", self.game.score];
if (self.game.notification) {
[UIView animateWithDuration:2 animations:^{
self.notificationLabel.text = [NSString stringWithFormat:#"%#", self.game.notification];
self.notificationLabel.alpha = 0;
}];
}
}
}
This will fade away the label over two seconds. Change the animateWithDuration: to however long you want
if (self.game.notification == nil) {
[UIView animateWithDuration:2 animations:^{
self.notificationLabel.alpha = 0;
}];
}
If you want to change the text, try this (I can't test it right now, so it might not work)
[UIView animateWithDuration:2 animations:^{
self.notificationLabel.text = #"text you want to change it to";
}];
And then, when you want to use the label again, you have to set the self.notificationLabel.alpha back to 1. So try
if (self.game.notification) {
self.notificationLabel.alpha = 1;
[UIView animateWithDuration:2 animations:^{
self.notificationLabel.text = [NSString stringWithFormat:#"%#", self.game.notification];
self.notificationLabel.alpha = 0;
}];
}
I don't think that's possible. More than likely, you'll need to replace the UILabel with a NSView in Interface Builder and use the drawing functions contained therein to draw the text with transparency.

NSMutableArray not holding UIImages properly?

I have enabled my Cocoa Touch app to be navigable by swiping left or right to alter positions in history. The animation is kind of done like Android's "card" style. Where swiping to the left (<--) just moves the current screen image out of the way, while showing the previous view beneath it.
This works fine, but when I want to swipe the other way (-->), to go back, I need to get the previous image, and move that over the current view. Now, I had this working if I only store the previous image, but what if I go <-- a few times, then I will not have enough images.
So, the solution is obvious, use an NSMutableArray and just throw the latest image at the front of the array, and when you swipe the other way, just use the first image in the array. However, the image never shows when I start the animation. It just shows nothing. Here's the required methods you should see:
-(void)animateBack {
CGRect screenRect = [self.view bounds];
UIImage *screen = [self captureScreen];
[imageArray insertObject:screen atIndex:0]; //Insert the screenshot at the first index
imgView = [[UIImageView alloc] initWithFrame:screenRect];
imgView.image = screen;
[imgView setHidden:NO];
NSLog(#"Center of imgView is x = %f, y = %f", imgView.center.x, imgView.center.y);
CGFloat startPointX = imgView.center.x;
CGFloat width = screenRect.size.width;
NSLog(#"Width = %f", width);
imgView.center = CGPointMake(imgView.center.x, imgView.center.y);
[self.view addSubview: imgView];
[self navigateBackInHistory];
[UIView animateWithDuration:.3 animations:^{
isSwiping = 1;
imgView.center = CGPointMake(startPointX - width, imgView.center.y);
} completion:^(BOOL finished){
// Your animation is finished
[self clearImage];
isSwiping = 0;
}];
}
-(void)animateForward {
CGRect screenRect = [self.view bounds];
//UIImage *screen = [self captureScreen];
UIImage *screen = [imageArray objectAtIndex:0]; //Get the latest image
imgView = [[UIImageView alloc] initWithFrame:screenRect];
imgView.image = screen;
[imgView setHidden:NO];
NSLog(#"Center of imgView is x = %f, y = %f", imgView.center.x, imgView.center.y);
CGFloat startPointX = imgView.center.x;
CGFloat width = screenRect.size.width;
NSLog(#"Width = %f", width);
imgView.center = CGPointMake(imgView.center.x - width, imgView.center.y);
[self.view addSubview: imgView];
[UIView animateWithDuration:.3 animations:^{
isSwiping = 1;
imgView.center = CGPointMake(startPointX, imgView.center.y);
} completion:^(BOOL finished){
// Your animation is finished
[self navigateForwardInHistory];
[self clearImage];
isSwiping = 0;
}];
}
-(void)clearImage {
[imgView setHidden:YES];
imgView.image = nil;
}
-(void)navigateBackInHistory {
[self saveItems:self];
[self alterIndexBack];
item = [[[LEItemStore sharedStore] allItems] objectAtIndex:currentHistoryIndex];
[self loadItems:self];
}
-(void)navigateForwardInHistory {
[imageArray removeObjectAtIndex:0]; //Remove the latest image, since we just finished swiping this way.
[self saveItems:self];
[self alterIndexForward];
item = [[[LEItemStore sharedStore] allItems] objectAtIndex:currentHistoryIndex];
[self loadItems:self];
}
Note that imgView is a class-level UIImageView and imageArray is a class level array.
Any ideas? Thanks.
Edit
Here's the code at the top of my .m to initalize it. Still does not work.
.....
NSMutableArray *imageArray;
- (void)viewDidLoad
{
[super viewDidLoad];
imageArray = [imageArray initWithObjects:nil];
It looks like you forgot to create the array. Something like this at the appropriate time would do (assuming ARC):
imageArray = [NSMutableArray array];
Glad that worked out.

Autolayout Constraint - Keyboard

Im stuck trying to animate a table view smoothly which has an autolayout contraint. I have a reference to the constraint "keyboardHeight" in my .h and have linked this up in IB. All i want to do is animate the table view with the keyboard when it pops up. Here is my code:
- (void)keyboardWillShow:(NSNotification *)notification
{
NSDictionary *info = [notification userInfo];
NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect keyboardFrame = [kbFrame CGRectValue];
CGFloat height = keyboardFrame.size.height;
[UIView animateWithDuration:animationDuration animations:^{
self.keyboardHeight.constant = -height;
[self.view setNeedsLayout];
}];
}
The thing is the animation block is instantaneous and I see white space appear before the keyboard has finished its animation. So basically I see the white background of the view as the keyboard is animating. I cannot make the animation last for as long as the keyboard is animating.
Am i approaching this the wrong way? Thanks in advance!
Try it this way:
self.keyboardHeight.constant = -height;
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
Remember this pattern because this should be the correct way to update constraint-based layouts (according to WWDC). You can also add or remove NSLayoutConstraints as long as you call setNeedsUpdateConstraints after.
If you're using UITableViewController, keyboard size should be automatically accommodated by iOS to adjust the contentInsets. But if your tableView is inside a UIViewController, you probably wanted to use this:
KeyboardLayoutConstraint in the Spring framework. Simplest solution I've found so far.
Try the next code. In this case table view lays out at the bottom edge of the screen.
- (void)keyboardWillShow:(NSNotification *)notification { // UIKeyboardWillShowNotification
NSDictionary *info = [notification userInfo];
NSValue *keyboardFrameValue = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect keyboardFrame = [keyboardFrameValue CGRectValue];
BOOL isPortrait = UIDeviceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation);
CGFloat keyboardHeight = isPortrait ? keyboardFrame.size.height : keyboardFrame.size.width;
// constrBottom is a constraint defining distance between bottom edge of tableView and bottom edge of its superview
constrBottom.constant = keyboardHeight;
// or constrBottom.constant = -keyboardHeight - in case if you create constrBottom in code (NSLayoutConstraint constraintWithItem:...:toItem:...) and set views in inverted order
[UIView animateWithDuration:animationDuration animations:^{
[tableView layoutIfNeeded];
}];
}
- (void)keyboardWillHide:(NSNotification *)notification { // UIKeyboardWillHideNotification
NSDictionary *info = [notification userInfo];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
constrBottom.constant = 0;
[UIView animateWithDuration:animationDuration animations:^{
[tableView layoutIfNeeded];
}];
}
The approach I took is to add a view which follows the size of the keyboard. Add it below your tableview, or text input or whatever and it will push things up when the keyboard appears.
This is how I set up the view hierarchy:
NSDictionary *views = #{#"chats": self.chatsListView, #"reply": self.replyBarView, #"fakeKeyboard":self.fakeKeyboardView};
[self.view addVisualConstraints:#"V:|-30-[chats][reply][fakeKeyboard]|" views:views];
And then the key bits of the keyboard-size-following view look like this:
- (void)keyboardWillShow:(NSNotification *)notification
{
// Save the height of keyboard and animation duration
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardRect = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
self.desiredHeight = CGRectGetHeight(keyboardRect);
self.duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue];
[self animateSizeChange];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
self.desiredHeight = 0.0f;
[self animateSizeChange];
}
- (CGSize)intrinsicContentSize
{
return CGSizeMake(UIViewNoIntrinsicMetric, self.desiredHeight);
}
- (void)animateSizeChange
{
[self invalidateIntrinsicContentSize];
// Animate transition
[UIView animateWithDuration:self.duration animations:^{
[self.superview layoutIfNeeded];
}];
}
The nice thing about letting this particular view handle its resizing is that you can let the view controller ignore it, and you can also re-use this view any place in your app you want to shift everything up.
The full file is here:
https://gist.github.com/shepting/6025439

How to elegantly transition images in slide show?

After some research on here I found a solution to creating a slide show of images in an iphone app. All working fine, currently the images show one after another.
My question is, can I make the images cross dissolve/fade rather than just appearing, and if so could I get some advice on that.
My Code
.m
}
int topIndex = 0, prevTopIndex = 1;
- (void)viewDidLoad
{
imagebottom = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,160,240)];
[self.view addSubview:imagebottom];
imagetop = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,160,240)];
[self.view addSubview:imagetop];
imageArray = [NSArray arrayWithObjects:
[UIImage imageNamed:#"image1.png"],
[UIImage imageNamed:#"image2.png"],
[UIImage imageNamed:#"image3.png"],
[UIImage imageNamed:#"ip2.png"],
nil];
NSTimer *timer = [NSTimer timerWithTimeInterval:5.0
target:self
selector:#selector(onTimer)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[timer fire];
[super viewDidLoad];
}
-(void)onTimer{
if(topIndex %2 == 0){
[UIView animateWithDuration:5.0 animations:^
{
imagebottom.alpha = 0.0;
}];
imagetop.image = [imageArray objectAtIndex:prevTopIndex];
imagetop.image = [imageArray objectAtIndex:topIndex];
}else{
[UIView animateWithDuration:5.0 animations:^
{
imagetop.alpha = 1.0;
}];
imagetop.image = [imageArray objectAtIndex:topIndex];
imagebottom.image = [imageArray objectAtIndex:prevTopIndex];
}
prevTopIndex = topIndex;
if(topIndex == [imageArray count]-1){
topIndex = 0;
}else{
topIndex++;
}
You have a bunch of options. If you have a "container" view, you can make a new UIImageView transparent (alpha = 0), then use a UIView animation block to fade one image in and the other out (or leave alpha = 1 on both and slide one in from any side you want.
For instance, you have your main view, self.view. You have one UIImageView *oldView, that is now at rect (0,0,320,100) and you want to slide it to the right as you slide a newView imageView in. First you set the newView frame to (-320,0,320,100) then [self.view addSubview newView]. To animate the change:
[UIView animateWithDuration:2 animations:^
{
oldView.frame = CGRectMake(320, 0, 320, 100);
newView.frame = CGRectMake(0,0,320, 100);
}
completion:^(BOOL finished)
{
[oldView removeFromSuperView];
} ];
You also have the option of using UiView's
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion
which gives you more/different options (and its less work too!). For instance, using the same basic objects in the first example, but the newView having the same frame as the oldView:
transitionFromView:oldView toView:newView duration:2 options: UIViewAnimationOptionTransitionCrossDissolve completion:^(BOOL finished)) { /*whatever*/}];