I implemented scrollViewDidScroll in order to update UITableView when tableView did scroll to bottom. and adding 10 new elements to it.
There is a UISearchbar in UITableView too. when I search something, scrolling might be needed. but I don't want scrollViewDidScroll to be executed in this situation.
override func scrollViewDidScroll(scrollView: UIScrollView) {
let height = scrollView.frame.size.height
let contentYoffset = scrollView.contentOffset.y
let distanceFromBottom = scrollView.contentSize.height - contentYoffset
if distanceFromBottom < height {
print(" you reached end of the table")
self.fetchOffset += 10
// changing fillteredPosts. updating tableView.
}
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
filteredPosts.removeAll()
let searchText = searchController.searchBar.text
if let searchString = searchText, let searchInt = Int(searchString) {
for post in originalAllPosts {
if post.userId == searchInt {
filteredPosts.append(post)
}
}
}
tableView.reloadData()
}
Assuming you are performing search for every single character that is entered
override func scrollViewDidScroll(scrollView: UIScrollView) {
if searchController.searchBar.text.isEmpty {
let height = scrollView.frame.size.height
let contentYoffset = scrollView.contentOffset.y
let distanceFromBottom = scrollView.contentSize.height - contentYoffset
if distanceFromBottom < height {
print(" you reached end of the table")
self.fetchOffset += 10
// changing fillteredPosts. updating tableView.
}
}
}
Here the statements inside scrollViewDidScroll will be executed only when searchBar is empty that means we are not performing a search action
Related
I have a chat app and I'm trying to show a custom view that I've made when the user scrolls to the top, also hide it if it's on the bottom of tableview. (like whatsapp does it)
To be honest I'm struggling with the logic of show/hide button.
Tried to save the contentOffset.y of my tableview right after I reload the data so I'll know that's the bottom, and if it's smaller to show the custom view, but mainTableView.contentOffset.y it's always 0.
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
if (scrollView == mainTableView) {
print(mainTableView.contentOffset.y)
if let point = startingPointForView {
//where var startingPointForView: CGFloat?
// and tried to save it after I reload the data
//self.startingPointForView = self.mainTableView.contentOffset.y
// but it's always 0
}
// Show and hide button logic
}
}
An image of what I m trying to achieve: https://imgur.com/ZkYEi2P
try this code to hide/show custom view according to UIscrollview contentOffset
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let scrollViewContentHeight = scrollView.contentSize.height
let scrollViewHeight = scrollView.frame.height
if scrollView.contentOffset.y < (scrollViewContentHeight - scrollViewHeight){
//Custom view show
}else{
//Custom view Hide
}
}
May be this code will help you
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.panGestureRecognizer.translation(in: scrollView).y > 0 {
// down
button.isHidden = false
} else {
// up
button.isHidden = true
}
}
For someone who is looking to hide a button when tableview is scrolling can use below code:
var previousContentOffset: CGFloat = CGFloat()
extension YourViewController: UIScrollViewDelegate{
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView == self.yourTableView{
let currentContentOffset = scrollView.contentOffset.y
if (currentContentOffset > previousContentOffset) {
// scrolling towards the bottom
if scrollView.contentOffset.y > 50 {
self.yourButton.isHidden = true
} else {
self.yourButton.isHidden = false
}
} else if (currentContentOffset < previousContentOffset) {
// scrolling towards the top
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height
// Change 10.0 to adjust the distance from bottom
if maximumOffset - currentContentOffset <= 10.0 {
self.yourButton.isHidden = true
} else {
self.yourButton.isHidden = false
}
}
previousContentOffset = currentContentOffset
}
}
}
i have a collection view which is used to show comment and i am using a uiview at bottom of the view controller with a height of 0.
when user reach the bottom of content in collection view,as he pull up past content i check in scrollviewdidscroll
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if self.comment.count >= 5 {
let offseety = scrollView.contentOffset.y
let contenthight = scrollView.contentSize.height
if offseety > contenthight - scrollView.frame.size.height + 5 && offseety > 50{
if self.viewheight.constant < 50 {
self.viewheight.constant = scrollView.frame.size.height - contenthight + offseety
if offseety > contenthight - scrollView.frame.size.height + 50{
self.anddiii.isHidden = false
self.anddiii.startAnimating()
self.anothershit.isHidden = false
self.anothershit.text = "Loading more"
}
}}else{
}
}
}
but problem after scrolling end the collection view scrolls back,is there a way to put an ofset bellow last collection cell to show uiview in
Try Below code:
self.collectionView.contentInset = UIEdgeInsetsMake(0,0,55,0)
Right now I have a UICollectionView set up with horizontal paging. I have sized my cells to fit the screen so that there is only ever one visible(unless you are scrolling).
What I wish to do is get the index path of the cell that is in view once you have stopped scrolling. This is because other parts of the view are dependent on the information that is currently visible.
I have set up a function in the scrollViewWillBeginDecelerating function and I am close but I still don't seem to understand how it is grabbing the cells.
func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
if( lastContentOffset > scrollView.contentOffset.x && lastPointVisited > 0)
{
lastPointVisited -= 1
print("Scrolling Right")
}
else if(lastContentOffset < scrollView.contentOffset.x && lastPointVisited < myPoints.count - 1)
{
lastPointVisited += 1
print("Scrolling Left")
}
lastContentOffset = scrollView.contentOffset.x
}
This gets me accurate results if I am very careful about scrolling. Going fast or only half scrolling a page so that it snaps back seems to throw everything off.
You can use following code to get page number
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageWidth = scrollView.frame.size.width
let page = Int(floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)
print("Page Number : \(page)")
}
It works for me If I put the same code in these two delegates at same time
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
//code here
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
//code here
}
instead of writing it in
func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView)
It gives me the exact value of index whether it is scrolling fast or half scrolled.
Hope it helps!
try this,
func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
let cellObj = collectionViewDemo.visibleCells[0]
print(collectionViewDemo.indexPath(for: cellObj))
}
You can use the below code it will be always effective to find the visible collectionView page
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageWidth = scrollview.frame.width
let pageIndex = scrollview.frame.width
let indexTemp = Int((scrollview.contentOffset.x +
pageWidth / 2) / pageWidth)
print(pageIndex)
}
I want to stop backward scrolling on ScrollView after user scrolls to the next page. How can I do that.
I tried the following two codes, but the first one does not have any effect
self.scrollView.contentOffset = CGPointMake(self.view.frame.width,0)
and the second only disables the forward scrolling.
self.scrollView.contentSize = CGSizeMake( 2 * scrollWidth, scrollHeight);
To disable scrolling in one direction you implement the UIScrollViewDelegate method scrollViewDidScroll and put your logic there. For instance this TableViewController can only ever scroll down, because if the user tries to scroll up, we just overwrite the contentOffset, effectively undoing their scroll before they see it.
class ViewController: UITableViewController {
var lastScrollPosition = CGPoint.zero
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard scrollView.contentOffset.y > lastScrollPosition.y else {
scrollView.setContentOffset(lastScrollPosition, animated: false)
return
}
lastScrollPosition = scrollView.contentOffset
}
}
If your cell is equal in size to your screen, you can apply the following option, which is very smooth:
var lastScrollPosition = CGPoint.zero
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if scrollView.contentOffset.x == lastScrollPosition.x + UIScreen.main.bounds.width {
lastScrollPosition.x += UIScreen.main.bounds.width
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard scrollView.contentOffset.x > lastScrollPosition.x else {
scrollView.setContentOffset(lastScrollPosition, animated: false)
return
}
}
I tried finding this question for a while but could not find this problem's answer.
My problem is that i have a UICollectionView and the Scroll Direction is Horizontal with Paging Enabled. My problem is that i want to keep the tack of the current page number on which the user is, so i created an int variable and now want to add or subtract it by 1 each time the user swipes right or left. I tried using scrollView's delegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
but when the user swipes right or left, it is called as many number of the times as the number of columns on a page in the UICollectionView plus it wont let me know that whether the user went to the next page or the previous one.
Swift 3 Xcode 8.2
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let x = scrollView.contentOffset.x
let w = scrollView.bounds.size.width
let currentPage = Int(ceil(x/w))
// Do whatever with currentPage.
}
Use :
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGFloat pageWidth = collectionView.frame.size.width;
float currentPage = collectionView.contentOffset.x / pageWidth;
if (0.0f != fmodf(currentPage, 1.0f))
{
pageControl.currentPage = currentPage + 1;
}
else
{
pageControl.currentPage = currentPage;
}
NSLog(#"Page Number : %ld", (long)pageControl.currentPage);
}
And if you are not using any pageControl, then ceil(currentPage) will be your current page number.
Based on #Shankar BS 's answer I've implemented it like this in Swit. Keep in mind that CollectionViewDelegate conforms to ScrollViewDelegate:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageWidth = scrollView.frame.size.width
let page = Int(floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)
print("page = \(page)")
}
You can get the current page like below, index will be from 0 to (total page - 1)
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
NSLog(#"Current page -> %d",page);
}
SWIFT 5
For example, put this method in your ViewController with extensions UICollectionViewDelegate,UICollectionViewDataSource
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageWidth = scrollView.frame.size.width
let page = Int(floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)
print("page = \(page)")
}
Swift 2.2
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let x = collectionView.contentOffset.x
let w = collectionView.bounds.size.width
let currentPage = Int(ceil(x/w))
print("Current Page: \(currentPage)")
}
You can get the currentPage this way when the user end the dragging:
Swift 5.6 Tested and works!
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let itemWidth = collectionView.frame.width // Get the itemWidth. In my case every cell was the same width as the collectionView itself
let contentOffset = targetContentOffset.pointee.x
let targetItem = lround(Double(contentOffset/itemWidth))
let targetIndex = targetItem % YOUR_ARRAY.count // numberOfItems which shows in the collection view
print(targetIndex)
}
Xamarin.iOS:
You can override DecelerationEnded method of UICollectionViewDelegate or subscribe to DecelerationEnded event of UICollectionView (custom delegate will be used under the hood).
public override void DecelerationEnded(UIScrollView scrollView)
{
var x = scrollView.ContentOffset.X;
var w = scrollView.Bounds.Size.Width;
var currentPage = Math.Ceiling(x / w);
// use currentPage here
}