Add read more to label and expanding UITableViewCell - ios

I am populating a UITableView with labels. How can i add a "read more" button at the end of the label only if the number of characters in that label exceed 120 and make the UItableViewCell expand to fit the new big label? Please help. (SWIFT)

I think you will have to manually adjust the string as it goes into the label, turn it into a NSAttributedString with 120 characters (with the ....) then append a NSLinkAttributeName for the read more part with a dummy URL, override textView shouldInteractWithURL and put expand function there (which should be just reload the cell with full string)

Just a Swift 3 version of #VRAwesome answer:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var height: CGFloat = 333
// assign initial height
let lblFrame = CGRect(x: CGFloat(40), y: CGFloat(50), width: CGFloat(194), height: CGFloat(50))
//assign initial frame
let strText = currentChallenge.description as NSString
let rect = strText.boundingRect(with: CGSize(width: lblFrame.size.width, height: CGFloat(Float.greatestFiniteMagnitude)), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
if rect.size.height > lblFrame.size.height || rect.size.height < lblFrame.size.height {
let diff = rect.size.height - lblFrame.size.height
height = height + diff + 20
}
if isRowOpen[indexPath.row] == true {
let rect = strSharedText.boundingRect(with: CGSize(width: lblFrame.size.width, height: CGFloat(Float.greatestFiniteMagnitude)), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
if rect.size.height > lblFrame.size.height || rect.size.height < lblFrame.size.height {
let diff = rect.size.height - lblFrame.size.height;
height = height + diff + 20;
}
}
return height
}

First calculate chars of string which you are going to assign to label. If that is more than 120 chars then create and add button(Read More) to the bottom right corner of cell.
And when press Read More then calculate size of string using boundingRectWithSize then reload that particular cell it will update size of cell.
Create one global boolean array :
bool isRowOpen[];
Your methods should be like :
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat height = 420; // assign initial height
CGRect lblFrame = CGRectMake(40, 50, 194, 50); //assign initial frame
NSString *strText = [someArray objectAtIndex:indexPAth.row];
CGRect rect = [strText boundingRectWithSize:CGSizeMake(lblFrame.size.width, FLT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil];
if (rect.size.height > lblFrame.size.height || rect.size.height < lblFrame.size.height) {
float diff = rect.size.height - lblFrame.size.height;
height = height+diff+20;
}
if (isRowOpen[indexPath.row] == TRUE) {
CGRect rect = [strSharedText boundingRectWithSize:CGSizeMake(lblFrame.size.width, FLT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil];
if (rect.size.height > lblFrame.size.height || rect.size.height < lblFrame.size.height) {
float diff = rect.size.height - lblFrame.size.height;
height = height+diff+20;
}
}
return height;
}
And last on Button Read More click event reload that particular cell. when you want expand, update isRowOpen[selectedRow] = TRUE. when you want collapse then again update isRowOpen[selectedRow] = FALSE. So it will show effect what you want.

Related

UITableView Dynamic Height not changing iOS

Drag and drop UITableViewHeader
You can look at an orange color UITextView.
I set the height constant of the tableview is zero.
After reloading the tableview total height of UITableView showing same as previous(as no UITextView showing)
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.heightConstCommentBox.constant = 0;
[self configureTableviewFooter];
}
-(void)configureTableviewFooter{
//More button Configure
height = 50 +[self recusiveDescription:self.viewFooter] ;
// Assign new frame
self.viewFooter.frame = CGRectMake(self.viewFooter.frame.origin.x,
self.viewFooter.frame.origin.y,self.viewFooter.frame.size.width , height); // viewFooter is container view of tableFooterView
self.tableView.tableFooterView = self.viewFooter;
[self.tableView reloadData];
}
- (float )recusiveDescription:(UIView *)view
{
NSString *s = #"";
float height = 0;
NSArray *subviews = [view subviews];
if ([subviews count] == 0) return 0;
for (UIView *subView in subviews) {
height = height + subView.frame.size.height ;
[self recusiveDescription:subView];
}
return height;
}
After reloading the tableview , table view footer size not changing.
In method recusiveDescription:(UIView *)view you use the frame property of the subview. But for the autolayout it is not correct. To get future size of the view, call:
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize
withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority
verticalFittingPriority:(UILayoutPriority)verticalFittingPriority;
This method returns the optimal size for the view based on the provided constraint priorities.
Also I did not understand why do you call recusiveDescription in recusiveDescription: and do not use result value.
u can use following in case u used custom cell for table.
in following code replace postss[index.row].post with your label content and +230 is minimum height of your cell.
or u can say its height of other view other than label.
automatic dimension method will work only if u have 1 label or 1 textfield,1 textview.
and don't fix your label's height.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let heightOfRow = self.calculateHeight(inString: postss[indexPath.row].post)
return (heightOfRow + 230)
}
//custom function for calculate dynamic height
func calculateHeight(inString:String) -> CGFloat
{
let messageString = inString
let attributes : [NSAttributedString.Key : Any] = [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 15.0)]
let attributedString : NSAttributedString = NSAttributedString(string: messageString, attributes: attributes)
let rect : CGRect = attributedString.boundingRect(with: CGSize(width: 370, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, context: nil)
let requredSize:CGRect = rect
return requredSize.height
}

