How can I refresh the table view but disable the bounce? - ios

I want to disable my scrollview bounce when scroll down.
When I disable bounce vertically I can't refresh my table.
Any suggestion how to disable bounce, but enable refresh table?
I'm refreshing this way:
self.refreshControl = UIRefreshControl()
self.refreshControl.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refreshControl)
func refresh(sender:AnyObject) {
getJson()
self.tableView.reloadData()
self.refreshControl.endRefreshing()
}
Thanks.

Just did it this way:
func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView.contentOffset.y < 0.0 {
return
}
if (scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.frame.size.height) {
scrollView.setContentOffset(CGPointMake(scrollView.contentOffset.x, scrollView.contentSize.height - scrollView.frame.size.height), animated: false)
}
}

Implement the scrollViewDidScroll method in the UIScrollViewDelegate
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y > 0 {
scrollView.setContentOffset(CGPoint(x: scrollView.contentOffset.x, y: 0), animated: false)
}
}
}
This allows the table view to pull to refresh down, but restricts pulling up. This removes the bounce in the upwards direction.
Side-effect: this will not let you go beyond the cells already on view, so you can't scroll down to cells not visible.

Related

Detect when a user swipes past a certain point in a UICollectionView's scrollViewWillBeginDragging?

In my collectionView the cells are the size of the entire screen, I use vertical scrolling, and I have .isPagingEnabled = true. I needed to prevent the user from swiping fast. Changing the .decelerationRate didn't work. The only thing that I found was to disable/enable the scrollView as the user swipes which almost works fine.
In the pic below, when the swiping starts, I disable the scrollView and show a red label at the top that says "cv Disabled". When swiping ends because the user lifted their finger, I enable the scrollView and remove the label. But when I swipe a hairline bit and quickly lift my finger from the cell, the red label never disappears and the scroll stays disabled. The orange arrow points to the next cell with a beige background that's about to be shown when I subtly swiped.
In the code below using both tries everything works fine when scrolling past a certain point occurs like full screen or a quarter of the screen. The issue is if I subtly swipe a hairline bit, the scrollView stays disabled because the methods myScrollView?.isUserInteractionEnabled = true are in never gets fired.
1st try:
var myScrollView: UIScrollView?
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
if myScrollView == nil {
myScrollView = scrollView
}
myScrollView?.isUserInteractionEnabled = false
showRedDisabledLabel()
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
myScrollView?.isUserInteractionEnabled = true
removeRedDisabledLabel()
}
2nd try:
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
if myScrollView == nil {
myScrollView = scrollView
}
myScrollView?.isUserInteractionEnabled = false
showRedDisabledLabel()
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
NSObject.cancelPreviousPerformRequests(withTarget: self)
perform(#selector(UIScrollViewDelegate.scrollViewDidEndScrollingAnimation), with: nil, afterDelay: 0.3)
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
myScrollView?.isUserInteractionEnabled = true
removeRedDisabledLabel()
NSObject.cancelPreviousPerformRequests(withTarget: self)
}
This problem literally only occurs when I swipe that hairline bit and quickly lift my finger, every other time the code from both tries works perfectly. The question is in scrollViewWillBeginDragging, how can I detect when a user swipes past a certain point so that I can then set myScrollView?.isUserInteractionEnabled = false
I couldn't find a way to to determine how much a user swiped in scrollViewWillBeginDragging but I did find a workaround to the actual problem of hairline scrolling. I put myScrollView?.isUserInteractionEnabled and the redLabel into their own functions, combined this answer and this answer, created an instance property named isScrolling, and use didSet to determine if it's scrolling or not and call the functions from there:
// Properties
var myScrollView: UIScrollView?
var isScrolling = false {
didSet {
if isScrolling {
disableScrollView()
} else {
enableScrollView()
}
}
}
// My 2 Functions
func disableScrollView() {
myScrollView?.isUserInteractionEnabled = false
showRedDisabledLabel()
}
func enableScrollView() {
myScrollView?.isUserInteractionEnabled = true
removeRedDisabledLabel()
}
// UIScrollView Delegate Methods
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
if myScrollView == nil {
myScrollView = scrollView
}
isScrolling = true
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
isScrolling = false
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
isScrolling = false
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
NSObject.cancelPreviousPerformRequests(withTarget: self)
perform(#selector(UIScrollViewDelegate.scrollViewDidEndScrollingAnimation), with: nil, afterDelay: 0.3)
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
isScrolling = false
NSObject.cancelPreviousPerformRequests(withTarget: self)
}

Swipe only to the left using a UIScrollView

