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
}
Related
1.When the content inside the cell is too long, cell expansion, Or then shrink, UITableView will scroll to the back of the cell position.
2.I want cell to roll back to where it started expansion.
my code:
((PartnershipsTableViewCell *)cell).commentSpreadButtonClickHandler = ^() {
// just call - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
[weakSelf.tableView beginUpdates];
[weakCell configUI];
[weakSelf.tableView endUpdates];
// if here use "[weakSelf.tableView reloadData]",
// it can be correct,
// Unless on the first cell which have the expansion button.
};
then update uitableview cell's height. but the result isn't what i want
- (void)configUI {
if ([self.baseModel isKindOfClass: [UserWorldDynamicModel class]]) {
self.model = (id)self.baseModel;
}
[self setupValue];
}
- (void)setupValue {
// setup the property value, and update the constraints with masonry
}
// the button : read less or read more
- (void)setSpreadButton {
NSString *text = self.model.isContentOpen ? #"read less" : #"read more";
if (!self.spreadButton) {
self.spreadButton = [MYSUtil createButtonWithTitle: text target: self sel: #selector(spreadButtonClick:) image: nil font: Font14 color: DarkBlueTextColor cornerRadius: 0];
self.spreadButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
}
if (self.model.shouldShowSpreadButton) {
if (!self.spreadButton.superview) {
[self.whiteBackgroudView addSubview: self.spreadButton];
}
[self.spreadButton setTitle: text forState: UIControlStateNormal];
self.spreadButton.selected = [self.model.isSpreadState intValue];
self.spreadButton.frame = CGRectMake(CGRectGetMinX(self.contentLabel.frame), CGRectGetMaxY(self.contentLabel.frame), 80, 30);
self.tempView = self.spreadButton;
} else {
if (self.spreadButton.superview) {
[self.spreadButton removeFromSuperview];
}
}
}
// calculate the height of the label and compare it with the fixed value
NSMutableAttributedString *string = [self createMutableAttibuteStringWithNSString: text withFont: font];
self.contentLabel.attributedText = string;
// here calculate maxContentLabelHeight with
CGFloat maxContentLabelHeight = self.contentLabel.font.pointSize * (numberOfLines + 1) + 16;
// here calculate the NSMutableAttributedString's height
YYTextContainer *container = [YYTextContainer containerWithSize:CGSizeMake(width, MAXFLOAT)];
YYTextLayout *textLayout = [YYTextLayout layoutWithContainer:container text: string];
CGSize size = textLayout.textBoundingSize;
CGFloat height = size.height;
// then compare the NSMutableAttributedString's height with the fixed value. if true, show the spreadButton
if (height > maxContentLabelHeight) {
self.model.shouldShowSpreadButton = YES;
// storage the real height and temp height, use to calculate the tableView's contentOffset, when cell from expansion state to shrinking state in block.
self.model.contentHeight = height;
self.model.tempContentHeight = maxContentLabelHeight;
}
// if height > maxContentLabelHeight and the property "isContentOpen" of the viewModel, the height value is maxContentLabelHeight, Or not, the height value is height
if (!self.model.isContentOpen && height > maxContentLabelHeight) {
height = maxContentLabelHeight;
}
// no matter cell is expansion state or shrinking state, reset label's frame.
self.contentLabel.frame = CGRectMake(x, CGRectGetMaxY(self.headerImageView.frame) + Margin_Top, width, height);
readMoreļ¼ readLess block
before tableView reloadData on mainQueue, record it's contentOffset, Used to calculate the position of the tableView need to scroll. like this:
CGPoint point = weakSelf.tableView.contentOffset;
reloadData : refresh tableView On mainQueue.
when reloadData complete, scroll tableView to the position which expanded. when tableView from expansion state to shrinking state, and the height of expansion state is greater than 70% of the Screen's height, scroll the tableView (70% is ma condition, you can change is according to your condition)
- (UITableViewCell *)tableView:(UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath {
// here is your code
PartnershipsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: cellIdentifierString];
[cell config];
((PartnershipsTableViewCell *)cell).spreadButtonClickHandler = ^() {
CGPoint point = weakSelf.tb.contentOffset;
[weakSelf.tb reloadData];
if (!baseModel.isContentOpen && baseModel.contentHeight > SCREEN_HEIGHT * 0.7) {
point.y -= baseModel.contentHeight - baseModel.tempContentHeight;
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.tb.contentOffset = point;
});
}
};
return cell;
}
- (CGFloat)tableView:(UITableView *) tableView heightForRowAtIndexPath:(NSIndexPath *) indexPath {
return 70;
}
in my issue, I find a another interesting problem, when use the follow method in your code. if your cell have great changes, especially the height of the cell. when you use the method [tableView reloadData], you'd better not use the follow method.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 70;
}
then use the method [tableView reloadData] to refresh UI, tableView will scroll to any position, so I delete it. because, this method use to estimated height of cell, then use to estimate tableView's contentSize, if the height between estimated and actual is bigger difference, use the method [tableView reloadData], will cause the tableView scroll to anywhere.(don't ask me how to know, this is a painful process for me).
I have solved the problem, leave some notes to myself, and for every one, and hope my solution can help you too.
thanks for #pckill and #Theorist, without your suggestion, I can't solve my question so perfect, thank you very much.
#Theorist I have reedited my code in my mind. Perhaps, the readability is better now.
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 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];
}
hi iam developing a social networking application using UICollectionview horizontal layout, when ever my app launches collection view loads up to 5 cells then if i swipe 5th cell then that time only 6th cell memory will allocates. same way swipe 6th cell to 7 th cell like that.So,how can i implement this process
thanks in advance for any advices
You need to add a swipe gesture recognizer to your collectionView:
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeGesture:)];
swipeGesture.direction = UISwipeGestureRecognizerDirectionUp;
[collectionView addGestureRecognizer:swipeGesture];
Then, handle the swipe in handleSwipeGesture: to allocate the cell.
-(void) handleSwipeGesture:(UISwipeGestureRecognizer *) sender
{
...
}
You can make the swipe direction whatever you want to use, this one is configure for up.
That's pretty much all there is to it. Main thing is you don't want the direction to conflict with the scrolling direction swipe, as I don't think there is a clean way to deal with that. When you are scrolling horizontally, that is a swipe, so you would need to use up/down swipe direction.
To attach to the cell instead (to capture gesture on an individual cell) I do it most times for simple collectionviews in the following method:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
...
UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
[cell addGestureRecognizer:longPressGestureRecognizer];
...
}
(This is a long press, but it works the same way). In the case of putting it in the cell, you'll need to put a tag on the cell then reference that tag int the handler to figure out which cell it came from:
Here's one for the above:
- (void) handleLongPress: (UILongPressGestureRecognizer *) sender
{
if (sender.state != UIGestureRecognizerStateBegan)
return;
CGPoint p = [sender locationInView: collectionView];
NSIndexPath *indexPath = [collectionView indexPathForItemAtPoint:p];
if (indexPath != nil)
{
UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath];
if (cell)
{
int indexOfItem = cell.tag;
NSLog(#"Selected item = %d", indexOfItem);
}
}
At least something along this line...
You can achieve this by implement the UIScrollViewDelegate method
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint offset = scrollView.contentOffset;
CGRect bounds = scrollView.bounds;
CGSize size = scrollView.contentSize;
UIEdgeInsets inset = scrollView.contentInset;
float y = offset.x + bounds.size.width - inset.right;
float h = size.width;
float reload_distance = 75; //distance for which you want to load more
if(y > h + reload_distance) {
// write your code getting the more data
NSLog(#"load more rows");
}
}
in this when you go at the last cell of the collection then this scroll view delegate method will called.
and you may change the distance vale according to your requirement.
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];
}
}