I'm working on an app that I had originally made for iOS 7 which worked perfectly fine, but now after moving to iOS 8, things aren't working properly anymore. Basically, I have a view with a button. When I tap that button, another UIView with a UITextField "slides" up onto the screen from a position below the visible screen area. The problem comes when I tap the UITextField to type into it, where a keyboard comes up, but the view with the UITextField goes back to its initial position off the screen. This was not happening in iOS 7, so I'm assuming this has something to do with the changes to autolayout for iOS 8. Does anyone know what I can possibly do to fix this? I would rather not turn off autolayout if I don't have to, as a good portion of my app depends on it.
Here is some code to show you what I'm referring to. In my example, "locationField" is the button that gets tapped, and "locationView" is the UIView that slides onto the screen:
- (IBAction) locationFieldTapped:(UIButton *)sender {
[self slideViewUp:_locationView];
}
- (void) slideViewUp:(UIView *)slidingView {
if (viewIsSlidUp) {
return;
}
CGRect frame = slidingView.frame;
int availableHeight = self.view.frame.size.height;
// don't move view up if it's already moved up or in the process of moving up
if (frame.origin.y < availableHeight) {
return;
}
viewIsSlidUp = YES;
// move view just off screen for animation start, in case it's not already there
frame.origin.y = availableHeight;
slidingView.frame = frame;
[UIView animateWithDuration:0.5f animations:^{
CGRect newFrame = frame;
newFrame.origin.y = availableHeight - CGRectGetHeight(frame);
slidingView.frame = newFrame;
}];
}
You need to set the constraints of the view you're animating in iOS 8 and the autolayout system then deals with the rest. You can create an IBOutlet to an NSLayoutConstraint and simply change its constant property. Then you call the layoutIfNeeded method on the edited view's super view in the animation block.
Related
in my app im tapping on a navigation bar button and as a response i move the view beneath the navigation bar 60 px down (the delta var in the code), and under the view that moves down, appears a UITextField and at the same time show the keyboard.
that's how i achieve it:
-(void)btnSearch_Click:(id)sender{
float delta = _viewBtnSort.frame.size.height;
CGRect rect = rectSearch;
rect.origin.y += delta;
[UIView animateWithDuration:0.3f animations:^{
[_viewSearchResults setFrame:rect];
}completion:^(BOOL finished) {
[buttonSearch setEnabled:NO];
[_txtFieldSearch becomeFirstResponder];
}];}
Problem
it works fine for a few times and then for some unexplained reason(couldnt find so far why), when the keyboard appears it pushes my view back up i and i dont get the effect i want.
anybody got any ideas? thanks!
so i kept looking for a fix, and did it using this iOS8: What's going on with moving views during keyboard transitions? answer.
i changed my constraint instead of the frame and now it seems to work fine.
I created new Xcode single view project. In interface builder, I added a UIScrollView to cover complete view. Over this scrollview, I added a UITextField. The resulting UI looked like this:
Note that the scrollview does not scroll at this point as the content takes only the size of view and not greater than it.
Now for bringing UITextField on top of keyboard while editing, I followed the way described by Apple on Managing The Keyboard page. After doing this, it gave me expected behavior which brought the text field right above keyboard on editing begin as shown in following screenshot:
Now, after calling [textfield endEditing:YES], the keyboard hides itself, but the textfield does not return to its original place. It return to the place just little above its original place and now the scroll view becomes scrollable as if little height was added to it:
Notice the scroll bar in the above screenshot!
I want help in bring back the original behavior of the view after editing ends (when keyboard hides) i.e. the textField to return to exact same place and scroll should be happening as it was not happening before editing begin.
Project URL: - https://github.com/therohansanap/keyboard.git
You need adjust scrollview contentOffset textFieldDidBeginEditing and textFieldDidEndEditing.
or
One controller is available for scrollview auto scroll.
https://github.com/simonbs/BSKeyboardControls
I think the official way specified by Apple here is easiest and best way to keep this functionality working.
You can do something similar without Using Keyboard notifications as well. As you may know that we have TextField delegate methods , we can use those to set scrollView contentOffset and acquire the same behaviour
- (void)textFieldDidBeginEditing:(UITextField *)textField{
scrollView.contentOffset = CGPointMake(0, textField.center.y-80); // you can change 80 to whatever which fits your needs
}
the above method sets contentOffset Value of scroll view and your textFiled moves up, while the textField resignFirstResponder the below delegate method gets called, where you can set back the contentOffset value
- (void)textFieldDidEndEditing:(UITextField *)textField{
scrollView.contentOffset = CGPointMake(0,-80);
}
Note: you need to make every text field in your view to have their delegate as your UIViewController instance. You also need need your UIViewController to adopt UITextFieldDelegate
Took a look at your code, you dont need to change the content insets etc when trying to position the scroll view. You just need to modify the content offset property.
Here is the modified code :
#interface ViewController () {
UITextField *activeField;
CGPoint scrollViewOldPosition;
}
Modify the keyboardWasShow as follows :
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGFloat someSpaceBetweenKeyBoardAndField = 20.0;
scrollViewOldPosition = self.scrollView.contentOffset;
self.scrollView.contentOffset = CGPointMake(0, kbSize.height - (self.view.frame.size.height - activeField.frame.origin.y - activeField.frame.size.height) + someSpaceBetweenKeyBoardAndField);
}
Keyboard will be hidden method :
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
self.scrollView.contentOffset = scrollViewOldPosition;
}
Not the best code ever but it have some more features u can use, anything with _ is global variable
//Handle notification when keyboard appear
- (void)keyboardOnScreen:(NSNotification *)notification
{
if (_isKeyboardShow) {
return; //If keyboard is showing then return
}
_keyboardHeight = [[notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
[self animateTextFieldUp: YES];
_isKeyboardShow = YES;
}
//Handle notification when keyboard hide
- (void)keyboardOffScreen:(NSNotification *)notification
{
if(!_isKeyboardShow) return;
[self animateTextFieldUp: NO];
_isKeyboardShow = NO;//Missed this line
}
//Push view up with animation when keyboard show
- (void) animateTextFieldUp: (BOOL) up
{
UITextField *textfield = [UIResponder currentFirstResponder];
CGPoint windowPoint = [textfield convertPoint:textfield.bounds.origin toView:self.view];
int movementDistance;
CGPoint point = [_mainScrollView contentOffset];
//Push up only when blocked by keyboard
if (windowPoint.y + textfield.frame.size.height >= self.view.frame.size.height - _keyboardHeight) {
movementDistance = windowPoint.y - (self.view.frame.size.height - _keyboardHeight) + textfield.frame.size.height + 10;
_oldMovementDistance = movementDistance;
int movement = (up ? -movementDistance : movementDistance);
[_mainScrollView setContentOffset:CGPointMake(0, point.y - movement) animated:YES];
}
else { //Push view down the same amount
int movement = (up ? -movementDistance : _oldMovementDistance);
[_mainScrollView setContentOffset:CGPointMake(0, point.y - movement) animated:YES];
_oldMovementDistance = 0;
}
}
move UITextField and UITextView out of the way of the keyboard during editing:
For non-UITableViewControllers, drop the TPKeyboardAvoidingScrollView.m and TPKeyboardAvoidingScrollView.h source files into your project, pop a UIScrollView into your view controller's xib or storyboard, set the scroll view's class to TPKeyboardAvoidingScrollView, and put all your controls within that scroll view. You can also create it programmatically, without using a xib - just use the TPKeyboardAvoidingScrollView as your top-level view.
For use with UITableViewController classes, drop TPKeyboardAvoidingTableView.m and TPKeyboardAvoidingTableView.h into your project, and make your UITableView a TPKeyboardAvoidingTableView in the xib. If you're not using a xib with your controller, I know of no easy way to make its UITableView a custom class: The path of least resistance is to create a xib for it.
You can get reference from here.
Hope this helps.
This is written in Swift 2 in Xcode 7.
I have a UIView, which originally is set to be below the screen. Upon being triggered, it should slide up from the bottom of screen. This is the code for the animation:
func durationView(sender: UIButton){
let heightOffset = self.durationNotificationContainerView.frame.height
self.durationNotificationContainerView.translatesAutoresizingMaskIntoConstraints = false
UIView.animateWithDuration(0.2, animations: {self.durationNotificationContainerView.frame = CGRectMake(self.durationNotificationContainerView.frame.origin.x, self.durationNotificationContainerView.frame.origin.y + heightOffset, self.durationNotificationContainerView.frame.width, self.durationNotificationContainerView.frame.height)})
}
What happens right now is when I press the UIButton that triggers this view, it slides up and then immediately back down (to outside of the screen). I should also point out that in my storyboard I have some views added manually with AutoLayout constraints, so I don't know if that's what is messing up my animation.
In Autolayout, constraints need to be changed and updated in the the animation as seen below:
- (IBAction)moveAction:(id)sender {
self.spaceConstraint.constant += 220;
[UIView animateWithDuration:0.5 animations:^{
[self.imageView layoutIfNeeded];
}];
}
I am trying to make a UITableView appear when a user taps on a button and disappear when the button is re-tapped.
I implemented the following code but nothing seems to appear when I tap the button.
- (IBAction)dropDown:(UIButton *)sender
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.6];
CGAffineTransform transfrom = CGAffineTransformMakeTranslation(0, 200);
self.markersTableView.transform = transfrom;
self.markersTableView.alpha = self.markersTableView.alpha * (-1) + 1;
[UIView commitAnimations];
}
What may potentially be the issue?
EDIT:
I was able to make the UITableView appear and disappear by adding self.markersTableView.hidden = YES; in viewDidLoad() and self.markersTableView.hidden = NO; in the IBAction method.
However, the table view disappears when I initially tap on the button as shown in the screenshot:
The fading of the rows is an indication it is moving down the screen, and then it disappears.
It only reappears when I re-tap on the UIButton the 2nd time.
Any clues?
Don't use a transform on your table view. That will make it LOOK like it's in a different position, but it won't respond to taps correctly.
Instead, use the newer UIView block-based animation methods and change the view's center.
The code might look like this (if you're NOT using auto-layout)
[UIView AnimateWithDuration: .2
animations: ^
{
CGPoint center = self.markersTableView.center;
center.y += 200;
self.markersTableView.center = center;
}
];
If you're using auto-layout, though, that won't work and you will need to animate the view's position using constraints.
From memory, here's an outline of how to do auto-layout based animations: You would create a vertical position constraint on your table view and connect the constraint to an IBOutlet in your view controller. In your animation code you change the constant of the constraint (the vertical position) and then in the animation block, send the view a needsLayout message.
I have a problem with a uiview that placed in story board in one position and after the app start I move the uiview to second position with animate With Duration with a button from code.
int alpha = -212;
if(!flag)
{
alpha = 212;
}
[UIView animateWithDuration:0.8 animations:^(void)
{
keyboardView.frame = CGRectMake(keyboardView.frame.origin.x, keyboardView.frame.origin.y + alpha, keyboardView.frame.size.width, keyboardView.frame.size.height);
}
completion:nil];
After I do something like reload label or change something in text filed the
uiview back to story board position.
labelTest1.text = tempTextFiled;
[textField setText:tempTextFiled];
How can I keep the uiview stay in the second position ?
Try to create this view without the storyboard (code only). this will fix your issue.