UITextView in UITableViewCell scroll to location - ios

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;
}

Related

Auto Size cell based on UITextView

I have a UITextView in a UITableViewCell in the storyboard. I then added a constraint on all 4 sides of the UITextView.
In the code below I tried making the textView dynamically change as the user enters text. I'm pretty sure that worked successfully. But the problem is the cell is not. Bellow is the code I tried, without success.
-(void)viewDidLoad
{
tableView.rowHeight = UITableViewAutomaticDimension;
tableView.estimatedRowHeight = 44;
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if (textView == myTextView)
{
[self textViewFitToContent:myTextView];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[[NSIndexPath indexPathForItem:1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
}
return YES;
}
- (void)textViewFitToContent:(UITextView *)textView
{
CGFloat fixedWidth = textView.frame.size.width;
CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
CGRect newFrame = textView.frame;
newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
textView.frame = newFrame;
textView.scrollEnabled = NO;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return myTextView.frame.size.height + 40;
}
I'm a beginner so please don't be too harsh on me.
Thanks
Your code is fine, flawless infact and quite well done. Without seeing your declared variables, I believe the reason that the cell isn't resizing is because you're heightForRowAtIndexPath method is returning the height of the wrong UITextView. Instead of txtSymptoms which isn't used anywhere else in the resizing code, you should be using myTextView instead, which, when the user edits the text of, will trigger the tableView to reload.
This snippet of yours:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return myTextView.frame.size.height + 40;
}
From the rest of your code, myTextView seems to be a special text view that you are adding text to and resizing, but this method uses that larger height for sizing, which is why all of your cells grow taller.
In the storyboard, select your text view and in the size inspector look for the content hugging priority option.
Content hugging priority can range from 0 to 1000.
Keep the content hugging priority of your text view (for vertical section especially) higher than the content hugging priority of the content view of the cell in which the text view resides.

UICollectionView with spacing between cells has scrolling issues

i have a collection view, with cells in a size of the all screen.
i'm trying to add spacing between the cells, so when ever i scroll between the cells there will be some space between - as in the iOS photo gallery, when you scroll between full screen images.
obviously i have paging enabled.
but for some reason when i scroll between the cells, the spacing is staying on the screen.
i.e. if the cell width is 320, and the space between the next cell is 20px, so when i scroll to the next cell, the space is reaching to x=0, and the new cell starts at x=20.
why is that?
how do i get the exact iOS photo gallery scrolling full screen images effect?
increase the width of the collection to the space value and shift collection left to the half space value. then change right and left section insets to the half space value
or you can make your own paging that will works even if cell size are less then collection view:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
CGPoint contentOffset = scrollView.contentOffset;
CGSize size = scrollView.frame.size;
CGPoint locationInView = CGPointMake(contentOffset.x + size.width/2, contentOffset.y + size.height/2);
if (scrollView == _collectionView) {
NSIndexPath *indexPath = [_collectionView indexPathForItemAtPoint:locationInView];
[_collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
[self collectionView:_collectionView didSelectItemAtIndexPath:indexPath];
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (!decelerate) {
[self scrollViewDidEndDecelerating:scrollView];
}
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
}

UITableView selected row in the middle of frame

I need to have the possibility to put the selected line on the middle of frame. So if I select the first or the last row, this row needs to be on the center and not clipped to the top (or to the bottom) of the tableview (something like an UIPickerView).
This is my code on scrollViewWillEndDragging:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset {
CGFloat rowHeight = [delegate rowHeightForMyPickerView:self];
CGFloat floatVal = targetContentOffset->y / rowHeight;
NSInteger rounded = (NSInteger)(lround(floatVal));
targetContentOffset->y = rounded * rowHeight;
NSLog(#"Offset: %f Float: %f Row: %d",targetContentOffset->y,floatVal,rounded);
[delegate myPickerView:self isOverRow:rounded];
}
With this code, I create snap effect but rounded is not the correct row. Changing the first and last cell height with a double height makes the problem disappear but I don't like that solution.
The UITableView class can scroll to the selected indexPath, with animations as well, using scrollToRowAtIndexPath:atScrollPosition:animated method. Preferably in the tableView:didSelectRowAtIndexPath:indexPath method, add:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; //scrolls the selected cell to middle
}

Get position of cell or text field in this cell

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

UITableView with UITextView scrolling issue

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];
}
}

Resources