I have a scrollView with the delegate method set.
private let scrollView: UIScrollView = {
let scrollView = UIScrollView(frame: .zero).usingAutoLayout()
scrollView.isPagingEnabled = true
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false
return scrollView
}()
I'm trying to making only scroll to the left to mimic a "delete cell", like in the phone book. I don't want the user to be able to scroll to the right. I have this, which kinda works:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.x < 0 {
scrollView.contentOffset.x = 0
}
The problem is that if I swipe fast the contentOffSet is set to positive values, which makes the scrollView scroll in the opposite direction. This usually happens after I finish the swipe gesture. This makes me think it has to do with the bounce, but even setting it to false, it still occurs.
Was able to come up with a solution:
extension SwipeableCollectionViewCell: UIScrollViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
if scrollView.panGestureRecognizer.translation(in: scrollView.superview).x > 0 {
self.scrollDirection = .rigth
} else {
self.scrollDirection = .left
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if self.scrollDirection == .rigth {
scrollView.contentOffset.x = 0
}
}
}
private enum ScrollDirection {
case rigth
case left
}

When I pull down to refresh on my UIScrollView it requires me to pull down to the middle of the screen

I have a function: didPullToRefresh(). In order to set this function into motion, I have to pull my UIScrollView all the way to the middle of the screen. Is there a way I can refresh the data I want to refresh by only pulling the screen down 50 pixels? Thanks?
Here is the code I am currently running:
var refreshControl: UIRefreshControl!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.alwaysBounceVertical = true
scrollView.bounces = true
refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(didPullToRefresh), for: .valueChanged)
self.scrollView.addSubview(refreshControl)
}
#objc func didPullToRefresh() {
print("Refersh")
// For End refrshing
refreshControl?.endRefreshing()
}
Don't add target to Refresh control. Just addSubView it to scrollview. In viewDidLoad:
scrollView.alwaysBounceVertical = true
scrollView.bounces = true
scrollView.delegate = self
refreshControl = UIRefreshControl()
self.scrollView.addSubview(refreshControl)
Set scrollview delegate to self. And implement following scrollview delegate method:
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if scrollView.contentOffset.y <= -50 {
refreshControl.beginRefreshing()
print("Start Refresh Service")
}
}
Write "refreshControl?.endRefreshing()" on refresh service finish.

UIRefreshControl - collectionView jumps when scrolling

I have a problem with UIRefreshControl. When I scroll down the collectionView the content of the collectionView jumps a little bit up.
GIF here: https://imgur.com/a/8rK5s
I have already seen some question about this exact problem, however, I haven't been able to find an answer that would work for me. (for example this question)
I have a UICollectionViewController inside another UIViewCotroller as a subview.
I have implemented UIRefreshControl like this:
let refreshControl = UIRefreshControl()
if #available(iOS 10.0, *){
self.collectionView?.refreshControl = self.refreshControl
} else{
self.collectionView?.insertSubview(self.refreshControl, at: 0)
}
self.collectionView?.alwaysBounceVertical = true
refreshControl.addTarget(self, action: #selector(refreshControlChanged), for: .valueChanged)
refreshControl.tintColor = UIColor.custom.blue.classicBlue
Also, I want my collectionView to refresh data after the user stops dragging.
#objc func refreshControlChanged(){
if !(self.collectionView?.isDragging)!{
nextRecommended()
}
}
override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if refreshControl.isRefreshing{
nextRecommended()
}
}
And inside nextRecommended():
DispatchQueue.main.async {
self.refreshControl.endRefreshing()
self.collectionView?.reloadData()
}
Any help much appreciated.

how to know UIwebview is scrolling down side or up side? (swift)

in my app i am using small menu at the bottom of uiwebview. and i want to make like when user scroll downside that view must be hide. and when scrolling upside view must be unhide.
Like Safari.
this is what i tried
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
print("Going Down")
viewbottom.hidden = true
viewHieght.constant = 0
}
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
print("Going Up")
viewbottom.hidden = false
viewHieght.constant = 45
}
but by using this code its continuously showing up and down.
Use scroll view pan gesture recogniser to determine the direction.
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
if scrollView.panGestureRecognizer.translationInView(scrollView.superview).y > 0 {
// scrolls down
} else {
// scrolls up
}
}
keep tracking the scrollView.contentOffset.y value and compare the last with the current value like so:
in your mainView add: var lastScrollOffset = CGFloat()
compare the last value with the current one in func scrollViewDidScroll(scrollView: UIScrollView)
func scrollViewDidScroll(scrollView: UIScrollView) {
let scrollOffset = scrollView.contentOffset.y
if lastScrollOffset < scrollOffset{
//scrolling down
}else if lastScrollOffset > scrollOffset {
//scrolling up
}else{
//going crazy
}
lastScrollOffset = scrollOffset
}

Resources