GrowingTextView or expandable textview inside UItableview cell

I wish to implement an expandable textview inside the table cell, I found the GrowingTextView but I still failed to implement.I need to get input from user and the cell will auto resize when the users typing. Is there any easier implementation or guide on this? Thanks all
Actually you dont need 3rd party library to do this.
Change your GrowingTextView to UILabel
Config you UILabel to Top, Left, Right, and Bottom to the cell, and make "Title" label dependent on the UILabel
this is important because the cell size is dependant of the content of UILabel.
Set numberOfLines to 0 and
Set lineBreakMode to word wrapping or character warpping
Set tableView.rowHeight = UITableViewAutomaticDimension and tableView.estimatedRowHeight = 150 // or wtever you found reasonable
For task like these i suggest you can do more research on Internet instead of using a 3rd party library so fast, the keyword here is dynamic table view cell which by searching on Google there are lots of tutorials helping you out without using 3rd party library.
You can achieve it with native UITextView.
Implement this in the text view's delegate
- (void)textViewDidChange:(UITextView *)textView{
CGRect oldFrame = textView.frame;
CGSize constraint = CGSizeMake(yourTextViewWidth, MAXFLOAT);
CGRect rect = [textView.text boundingRectWithSize:constraint options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:textView.font} context:nil];
CGSize size = CGSizeMake(rect.size.width, rect.size.height);
[textView setFrame:CGRectMake(oldFrame.origin.x, oldFrame.origin.y, oldFrame.size.width, size.height + 5)];
// These 2 lines to force UITableView to redo the height calculation.
[self.yourTableView beginUpdates];
[self.yourTableView endUpdates];
}
Then, implement this in the table view's delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *yourTextViewText;
// You get the text either from the same way you did in cellForRowAtIndexPath dataSource
// or if you already referenced UITextView as your property you can easily retrieve the text by calling self.yourTextView.text
CGSize constraint = CGSizeMake(yourTextViewWidth, MAXFLOAT);
CGRect rect = [text boundingRectWithSize:constraint options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:[UIFont systemFontOfSize:yourFontSize]} context:nil];
CGSize size = CGSizeMake(rect.size.width, rect.size.height);
CGFloat height = MAX(size.height, yourDefaultCellHeight);
return height + 5;
}
UPDATE Swift version converted by Swiftify v4.1.6738 - https://objectivec2swift.com/
func textViewDidChange(_ textView: UITextView) {
let oldFrame: CGRect = textView.frame
let constraint = CGSize(width: yourTextViewWidth, height: MAXFLOAT)
let rect: CGRect = textView.text.boundingRect(with: constraint, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: textView.font], context: nil)
let size = CGSize(width: rect.size.width, height: rect.size.height)
textView.frame = CGRect(x: oldFrame.origin.x, y: oldFrame.origin.y, width: oldFrame.size.width, height: size.height + 5)
// These 2 lines to force UITableView to redo the height calculation.
yourTableView.beginUpdates()
yourTableView.endUpdates()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let yourTextViewText: String
// You get the text either from the same way you did in cellForRowAtIndexPath dataSource
// or if you already referenced UITextView as your property you can easily retrieve the text by calling self.yourTextView.text
let constraint = CGSize(width: yourTextViewWidth, height: MAXFLOAT)
let rect: CGRect = text.boundingRect(with: constraint, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: yourFontSize)], context: nil)
let size = CGSize(width: rect.size.width, height: rect.size.height)
let height: CGFloat = max(size.height, yourDefaultCellHeight)
return height + 5
}

