Improve tabBar animation when hidden - ios

I've think about how to make the tabBar 's hidden animation more elegant and smoothly:
Here is how I implement:
So I just want to improve the animation, while the tabBar is suddenly, you know, disappear and hidden.
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[self.tabBarController.tabBar setHidden:YES];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self.tabBarController.tabBar setHidden:NO];
}
Any suggestion?

Try adding this method:
- (void)setTabBarHidden:(BOOL)tabBarHidden animated:(BOOL)animated
{
if (tabBarHidden == _isTabBarHidden)
return;
CGFloat offset = tabBarHidden ? self.tabBarController.tabBar.frame.size.height : -self.tabBarController.tabBar.frame.size.height;
[UIView animateWithDuration:animated ? 0.6 : 0.0
delay:0
usingSpringWithDamping:0.7
initialSpringVelocity:0.5
options:UIViewAnimationOptionCurveEaseIn|UIViewAnimationOptionLayoutSubviews
animations:^{
self.tabBarController.tabBar.center = CGPointMake(self.tabBarController.tabBar.center.x,
self.tabBarController.tabBar.center.y + offset);
}
completion:nil];
_isTabBarHidden = tabBarHidden;
}
Then you can call it like [self setTabBarHidden:YES animated:YES] and [self setTabBarHidden:NO animated:YES] to hide and show your bar, this will move it in and out of the screen instead of just make it instantly dissapear.
Don't forget to add a new bool property isTabBarHidden and also you can play with the values of the animation.

Related

How to create a shrink animation in uinavigationbar?

I use this code in objective c to make a fade in fadeout animation when the user scrolls up or down the uitableview. Is there any way to make a nice animation like shrinking the navigationbar slowly while the user scrolls to top slowly? The more he scrolls to the top the more the navigationbar should shrink.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat scrollPos = self.tableView.contentOffset.y ;
if(scrollPos >= _currentOffset ){
//hide navbar and fadeout
[UIView animateWithDuration:0.50 animations:^{
[self.navigationController setNavigationBarHidden:YES animated:YES];
self.navigationController.navigationBar.alpha = 0.0f;
}];
} else {
//Slide it up incrementally and fadein, etc.
[UIView animateWithDuration:0.50 animations:^{
[self.navigationController setNavigationBarHidden:NO animated:YES];
self.navigationController.navigationBar.alpha = 1.0f;
}];
}
}
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
scrollView = self.tableView;
_currentOffset = self.tableView.contentOffset.y;
}
You cannot customize the size of UINavigationBar on your own. You can only hide/appear it. Apple does not allow you to do that.
You can use UIView instead! Just hide your UINavigationBar and put the same frame of UIView. Since UIView is highly customizable, you can do whatever you want.

How can I animate NSLayoutConstraint when GMSMapView will move?

I want to animate buttons moving when user scrolls map (that has type GMSMapView) in my iOS application:
- (void)setButtonHidden:(bool)hidden
[UIView animateWithDuration:1 animations:^{
[_myButton setAlpha:hidden ? 0 : 1];
// or so:
[_myButtonConstraint setConstant:hidden ? -40 : 92];
[[self view] layoutIfNeeded];
}
}
Button showing animation works perfectly, but hiding is not animated.
I think than it's because of I calls [self setButtonHidden:YES] from mapView:willMove: method after which map view will be animated.
How can I combine different animations, in this case my animation and GMSMapView animation?
I found solution. Reason is GMSMapView bug
Solution is:
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:1 animations:^{
[_myButton setAlpha:hidden ? 0 : 1];
// or so:
[_myButtonConstraint setConstant:hidden ? -40 : 92];
[[self view] layoutIfNeeded];
// or any other animation
}];
});
Thanks all for help!
You can combine animations, but hidden can just turn on/off.
Adjust alpha first (as you did, but not with hidden), and set hidden in completion block.
[UIView animateWithDuration:1
animations:^{
_myButton.alpha = hidden ? 0 : 1;
// or so:
[_myButtonConstraint setConstant:hidden ? -40 : 92];
[[self view] layoutIfNeeded];
} completion:^(BOOL finished) {
_myButton.hidden = hidden ? YES : NO;
}];

keyboard not show at first time(iOS)

