I have a split view controller: view & tableview. In this table view I have custom cells with text field. I don't know how many cells will I have, so it generate automatically. And now I'm trying scroll to textfield, when it becomeFirstResponder. I've tried something like this:
-(void) textFieldDidBeginEditing:(UITextField *)textField {
CGPoint focusOnTextField = CGPointMake(0, 300 + textField.frame.origin.y);
[scroller setContentOffset: focusOnTextField animated: YES];
}
300px - start position of my TableView. All seems alright, but textField.frame.origin.y always equal to 0 (like and bounds.origin.y btw).
I thought I can solve a problem if get position of cell, which textfield is active, and then replace textField.frame.origin.y on cell.frame.origin.y or something like this.
===================================================================
I forgot say that my tableviews scroll is disabled. I follow your advices and code examples and solve it like that:
- (UITableViewCell *)cellWithSubview:(UIView *)subview {
while (subview && ![subview isKindOfClass:[UITableViewCell self]])
subview = subview.superview;
return (UITableViewCell *)subview;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
UITableViewCell *activeCell = [self cellWithSubview:textField];
float offsetValueY = 200 + activeCell.origin.y;
CGPoint focusOnTextField = CGPointMake(0, offsetValueY);
[scroller setContentOffset:focusOnTextField animated:YES];
}
And know what? It's working! :-) But it create a new problem. When I begin editing textfield, scroller at first jump on top, and only then going to it correct position. When I write [scroller setContentOffset:focusOnTextField animated:NO]; and this problem disappear, but there is no smooth move of scroller. And this is bad to me :-) So how we can solve it?
Here's how to scroll to a cell containing a text field ...
// find the cell containing a subview. this works independently of how cells
// have been constructed.
- (UITableViewCell *)cellWithSubview:(UIView *)subview {
while (subview && ![subview isKindOfClass:[UITableViewCell self]])
subview = subview.superview;
return (UITableViewCell *)subview;
}
Your idea is correct to trigger that action when editing begins. Just do it using the cell...
- (void)textFieldDidBeginEditing:(UITextField *)textField {
// find the cell containing this text field
UITableViewCell *cell = [self cellWithSubview:textField];
// now scroll using that cell's index path as the target
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
If you add the textfield in the UITableVieCell content view (added by default if you are using .xib) then you have to call something like textField.superview.superview and this will give you the parent cell. If you add the text field directly to the cell view then you have to textField.superview.
[tableView scrollToRowContainingComponent:textField atScrollPosition: UITableViewScrollPositionMiddle animated:YES];
after adding the following category to UITableView:
#implementation UITableView (MyCategory)
-(NSIndexPath*)indexPathOfCellComponent:(UIView*)component {
if([component isDescendantOfView:self] && component != self) {
CGPoint point = [component.superview convertPoint:component.center toView:self];
return [self indexPathForRowAtPoint:point];
}
else {
return nil;
}
}
-(void)scrollToRowContainingComponent:(UIView*)component atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated {
NSIndexPath *indexPath = [self indexPathOfCellComponent:component];
if(indexPath) {
[self scrollToRowAtIndexPath:indexPath atScrollPosition: scrollPosition animated:animated];
}
}
#end
Related
When I add a UILongPressGestureRecognizer on my collectionView (I'm doing it like in this answer), the collection view stops highlighting cells as expected.
I'm handling the cell highlighting in my UICollectionViewCellSubclass, like it's explained in this answer:
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
if (self.highlighted) {
//Here I show my highlighting layer
}
else {
//Here I hide my highlighting layer
}
}
- (void)setHighlighted:(BOOL)highlighted
{
[super setHighlighted:highlighted];
[self setNeedsDisplay]; //This call draw rect and show/hide the highlighting layer
}
The problem seems to be that, when I add the UILongPressGestureRecognizer gesture on the collection view, drawRect is not being called after setting highlighted to YES.
If I move the logic to show my highlighting layer in setHighlighted:YES, I can't see the touching-feedback because setHighlighted:NO its being called immediately after! (This happens only after adding the UILongPressGestureRecognizer).
I've also tried to move the logic in touchesBegan/touchesEnded but then didSelectRowAtIndexPath: doesn't work anymore.
Unfortunately, it looks like the UILongPressGestureRecognizer is blocking the touches required for the UICollectionView to highlight the cell. It doesn't look like there is a good way to forward the touches, so I'd imagine you will have to handle the highlighting manually if you want that to appear. You could do it through a separate method than setHighlighted, or try to use the cell.highlighted property to do your drawing.
Here is an example I came up with that worked for my UICollectionView
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
// if (gestureRecognizer.state != UIGestureRecognizerStateEnded) {
// return;
// }
CGPoint p = [gestureRecognizer locationInView:self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:p];
if (indexPath == nil){
NSLog(#"couldn't find index path");
} else {
// get the cell at indexPath (the one you long pressed)
UICollectionViewCell* cell = [self.collectionView cellForItemAtIndexPath:indexPath];
if (gestureRecognizer.state != UIGestureRecognizerStateEnded) {
if (!cell.highlighted) {
[cell setHighlighted:YES];
}
return;
}
[cell setHighlighted:NO];
// do stuff with the cell
}
}
I have a UITableViewController in which I am using Static Cells that are grouped. Each cell has a UITextField for users to enter info, and at the bottom is a submit button. Upon tapping the button, I verify that they have entered info for each of the fields and if not, I scroll up to that cell/field so that they can complete it.
However, for some reason it is not scrolling to the correct cell when using scrollToRowAtIndexPath:
#pragma mark - Save
- (IBAction)didTapSaveGuestDetails:(ZSSBottomOverlayButton *)sender {
[self checkForFormSubmissionErrors];
}
- (void)checkForFormSubmissionErrors {
// First Name
if (self.nameFirst.text.length == 0) {
[self showAlertWithMessage:NSLocalizedString(#"* Please enter first name", nil) fieldToHighlight:self.nameFirst];
return;
}
[self.view endEditing:YES];
[self submitUpdatedGuestInfo];
}
- (void)submitUpdatedGuestInfo {
}
#pragma mark - Alert
- (void)showAlertWithMessage:(NSString *)message fieldToHighlight:(UIView *)field {
UIColor *redColor = [OTAColors colorWithRed:234 green:85 blue:58];
[RKDropdownAlert title:message backgroundColor:redColor textColor:[UIColor whiteColor] time:2.0];
if (field) {
[self highlightField:field];
}
}
- (void)highlightField:(UIView *)field {
[self.tableView endEditing:YES];
// Color field
if ([field isKindOfClass:[ZSSLargeTextField class]]) {
ZSSLargeTextField *textField = (ZSSLargeTextField *)field;
[textField showWarning];
}
CGPoint pointInTable = [field convertPoint:field.bounds.origin toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:pointInTable];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
This exact implementation works great when using prototype cells, but NOT static.
However, if I use the following it does scroll to the correct cell:
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0] atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
So, it seems the issue could be in my convertPoint:toView: method?
Any idea what could be preventing it from scrolling to the correct cell?
I have a UIDatePicker in a static UITableViewCell with auto layout applied (to the datePicker). The datePicker is hidden until a button is selected. When the button is selected, the datePicker becomes visible, and the cells height gets bigger.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 1)
{
if (self.datePickerView.hidden == YES) {
return 252 - self.datePickerView.bounds.size.height;
}
else return 252;
}
tableView.estimatedRowHeight = 150;
return UITableViewAutomaticDimension;
}
- (IBAction)datePicker:(id)sender
{
if (self.datePickerView.hidden == YES)
{
[self.datePickerView setHidden:NO];
CGFloat originalHeight = 162;
[self.datePickerView setFrame:CGRectMake(self.datePickerView.frame.origin.x, self.datePickerView.frame.origin.y, self.datePickerView.frame.size.width, 0)];
[UIDatePicker animateWithDuration:1.0 animations:^(){
[self.datePickerView setFrame:CGRectMake(self.datePickerView.frame.origin.x, self.datePickerView.frame.origin.y, self.datePickerView.frame.size.width, originalHeight)];
}];
} else {
[self.datePickerView setHidden:YES];
}
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
When the button gets selected, the cells height is animated, but the datePicker isn't. It just appears, and gets in the way of everything until the cell is finished animating.
How can I get the datePicker to animate its height, so it should animate together with the cell?
Updating frames would not work with auto-layout. you'll have to update your constraint to do the animation.
In your case, you should have separate cell for your datePickerview and insert/ remove the cell from your tableview in order to hide and show the pickerview with animation.
[Edited]
Sample Code here: http://www.filedropper.com/tableviewsample
I have a UITextView in a UITableViewCell. They both dynamically size itself to fit. The problem I have is that when the texview reaches below the bottom of the screen (from making new lines), the tableView does not scroll to its location.
I tried this code, but it didn't work.
- (void)textViewDidChangeSelection:(UITextView *)textView {
[textView scrollRangeToVisible:textView.selectedRange];
}
You can find the cell containing the textView and tell the table view to scroll to that cell:
UIView *parentView = textView.superview;
while(![parentView isKindOfClass:[UITableViewCell class]]) {
parentView = parentView.superview;
}
NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell*)parentView];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
You should add code below to scroll the tableView too:
- (void)textViewDidChangeSelection:(UITextView *)textView {
[textView scrollRangeToVisible:textView.selectedRange];
// since you are only scrolling the table a little bit and not by a whole cell, then change the scrollView.offset
CGPoint offset = tableView.contentOffset;
offset.x += 20; // an example. You need to change this based on the new size of the textview.
tableView.contentOffset = offset;
}
I have composed a tableview with some custom cells. Some of the custom cells contain UIWebView, some has UISlider plus UITextField, some has UIButton.
Now when I click on textfield which is uitableviewcell's subview at the bottom of the UITableView, I can't manage to get my table cell properly visible above the keyboard.
Using of UITableViewController instead of UIViewController is not possible for me. Because my UI structure is somewhat weird and dynamic. In simple way it is like
UIView -> UIScrollView with paging -> x number of UITableViews -> y number of UITableViewCell -> z number of UITextFields, UISliders, UIWebViews, UIButtons, UILables, etc.
I have also tried below code to make it work.
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
[table_Question[pageNumber] scrollToRowAtIndexPath:[table_Question[pageNumber] indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
but it is not working :(
Thanks,
EDIT 1:
I have checked references for textfield, tableviewcell and tableview. So reference of object is not the problem.
Try this code....
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
NSIndexPath *indexPath = [[table_Question[pageNumber] indexPathForCell:cell];
int totalRows = 0;
if([[table_Question[pageNumber] numberOfSections] > 1)
{
for(int i = 0; i<([indexPath.section] - 1);i++)
{
totalRows += [[table_Question[pageNumber] numberOfRowsInSection:i];
}
}
totalRows += indexPath.row;
int yPosition = totalRows * cell.frame.size.height;
CGPoint offset = CGPointMake(0, yPosition);
[[table_Question[pageNumber] setContentOffset:offset animated:YES];
}
This will helps for you...
Try this code
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
UITableViewCell *aCell = [table_Question[pageNumber] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]];
CGSize cellSize = aCell.frame.size;
[table_Question[pageNumber] setContentOffset:CGPointMake(0, cellSize.height*2) animated:YES];
}
As per my understanding, you want to show the UITextField as well as the keyboard, when the user starts editing the UITextField inside the UITableViewCell.
If that's the case, you can set the contentInset of the UITableView to the required size and then just scroll to the required index path.
Following is a sample code:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
#try
{
table_Question[pageNumber].contentInset = UIEdgeInsetsMake(CGFloat Req_top, CGFloat Req_left, CGFloat Req_bottom, CGFloat Req_right);
[table_Question[pageNumber] scrollToRowAtIndexPath:[table_Question[pageNumber] indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
//Add this to you code to scroll in the tableview gets hidden by keyboard
CGPoint scrollPoint = CGPointMake(0, Required_Height);
[yourScrollView setContentOffset:scrollPoint animated:YES];
}
}