Get height of UIView based on specific width before showing view

I have a UIView which I have designed in Interface Builder. It basically consists out of a header image and some text (UILabel) below. The view is being shown modally with a custom Transition and doesn't fill the whole screen.
There is like a 20 pixels margin on the left and right and 40 px on the top. The UILabel gets filled with some text that's coming from the web. What I want do do, is to find (or should I say predict) the height of the whole view for a specific width. How can I do that?
I had similar problem, but instead of calculating font size and image height you can use this UIView extension that will autosize your view with max width:
extension UIView {
func autosize(maxWidth: CGFloat) {
translatesAutoresizingMaskIntoConstraints = false
let dummyContainerView = UIView(frame: CGRect(x: 0, y: 0, width: maxWidth, height: 10000000))
dummyContainerView.addSubview(self)
dummyContainerView.topAnchor.constraint(equalTo: topAnchor, constant: 0).isActive = true
dummyContainerView.leftAnchor.constraint(equalTo: leftAnchor, constant: 0).isActive = true
dummyContainerView.rightAnchor.constraint(equalTo: rightAnchor, constant: 0).isActive = true
setNeedsLayout()
layoutIfNeeded()
removeFromSuperview()
frame = CGRect(x: 0, y: 0, width: frame.width, height: frame.height)
translatesAutoresizingMaskIntoConstraints = true
}
}
Using this approuch you don't have to worry about your content inside the view.
To use it:
let customView: CustomView = ... //create your view
... // configure all data on your view, e.g. labels with correct text
customView.autosize(maxWidth: 150) // resize your view
view.addSubview(customView) // add your view to any view
You need to have both the picture and the label before calculating the aspected size.
I guess you should use something like this (maybe adding the vertical inter-distance between the imageView and the Label to the sum, and maybe removing the lateral margins from the width):
objective C :
- (CGFloat)preferredHeightFromWidth:(CGFloat)width text:(NSString *)text font:(UIFont *)font image:(UIImage *)image
{
// Calculate label height
CGFloat labelHeight = [text
boundingRectWithSize:CGSizeMake(width, 10000)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:font}
context:[[NSStringDrawingContext alloc] init]
].size.height;
// Calculate image height
CGFloat ratio = image.size.height/ image.size.width;
CGFloat imageHeight = (ratio * width);
// Do the sum
return labelHeight + imageHeight;
}
Swift:
func preferredHeight(width: CGFloat, text: NSString, font: UIFont, image: UIImage) -> CGFloat {
// Calculate Label Height
let labelRect = text.boundingRect(
with: CGSize.init(width: width, height: 10000),
options: .usesLineFragmentOrigin,
attributes: [NSFontAttributeName : font],
context: NSStringDrawingContext())
let labelHeight = labelRect.height
// Calculate Image Height
let ratio = image.size.height / image.size.width
let imageHeight = ratio / width
// Calculate Total Height
let height = labelHeight + imageHeight
// Return Height Value
return height
}
(Thanks to Christopher Hannah for swift version)
Here is the same answer as Alberto, but I have changed it into Swift 3.
func preferredHeight(width: CGFloat, text: NSString, font: UIFont, image: UIImage) -> CGFloat {
// Calculate Label Height
let labelRect = text.boundingRect(
with: CGSize.init(width: width, height: 10000),
options: .usesLineFragmentOrigin,
attributes: [NSFontAttributeName : font],
context: NSStringDrawingContext())
let labelHeight = labelRect.height
// Calculate Image Height
let ratio = image.size.height / image.size.width
let imageHeight = ratio / width
// Calculate Total Height
let height = labelHeight + imageHeight
// Return Height Value
return height
}