My code like this:
- (void)setupSubViews {
[self addSubview:self.textView];
[self addSubview:self.sendButton];
[self.textView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(5);
make.bottom.equalTo(-5);
make.leading.equalTo(9);
}];
[self.sendButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self);
make.trailing.equalTo(-9);
make.leading.equalTo(self.textView.mas_trailing).offset(7);
make.width.equalTo(60);
make.height.equalTo(40);
}];
}
The show function to make the textView becomeFirstResponder
- (void)show {
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
[keyWindow addSubview:self];
[self mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.trailing.equalTo(0);
make.bottom.equalTo(InputHeight);
}];
[self.textView becomeFirstResponder];
}
This view add to the keyWindow at the bottom of mainScreen, it's translate will changing follow the keyboard when the keyboard's frame changed.
- (void)keyboardWillChangeFrame:(NSNotification *)noti {
if (!self.textView.isFirstResponder) {
return;
}
NSValue *endFrame = noti.userInfo[#"UIKeyboardFrameEndUserInfoKey"];
CGFloat endY = [endFrame CGRectValue].origin.y;
BOOL isBackToBottom = endY == UI_SCREEN_HEIGHT;
CGFloat needOffset = endY - (UI_SCREEN_HEIGHT + InputHeight);
if (isBackToBottom) {
[UIView animateWithDuration:0.25 animations:^{
self.transform = CGAffineTransformIdentity;
} completion:^(BOOL finished) {
[self removeFromSuperview];
}];
} else {
[UIView animateWithDuration:0.25 animations:^{
self.transform = CGAffineTransformMakeTranslation(0, needOffset);
}];
}
}
Use Case:
viewController has a button, button click action like this:
- (void)beginChat {
[self.inputView show];
}
self.inputView is the above customView,
- (LiveChatInputView *)inputView {
if (!_inputView) {
_inputView = [LiveChatInputView new];
_inputView.sendBlock = ^(NSString *string) {
....
};
}
return _inputView;
}
Now my question is that when we call show function at the first time after application launched, the keyboard will not show, but call show function in second time, every thing is fine.
How to deal with this question, THX.
Calling this method is not a guarantee that the object will become the first responder.
As per Apple,
A responder object only becomes the first responder if the current
responder can resign first-responder status (canResignFirstResponder)
and the new responder can become first responder.
Try calling becomeFirstResponder like below,
[self.textView performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0];
I made a mistake, call [self removeFromSuperview] in the function of keyboardWillChangeFrame:.
I thought UIKeyboardWillChangeFrameNotification could only post it once at the keyboard show or hide, so i put the implementation of back action in keyboardWillChangeFrame:, and controlled by endFrame.origin.y == UI_SCREEN_HEIGHT
In practice, the fact is that:
when the keyboard show, NSNotificationCenter will post UIKeyboardWillChangeFrameNotification three times:
first
second
third
Tips:
only first time show the keyboard after application launched, the first UIKeyboardWillChangeFrameNotification of above three, the endFrame.origin.y is equal to UI_SCREEN_HEIGHT
My solution:
Observer the UIKeyboardWillHideNotification, and do back action in this callback.
Thanks for all answers of this question.

How do I move a child view controller, while hiding the status bar using Auto Layout instead of frames?

I have a view controller with multiple child view controllers in it (set up using Storyboards), and I move the one on top to the right (with the status bar as well) to display the underlying sidebar view controller.
This works perfectly with frames, as shown below:
- (void)displaySidebar {
self.fullScreenSnapshotOverlay = [self takeFullScreenSnapshot];
[self.postsView addSubview:self.fullScreenSnapshotOverlay];
[self hideStatusBar];
[UIView animateWithDuration:0.4 animations:^{
CGRect newFrame = self.postsView.frame;
newFrame.origin.x += 200.0;
self.postsView.frame = newFrame;
}];
}
(hideStatusBar simply called the UIApplication method and layoutIfNeeded.)
Giving me this (perfect) result:
However, if in the Storyboard I go to the container view controller and make a constraint from its leading space to the left of the view controller it's embedded in, and then adjust that constant, it really messes up the navigation bar, I assume due to hiding the status bar and taking a screenshot. I'm using this code:
- (void)displaySidebar {
self.fullScreenSnapshotOverlay = [self takeFullScreenSnapshot];
[self.postsViewController.view addSubview:self.fullScreenSnapshotOverlay];
[self hideStatusBar];
[UIView animateWithDuration:0.4 animations:^{
self.postsViewControllerDistanceFromLeftSideConstraint.constant = 270.0;
[self.view layoutIfNeeded];
}];
}
Giving me this messed up result:
Now I know the simple thing to do would be to just continue with frames, but I'd like to learn how do it properly with Auto Layout. What am I doing wrong here?
I'm not sure how what I did is any different from what you're doing. I modified the code I posted to your other question (Why does hiding my status bar completely break my simple animation?) to what's below, and it worked fine.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self performSelector:#selector(displaySidebar) withObject:nil afterDelay:1];
}
-(void)displaySidebar {
self.snapshotView = [self takeSnapshot];
[self.PostsView addSubview:self.snapshotView];
[self hideStatusBar];
self.leftCon.constant = 270;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
}];
}
-(void)moveOutMenu { // called from a button in the menu controller
self.leftCon.constant = 0;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
[[UIApplication sharedApplication] setStatusBarHidden:NO];
[self.snapshotView performSelector:#selector(removeFromSuperview) withObject:nil afterDelay:0.01];
}];
}
-(UIView *)takeSnapshot {
UIView *v = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO];
return v;
}
-(void)hideStatusBar {
[[UIApplication sharedApplication] setStatusBarHidden:YES];
[self.view layoutIfNeeded];
}
What are all the constraints you have on the container view that you're moving? Maybe there's something different there (I have top, leading, bottom and width constraints on mine -- leftCon is the outlet to the leading constraint).

