I would like to increase the keyboard height use in your code by 30. I have a toolbar over my keyboard. I play around with the code but I couldn't make it work. the toolbar over keyboard hides the last cell. I changed this line of code:
if ( offset != -1 ) {
[self setContentOffset:CGPointMake(self.contentOffset.x, offset+30) animated:YES]; // this one
}
I works but the rest of the cell don't get center anymore when clicking on it.
Where in your code is the height of the keyboard?
For that, first you have take scroll view. And add table view inside the scroll view.
After that, you have set scroll view height accordingly.
Like Below:
[scrlPage setFrame:CGRectMake(scrlPage.frame.origin.x, scrlPage.frame.origin.y, scrlPage.frame.size.width, 361.0-150.0)];
[scrlPage setContentSize:CGSizeMake(scrlPage.frame.size.width, 361.0)];
[scrlPage setContentOffset:CGPointMake(0.0, 50.0)];
Hope you will get it.
Though let me know in case of any difficulty.
Related
I have a tableview with a textview for entering text immediately below it similar to Apple Messages. When the user begins to enter text and the keyboard appears, I want the following behavior similar to IOS Messages.
If the keyboard will not cover anything, the visible part of the tableview remains unchanged.
If the keyboard will cover something, the tableview moves up just enough so that its bottom-most filled cell is just above the keyboard.
Because I'm using autolayout, I currently have a constraint between the tableview and the textview below it. Also, the project has IQKeyboard which manages a lot of other views involving textfields and textviews.
The constraint combined with IQKeyboard accomplishes 2. When the keyboard appears, the keyboard pushes the textview up. The textview pushes the tableview up. So if the tableview is fully populated, you see the last cell of the tableview above the textview above the keyboard as desired.
However, 2. is not working.
if the tableview is not filled, the keyboard pushes up the textview which pushes up the tableview so that you longer see the top of the tableview.
I have tried adjusting the contentOffset property of the tableview when the Keyboard Shows and this sort of works but the tableview initially moves up before coming back down. I think this is because the notification to change the offset property does not fire until after the keyboard has begun to move up.
I also tried adjusting the tableview height to its content but this causes the textview to expand to fill the difference due to constraints.
Content offset approach - problem is that content offset adjusts too late
//register for keyboard notifications and in handler:
if let infoKey = notification.userInfo?[UIKeyboardFrameEndUserInfoKey],
let rawFrame = (infoKey as AnyObject).cgRectValue {
let keyboardFrame = view.convert(rawFrame, from: nil)
self.heightKeyboard = keyboardFrame.size.height
UIView.animate(withDuration: 0.2, animations: {
self.tableView.contentInset = UIEdgeInsetsMake(self.heightKeyboard!, 0, 0, 0);
})
}
Can anyone suggest a way to mimic the behavior of Apple Messages? Thanks in advance for any suggestions.
One approach:
constrain the top of the tableView to the top of the view
constrain the bottom of the tableView to the top of the textField
constrain the bottom of the textField to the bottom of the view
create an #IBOutlet for the textField's bottom constraint
When the keyboard is shown, change the .constant of the textField's bottom constraint to the height of the keyboard view.
This will move the textField up, and because it's top is constrained to the bottom of the tableView, it will also move the tableView's bottom edge up.
Then scroll to the bottom of the tableView.
Layout:
Initial hierarchy, with 20 rows (scrolled to the bottom):
Hierarchy view (tableView background color set to green, so we can see its frame):
View after the keyboard is shown:
Hierarchy after the keyboard is shown:
Little tough to see from static screen caps, but the frame of the green rectangle (the tableView background) is now shorter... the user can still scroll up and down to see all the rows, but the bottom of the tableView is still constrained to the top of the textField.
When you the keyboard is dismissed, set the .constant of the textField's bottom constraint back to Zero.
You can see a full, working example project up on GitHub: https://github.com/DonMag/KBAdjust
I've got a view that has 3 tableView's. One is the "Main Table View", and then I have an 'Answers Table View' and 'Percentage Table View'.
When the screens loads, the Main Table View occupies the top 95% of the screen. The bottom of the screen is a UIView containing 2 buttons. "Answers" and "Percentage".
The way it works, is if I click "Percentage" it changes the height of the Main Table View to 0, and gives that height to the Answers Table View. This animates the "Answers/Percentage" View to the top, and reveals either the Answers or Percentage TableView below it.
Here's an example:
As you can see, I click on "Percentage" which animates it up. If you click on "Percentage" again it animates it back down.
However, what I want to do is if the "Answers/Percentage" view is at the bottom of the View, and the user scrolls the Main Feed UP reaches the very end of the tableView's contents (not just the end, but the end and a little bit more), I want to animate it up like in the .gif.
Similarly, if the "Answers/Percentage" is at the top, and the user scrolls the lower "Answers Table View" down past a certain point where there is no more data above, it will completely animate.
Also, I do not ever want the "Answers/Percentage" view to be in the middle, and showing a tableview both top and bottom. All one, or the other, but not a bit of both. Which I have right now.
What I need to know is... how can I detect if the user has scrolled past the very top or very bottom of the table view +30 pixels for example, to initiate my animation?
You can use the contentOffset property of the table view.
if(tableView.contentOffset.y >= (tableView.contentSize.height - tableView.frame.size.height)) {
// Start the animation
}
I haven't tested this, but let me know if it works.
Making another answer based on sublimepremise's approach because it's easier to format and post code that way. The base idea is to check the table view's .contentOffset.y, e.g. by implementing scrollViewDidScroll in its delegate, and triggering your animations accordingly.
It may have a bit of a QnD feel to it, but if you need to also abort the user's dragging action when triggering the animation, an easy way to do so would be by "resetting" the table view's gesture recognizer. In code that could look something like this:
static const CGFloat kChrisTableViewAnimationThreshold = 30.0f;
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == self.topTableView) {
if([self scrolledPastBottomThresholdInTableView:self.topTableView]) {
// Start the animation
// ...
// Toggling the table view's pangGestureRecognizer off and on cancels the gesture
self.topTableView.panGestureRecognizer.enabled = NO;
self.topTableView.panGestureRecognizer.enabled = YES;
}
}
}
- (BOOL)scrolledPastBottomThresholdInTableView:(UITableView *)tableView {
return (tableView.contentOffset.y - kChrisTableViewAnimationThreshold >= (tableView.contentSize.height - tableView.frame.size.height));
}
Note that this illustration obviously only covers recognizing when the top table view is scrolled past its bottom end, but adapting it for handling other scenarios should be pretty straightforward.
I have two questions related to UITableViews.
1) The first one is, what is the gap at the top of the UITableView? My app always starts with the top cell not flush with the top of the tableview (as shown in the second image), it starts about one cell lower, i.e. where that gap is in the interface builder. I can't find where that is coming from, or why.
2) I can't seem to resize the uitableview programmatically, I'm trying to reduce the height after a popup appears. I've shown an example of it not working in the second picture.
Here is (an example of) what I am trying at the moment:
- (void)viewDidLoad
{
[super viewDidLoad];
self.table_view.delegate = self;
CGRect tableBounds = self.table_view.bounds;
tableBounds.size.height -= 100;
self.table_view.bounds = tableBounds;
CGRect tableFrame = self.table_view.frame;
tableBounds.size.height -= 100;
self.table_view.frame = tableFrame;
}
Thanks!
UITableView Selected:
Simulation:
In your xib (or storyboard) put your UITableView at position (0,0). ( the same position as the navigation bar).
The first image shows that your table view has problems even in Interface Builder. It looks as if you've set the top inset incorrectly; check your edge insets.
The reason your resizing code is not working is probably that it is too early (viewDidLoad); put it in viewDidAppear: and see if that works, and if it does, try moving it back to viewWillAppear: so the user doesn't see the resizing. If it doesn't work, it might be because you're using auto layout; you can't manually alter the frame of something whose frame is dictated by auto layout. (Your resizing code is also silly; you want to set the frame, not the bounds.) But it might also be because you're using a UITableViewController in a UINavigationController; if you do that, the table view is under the navigation controller's direct control and its size is not up to you.
I have tableview and several controls (text fields, buttons and labels) beneath it.
When keyboard shows up I can either reduce parent view height or slide it up so my controls are accessible.
That part works fine.
However I want to adjust tableview also, so I tried reducing its height (if I reduce the height of the parent view) or moving down the origin.y coordinate (if I slide parent view up).
Neither worked, i.e. tableView would not change to the new frame, it stays the same. Tableview only resizes if I do not manipulate parent view, i.e. if I adjust tableView frame alone.
Here is the methods for that:
-(void)resizeTbl:(int)pnts{
CGRect tblframe = self.myTable.frame;
//tblframe.origin.y+=pnts;
tblframe.size.height-=pnts;
self.myTable.frame =tblframe;}
-(void )keyboardWillShow:(NSNotification *)notif{
int pnts=160;
CGRect frame = self.view.frame;
//frame.origin.y-=pnts;
frame.size.height-=pnts;
self.view.frame = frame;
[self resizeTbl:pnts];}
I probably could move all the controls up one by one and then table resize would work but I think there should be an easier way. Any advice would be greatly appreciated.
Update/workaround:
Since table resize works alone just fine, I added one more observer - keyboardDidShow, and moved resize myTable from keyboardWilShow into there to take care of tableview after keyboard is up.
-(void)keyboardDidShow:(NSNotification *)notif{
[self resizeTbl:160];}
So all the views come up as they are supposed to now.
However, when focus moves from one textbox to another with the keyboard already up, tableView resizes to its original frame by itself and I cannot catch when and how that does it. And then, when keyboard goes down tableView expands beyond its original frame, because I must have
-(void)keyboardDidHide:(NSNotification *)notif{
[self resizeTbl:-160];}
However, when focus changes again tableView shrinks back to its normal frame and everything looks just fine. If I could somehow prevent those unwanted tableview resizes that mess things up.
If someone could makes sense out all of this I would be very appreciative.
Update:
I got it. Autolayout was messing me up. I turned it off like that and my logic now works, no glitches.
What is the autoResizingMask of the view set to?
Try this when you initialize the table view.
self.myTable.autoresizingMask = UIViewAutoresizingFlexibleHeight;
This will cause the table view to be resized with its parent view.
You can't change self.view.frame. You should have a container view above self.view that holds self.myTable and all other controls you want. self.myTable and other controls should have the correct autoresizingMask.
When keyboard is shown, you resize the container view and all other views will respect their autoresizingMasks.
-(void )keyboardWillShow:(NSNotification *)notif{
int pnts=160;
CGRect rect = self.view.bounds;
rect.size.height-=pnts;
self.containerView.frame = rect;
// the following should not be needed if self.myTableView.autoresizingMask
// is at least UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleTopMargin
// but you can try adding this
self.myTableView.frame = self.containerView.bounds;
}
I am using a scroll view that contains a couple of text field. When the text field "begins editing", I perform 3 operations:
I change the scroll view content inset (so that the whole view becomes apparent above the keyboard). I only do that if it's not fixed already to this content inset.
I also change the scroll indicator inset to match the one in 1.
Finally, I change the scroll view content offset to some specific value.
However, a strange thing happens. Once I tap the text field, the scroll view animates to a content offset larger than the specific value, then immediately back to that specific value.
I suspected that both step 1 and 2 are the reasons for that so I excluded them and everything works just fine. However, this left me with part of the scroll view hidden below the keyboard.
EDIT: Here is the code I use (called when the text field starts editing):
UIScrollView *scrollView = (UIScrollView *) self.view;
if (scrollView.contentInset.bottom != C_SCROLL_VIEW_CONTENT_INSET_BOTTOM) {
[scrollView setContentInset:UIEdgeInsetsMake(C_ORIGIN_ZERO,
C_ORIGIN_ZERO,
C_SCROLL_VIEW_CONTENT_INSET_BOTTOM,
C_ORIGIN_ZERO)];
[scrollView setScrollIndicatorInsets:UIEdgeInsetsMake(C_ORIGIN_ZERO,
C_ORIGIN_ZERO,
C_SCROLL_VIEW_CONTENT_INSET_BOTTOM,
C_ORIGIN_ZERO)];
}
if (textField.tag == C_TAG_BUTTON) {
[scrollView setContentOffset:CGPointMake(C_ORIGIN_ZERO, C_ORIGIN_SHIFT_SCROLL_VIEW_FOR_CURRENT_Y)
animated:YES];
return;
}
Assuming that C_SCROLL_VIEW_CONTENT_INSET_BOTTOM is your constant, I think that value is wrong (too big).