How to vertical align (center) the content of UITableView?

I want to center the content of my UITableView that contains headerView and footerView created at storyboard, and UITableViewCells. How can I achieve this?
Here is what I'm trying to implement to solve my problem but this does not work.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
CGFloat height = self.tableView.frameHeight - self.navigationController.navigationBar.frameHeight - [UIApplication sharedApplication].statusBarFrame.size.height - (self.rowCount * self.rowHeight);
self.tableView.tableHeaderView.frameHeight = height / 2.0;
}
So I subtracted the height of the navigationBar & statusBar and cells' height to the tableView's height to get the height of the empty area.
Now that I get the height if the empty area, I divided it to 2 for the footer and header's view.
In the viewWillAppear and in the didRotateFromInterfaceOrientation functions :
CGFloat headerHeight = (self.view.frame.size.height - (ROW_HEIGHT * [self.tableView numberOfRowsInSection:0]))) / 2;
self.tableView.contentInset = UIEdgeInsetsMake(headerHeight, 0, -headerHeight, 0);
This will solve your problem.
EDIT
Call the updateTableViewContentInset function in the viewWillLayoutSubviews and after each reloadData :
Ojective-C
- (void)updateTableViewContentInset {
CGFloat viewHeight = self.view.frame.size.height;
CGFloat tableViewContentHeight = self.tableView.contentSize.height;
CGFloat marginHeight = (viewHeight - tableViewContentHeight) / 2.0;
self.tableView.contentInset = UIEdgeInsetsMake(marginHeight, 0, -marginHeight, 0);
}
Swift 4
func updateTableViewContentInset() {
let viewHeight: CGFloat = view.frame.size.height
let tableViewContentHeight: CGFloat = tableView.contentSize.height
let marginHeight: CGFloat = (viewHeight - tableViewContentHeight) / 2.0
self.tableView.contentInset = UIEdgeInsets(top: marginHeight, left: 0, bottom: -marginHeight, right: 0)
}
Override viewDidLayoutSubviews and compare the tableView's frame with its contentSize to set its contentInset. In Swift 4 :
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let tableViewHeight = self.tableView.frame.height
let contentHeight = self.tableView.contentSize.height
let centeringInset = (tableViewHeight - contentHeight) / 2.0
let topInset = max(centeringInset, 0.0)
self.tableView.contentInset = UIEdgeInsets(top: topInset, left: 0.0, bottom: 0.0, right: 0.0)
}
This works well with self-sizing table view cells 👌
Use the contentSize property of UITableView, that how you don't have to take the cell height or count into account.
- (void) updateTableInsetsForHeight: (CGFloat) height
{
CGFloat tableViewInset = MAX((height - self.tableView.contentSize.height) / 2.0, 0.f);
self.tableView.contentInset = UIEdgeInsetsMake(tableViewInset, 0, -tableViewInset, 0);
}
Update the contentInsets after reloading tableView-data, and when the containing view of the tableView becomes visible (viewWillAppear:) and when it changes size (viewWillTransitionToSize:withTransitionCoordinator:).
- (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[self updateTableInsetsForHeight: size.height];
}
Swift 3 based on Pipiks answer
let headerHeight: CGFloat = (view.frame.size.height - CGFloat(Int(tableView.rowHeight) * tableView.numberOfRows(inSection: 0))) / 2
tableView.contentInset = UIEdgeInsetsMake(headerHeight, 0, -headerHeight, 0)
Add a UIView at the top (UIView should be parent of your TableView) of your TableView from storyboard. After that set its constraints to fill the view. Now, set the size of your TableView and set its constraints to center both vertically and horizontally your top
UIView. This will solve your problem.
I found out what causing my computation wrong. The value of self.tableView.bounds.size.height is different from the actual height in viewWillAppear. I used self.view.bounds.size.height instead.
for SWIFT 3 :
var headerHeight: CGFloat = (tableView.frame.size.height - CGFloat(Int(tableView.rowHeight) * tableView.numberOfRows(inSection: 0))) / 2
if headerHeight > 0 {
tableView.contentInset = UIEdgeInsetsMake(headerHeight, 0, 0/*-headerHeight*/, 0)
} else {
headerHeight = 0
tableView.contentInset = UIEdgeInsetsMake(headerHeight, 0, 0/*-headerHeight*/, 0)
}
RESULT :
Set frame of your UITableView like this
CGFloat width = self.view.frame.size.width;
CGFloat height = self.view.frame.size.height;
CGFloat tableHeight = 200.0; //your table height
self.tableView.frame = CGRectMake(0,(height-tableHeight)/2,width,tableHeight);
or try this