How to Show and Hide UIPickerView like iOS Keyboard?

I have this code to hide UIPickerView by default:
- (void)viewDidLoad
{
[super viewDidLoad];
[_memberList setAlpha:0];
}
and this code to show UIPickerView when a button tapped :
- (IBAction)buttonChooseMember {
[UIView animateWithDuration:0.6 delay:0. options:UIViewAnimationOptionCurveEaseInOut animations:^{
[_memberList setAlpha:1];
} completion:nil];
}
and the last thing is this, to hide keyboard when user tap anywhere :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UIView * txt in self.view.subviews){
if ([txt isKindOfClass:[UITextField class]]) {
[txt resignFirstResponder];
}else if ([txt isKindOfClass:[UIPickerView class]]) {
[UIView animateWithDuration:0.6 delay:0. options:UIViewAnimationOptionCurveEaseInOut animations:^{
[_registerMLMList setAlpha:0];
} completion:nil];
}
}
}
but all of this just give me 'appear' animation, because it's only changing Alpha value from 0 to 1 (and vice versa). not slide-up or slide-down just like iOS keyboard.
I tried to use this animation below to have iOS keyboard look and feel on my UIPickerView :
- (IBAction)hidePicker {
UIPickerView *pickerView = [[UIPickerView alloc] init]; // default frame is set
float pvHeight = pickerView.frame.size.height;
float y = _screen.bounds.size.height - (pvHeight * -2); // the root view of view controller
[UIView animateWithDuration:0.5f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.picker.frame = CGRectMake(0 , y, pickerView.frame.size.width, pvHeight);
} completion:nil];
}
- (IBAction)showPicker {
UIPickerView *pickerView = [[UIPickerView alloc] init]; // default frame is set
float pvHeight = pickerView.frame.size.height;
float y = _screen.bounds.size.height - (pvHeight); // the root view of view controller
[UIView animateWithDuration:0.5f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.picker.frame = CGRectMake(0 , y, pickerView.frame.size.width, pvHeight);
} completion:nil];
}
I like this animation, it looks like iOS keyboard animation, but the problem with this animation is... when my app is loaded, the UIPickerView is already shows up. how to hide it when it loads up for the first time?
thank you.
All UIResponder objects have an inputView property. The inputView of a UIResponder is the view that will be shown in place of the keyboard when the responder becomes the first responder.
So if you want a UIPickerView to show up instead of the keyboard, you could simply do it by making your UIResponder (like a UITextField) have a UIPickerView as its inputView.
(As a caveat: you probably won't want a bare UIPickerView as the inputView, because you also need to account for when the keyboard would change size, like when you rotate. But this is the general idea.)
In viewDidLoad take one boolean variable and set it's value as TRUE and also set the UIPickerView's frame so that UIPickerView is invisible for first time.Based on the boolean value handle the frame animations to show or hide the picker view.
hidepicker and showpicker method idea is good, and the problem of "UIPicker is visible when the app is loaded" can be overcome by just setting the frame of UIPickerView while initiating it to the position such that it should not be visible...after that you can call the showpicker method to show the picker view.

Resources