Prevent UITableView scrolling below a certain point
You can use the property contentInset
of UITableView
just for that. Just remember to set them with minus values, cause we are shrinking the content size:
CGFloat insetTop = topAllowedRow * c_CELL_HEIGHT * -1;
CGFloat insetBottom = bottomAllowedRow * c_CELL_HEIGHT * -1;
[self.tableView setContentInset:UIEdgeInsetsMake(insetTop, 0, insetBottom, 0)];
The other solution is to implement UIScrollViewDelegate
method scrollViewDidScroll:
and when scrollView.contentOffset
is too huge, set it back to the max value that user can scroll to:
- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
CGPoint scrollViewOffset = scrollView.contentOffset;
if (scrollViewOffset.x > MAX_VALUE) {
scrollViewOffset.x = MAX_VALUE;
}
[scrollView setContentOffset:scrollViewOffset];
}
First solution has both the advantage and disadvantage since then UIScrollView
will manage the bouncing (just like in pull to refresh). It's more natural and HIG-compatible, but if you really need user not to see below the certain row, use delegate method.
How do I stop UITableview from scrolling more than one cell at a time
Thanks for your response. Here is how I solved it. I set:
tableView.isScrollEnabled = false // Set the tableview scroll enabled to false
Then in the "cellForRowAt indexPath: IndexPath" function I saved the indexPath of the first row to the currentIndexPath property :
currentIndexPath = indexPath
Then I added a gesture recognizer to the tableview for swiping up:
let swipeToNextVideoGesture = UISwipeGestureRecognizer(target: self, action:
#selector(swipeToNext(_:)))
swipeToNextVideoGesture.direction = .up
tableView.addGestureRecognizer(swipeToNextVideoGesture)
Then in the function I first checked if the next Row is in the tableview datasource array bounds, then I scrolled to that row:
@objc private func swipeToNext(_ gesture: UISwipeGestureRecognizer) {
let nextVideoIndexPath = currentIndexPath.row+1
if !(nextVideoIndexPath >= viewModel.postInformations.count) {
currentIndexPath = IndexPath(row: nextVideoIndexPath, section: indexPathSection)
tableView.scrollToRow(at: currentIndexPath, at: .none, animated: true)
}
}
How to prevent a UITableView from being pulled down past a certain point?
Try this
extension ViewController: UIScrollViewDelegate
{
func scrollViewDidScroll(_ scrollView: UIScrollView)
{
print("ddffddfd \(scrollView.contentOffset.y)")
if scrollView.contentOffset.y > 0 && imageContainerViewHeightConstraint.constant == 223
{
return
}
if scrollView.contentOffset.y > 0
{
var sd = imageContainerViewHeightConstraint.constant + abs(scrollView.contentOffset.y)
if(sd < 233 )
{
print("path111 1")
self.dataTableView.contentOffset = CGPoint.init(x: 0, y: 0 )
return
}
else
{
print("path111 2")
imageContainerViewHeightConstraint.constant -= abs(scrollView.contentOffset.y)
}
print("path11111 3")
view.layoutIfNeeded()
self.dataTableView.contentOffset = CGPoint.init(x: 0, y: 0 )
return
}
print("path11111 4")
if scrollView.contentOffset.y < 0 && imageContainerViewHeightConstraint.constant >= initialContainerImageViewHeight * 2
{
self.dataTableView.contentOffset = CGPoint.init(x: 0, y: 0 )
//self.dataTableView.bounces = false
return
}
else
{
imageContainerViewHeightConstraint.constant += abs(scrollView.contentOffset.y)
view.layoutIfNeeded()
}
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool)
{
resetContainerViewSize()
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView)
{
resetContainerViewSize()
}
}
///////
func resetContainerViewSize()
{
imageContainerViewHeightConstraint.constant = 223
UIView.animate(withDuration: 0.7,
delay: 0.0,
usingSpringWithDamping: 0.7,
initialSpringVelocity: 0.5,
options: .curveEaseInOut,
animations: {
self.view.layoutIfNeeded()
self.dataTableView.bounces = true
}, completion: nil)
}
In Action
Find a demo here testScrollAboveTable
Prevent UITableView from scrolling when new cells are inserted
func add(_ item: Item) {
// Calculate your `contentOffset` before adding new row
let additionalHeight = tableView.contentSize.height - tableView.frame.size.height
let yOffset = tableView.contentOffset.y
// Update your contentInset to start tableView from bottom of page
updateTableContentInset()
items.append(item)
// Create indexPath and add new row at the end
let indexPath = IndexPath(row: objects.count - 1, section: 0)
tableView.insertRows(at: [indexPath], with: .top)
// Scroll to new added row if you are viewing latest messages otherwise stay at where you are
if yOffset >= additionalHeight {
tableView.scrollToRow(at: indexPath, at: .top, animated: true)
}
}
Here is the method to update contentInset
. It will give you the same effect which you were achieving by this CGAffineTransform(scaleX: 1, y: -1)
func updateTableContentInset() {
var contentInsetTop = tableView.frame.size.height - tableView.contentSize.height
if contentInsetTop <= 0 {
contentInsetTop = 0
}
tableView.contentInset = UIEdgeInsets(top: contentInsetTop, left: 0, bottom: 0, right: 0)
}
Related Topics
Swiftui Tabbedview Only Shows First Tab's Content
How to Use a Generic Class Without the Type Argument in Swift
Custom Uitoolbar Too Close to the Home Indicator on iPhone X
How to Get Alexa Working on My iOS App
Do I Need to Wrap My Alamofire Calls Inside Dispatch_Async
Uilocalnotification: Playing a Custom Audio File Saved in Documents Directory
Segue Out of Navigation Controller
Cannot Set Color of Button's Label Inside Menu in Swiftui
How to Set Cmutablepointer<Objcbool> to False in Swift
Ios10, Swift 3, and Fcm Delegate Error
Swiftui: How to Change the Tint Color (Background Color) of a Navigationview
iOS Media Playback Controls Notification
Swiftui - Navigationview Title and Back Button Clipped Under Status Bar After Orientation Change
Self.Type Cannot Be Directly Converted to Anyclass in Extension to Objective-C Class in Swift
Launch Watch App into Middle View
Receipt Validation on iOS In-App-Purchase Returns Multiple Transaction