How to know when UITableView did scroll to bottom in iPhone?

I would like to know when a UITableView did scroll to bottom in order to load and show more content, something like a delegate or something else to let the controller know when the table did scroll to bottom.
How can I do this?
in the tableview delegate do something like this
ObjC:
- (void)scrollViewDidScroll:(UIScrollView *)aScrollView {
CGPoint offset = aScrollView.contentOffset;
CGRect bounds = aScrollView.bounds;
CGSize size = aScrollView.contentSize;
UIEdgeInsets inset = aScrollView.contentInset;
float y = offset.y + bounds.size.height - inset.bottom;
float h = size.height;
// NSLog(#"offset: %f", offset.y);
// NSLog(#"content.height: %f", size.height);
// NSLog(#"bounds.height: %f", bounds.size.height);
// NSLog(#"inset.top: %f", inset.top);
// NSLog(#"inset.bottom: %f", inset.bottom);
// NSLog(#"pos: %f of %f", y, h);
float reload_distance = 10;
if(y > h + reload_distance) {
NSLog(#"load more rows");
}
}
Swift:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offset = scrollView.contentOffset
let bounds = scrollView.bounds
let size = scrollView.contentSize
let inset = scrollView.contentInset
let y = offset.y + bounds.size.height - inset.bottom
let h = size.height
let reload_distance:CGFloat = 10.0
if y > (h + reload_distance) {
print("load more rows")
}
}
Modified neoneyes answer a bit.
This answer targets those of you who only wants the event to be triggered once per release of the finger.
Suitable when loading more content from some content provider (web service, core data etc).
Note that this approach does not respect the response time from your web service.
- (void)scrollViewDidEndDragging:(UIScrollView *)aScrollView
willDecelerate:(BOOL)decelerate
{
CGPoint offset = aScrollView.contentOffset;
CGRect bounds = aScrollView.bounds;
CGSize size = aScrollView.contentSize;
UIEdgeInsets inset = aScrollView.contentInset;
float y = offset.y + bounds.size.height - inset.bottom;
float h = size.height;
float reload_distance = 50;
if(y > h + reload_distance) {
NSLog(#"load more rows");
}
}
add this method in the UITableViewDelegate:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat height = scrollView.frame.size.height;
CGFloat contentYoffset = scrollView.contentOffset.y;
CGFloat distanceFromBottom = scrollView.contentSize.height - contentYoffset;
if(distanceFromBottom < height)
{
NSLog(#"end of the table");
}
}
None of the answers above helped me, so I came up with this:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)aScrollView
{
NSArray *visibleRows = [self.tableView visibleCells];
UITableViewCell *lastVisibleCell = [visibleRows lastObject];
NSIndexPath *path = [self.tableView indexPathForCell:lastVisibleCell];
if(path.section == lastSection && path.row == lastRow)
{
// Do something here
}
}
The best way is to test a point at the bottom of the screen and use this method call when ever the user scrolls (scrollViewDidScroll):
- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point
Test a point near the bottom of the screen, and then using the indexPath it returns check if that indexPath is the last row then if it is, add rows.
Use – tableView:willDisplayCell:forRowAtIndexPath: (UITableViewDelegate method)
Simply compare the indexPath with the items in your data array (or whatever data source you use for your table view) to figure out if the last element is being displayed.
Docs: http://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:willDisplayCell:forRowAtIndexPath:
UITableView is a subclass of UIScrollView, and UITableViewDelegate conforms to UIScrollViewDelegate. So the delegate you attach to the table view will get events such as scrollViewDidScroll:, and you can call methods such as contentOffset on the table view to find the scroll position.
NSLog(#"%f / %f",tableView.contentOffset.y, tableView.contentSize.height - tableView.frame.size.height);
if (tableView.contentOffset.y == tableView.contentSize.height - tableView.frame.size.height)
[self doSomething];
Nice and simple
in Swift you can do something like this. Following condition will be true every time you reach end of the tableview
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row+1 == postArray.count {
println("came to last row")
}
}
Building on #Jay Mayu's answer, which I felt was one of the better solutions:
Objective-C
// UITableViewDelegate
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
// Need to call the service & update the array
if(indexPath.row + 1 == self.sourceArray.count) {
DLog(#"Displayed the last row!");
}
}
Swift 2.x
// UITableViewDelegate
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if (indexPath.row + 1) == sourceArray.count {
print("Displayed the last row!")
}
}
Here is the swift 3.0 version code.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offset = scrollView.contentOffset
let bounds = scrollView.bounds
let size = scrollView.contentSize
let inset = scrollView.contentInset
let y: Float = Float(offset.y) + Float(bounds.size.height) + Float(inset.bottom)
let height: Float = Float(size.height)
let distance: Float = 10
if y > height + distance {
// load more data
}
}
I generally use this to load more data , when last cell starts display
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == myDataArray.count-1) {
NSLog(#"load more");
}
}
Taking neoneye excellent answers but in swift, and renaming of the variables..
Basically we know we have reached the bottom of the table view if the yOffsetAtBottom is beyond the table content height.
func isTableViewScrolledToBottom() -> Bool {
let tableHeight = tableView.bounds.size.height
let contentHeight = tableView.contentSize.height
let insetHeight = tableView.contentInset.bottom
let yOffset = tableView.contentOffset.y
let yOffsetAtBottom = yOffset + tableHeight - insetHeight
return yOffsetAtBottom > contentHeight
}
My solution is to add cells before tableview will decelerate on estimated offset. It's predictable on by velocity.
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)offset {
NSLog(#"offset: %f", offset->y+scrollView.frame.size.height);
NSLog(#"Scroll view content size: %f", scrollView.contentSize.height);
if (offset->y+scrollView.frame.size.height > scrollView.contentSize.height - 300) {
NSLog(#"Load new rows when reaches 300px before end of content");
[[DataManager shared] fetchRecordsNextPage];
}
}
Update for Swift 3
Neoneye's answer worked best for me in Objective C, this is the equivalent of the answer in Swift 3:
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let offset: CGPoint = scrollView.contentOffset
let bounds: CGRect = scrollView.bounds
let size: CGSize = scrollView.contentSize
let inset: UIEdgeInsets = scrollView.contentInset
let y: CGFloat = offset.y + bounds.size.height - inset.bottom
let h: CGFloat = size.height
// print("offset: %f", offset.y)
// print("content.height: %f", size.height)
// print("bounds.height: %f", bounds.size.height)
// print("inset.top: %f", inset.top)
// print("inset.bottom: %f", inset.bottom)
// print("position: %f of %f", y, h)
let reloadDistance: CGFloat = 10
if (y > h + reloadDistance) {
print("load more rows")
}
}
I want perform some action on my any 1 full Tableviewcell.
So the code is link the :
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
NSArray* cells = self.tableView.visibleCells;
NSIndexPath *indexPath = nil ;
for (int aIntCount = 0; aIntCount < [cells count]; aIntCount++)
{
UITableViewCell *cell = [cells objectAtIndex:aIntCount];
CGRect cellRect = [self.tableView convertRect:cell.frame toView:self.tableView.superview];
if (CGRectContainsRect(self.tableView.frame, cellRect))
{
indexPath = [self.tableView indexPathForCell:cell];
// remain logic
}
}
}
May this is help to some one.
#neoneye's answer worked for me. Here is the Swift 4 version of it
let offset = scrollView.contentOffset
let bounds = scrollView.bounds
let size = scrollView.contentSize
let insets = scrollView.contentInset
let y = offset.y + bounds.size.height - insets.bottom
let h = size.height
let reloadDistance = CGFloat(10)
if y > h + reloadDistance {
//load more rows
}

Resources