UIScrollView : only paging horizontally left, bouncing right - ios

How can I force a UIScrollView in which paging and scrolling are on to only move horizontally left or horizontally both direction(left and right)?
To be clearer, I'd like to allow the user to 'page only horizontally backward(only bounce when the user try to scroll horizontally right)' OR 'horizontally both direction(this is normal action)' at a given moment.
I am wondering that the solution is the subclass of UIScrollView.
Thanks in advance.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if ( only bounce.. ){
// is it right?
if (scrollView.contentOffset.y > 60) {
[scrollView setContentOffset:CGPointMake(0, 60)];
}
}
if ( only paing left... ){
How to do this??
}
}

I'd implement the delegate function scrollViewDidScroll: and store the state (scroll state) of the ScrollView. On subsequent calls, compare with the previous state and have it bounce back (by calling ZoomToRect: maybe) if it is in a particular direction that you don't like.

Related

UIrefresh Control on UIcollectionView at the top and bottom

I want to add paging in my collectionView. I am using Waterfall layout in my collection View. Having two rows only.
Scrolling is horizontal. I want to add paging in such a way that user can go back and forth the pages.
I found one of that over Git by Simon Westerlund. But in this UIrefreshCOntrol is added at the top only. I want to ahev UIrefresh control at the bottom too. So that I can show paging Effect. Just as, its in the case of Facebook app
I think you can use bounce effect of UICollectionView coz its already inherited from UIScrollView and use following delegate method
You just have to add following lines and call your method instead of [self fetchMoreEnteries]
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
float endScrolling = scrollView.contentOffset.y + scrollView.frame.size.height;
if (endScrolling >= scrollView.contentSize.height)
{
NSLog(#"Scroll End Called");
[self fetchMoreEntries];
}
}

Handling Conflicting Gestures in Nested UIScrollViews

So I realize that having nested scroll views at all it sort of a red flag, but the current setup of everything actually works quite well besides one small problem. One scroll view manages scrolling through a collection, while another handles zooming and panning on the entire collection view. This all works, but the small problem comes from when zooming in and panning downward, the scrollview pans while the collectionview scrolls, causing the view to scroll twice as fast, and not feel connected to your finger.
What I ideally want to happen is vertical scrolling is managed by the outer scroll view when panning is possible, and then handled by the inner scroll view when the outer one can no longer pan. I got very close by writing something like this:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == _outerScrollView) {
CGPoint offset = _outerScrollView.contentOffset;
CGFloat height = _outerScrollView.frame.size.height;
CGFloat contentHeight = _outerScrollView.contentSize.height;
ScrollDirection scrollDirection;
if (offset > _lastContentOffset){
scrollDirection = ScrollDirectionUp;
} else {
scrollDirection = ScrollDirectionDown;
}
BOOL scrollIsAtTop = offset.y <= 0;
BOOL scrollIsAtBottom = offset.y + height >= contentHeight;
//If there is a pan upward and we aren't at the top of the outer
//scrollview cancel the gesture on the inner view
//downward vice versa
if (!((scrollIsAtTop && scrollDirection == ScrollDirectionUp)
|| (scrollIsAtBottom && scrollDirection == ScrollDirectionDown))) {
_innerCollectionView.panGestureRecognizer.enabled = NO;
_innerCollectionView.panGestureRecognizer.enabled = YES;
}
}
_lastContentOffset = offset.y;
}
This ALMOST works, with one side effect of a big pan downward stops when it hits the bottom and requires the user to start a new gesture to continue scrolling with the inner collection. Ideally this transition would be smooth, but I'm having a hard time figuring out a way to do this. Again I realize scroll view inside scroll view is not ideal, but if I can fix this small problem everything will be good, rather than attempt to redesign the whole thing.
Any ideas on how I can handle the double scroll in a way that lets the pan gesture win, but cleanly transitions to the inner collection when the outer scroll view can no longer pan vertically?
So, since I never got any answers, this is the solution I've been going with. Essentially if the inner collection view isn't at the top or bottom, I reset the y offset change the outer scroll view has in scrollViewDidScroll. Code looks like this:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == _outerScrollView) {
if (![self innerScrollIsAtTop] && ![self innerScrollIsAtBottom] && !self.allowOuterScroll) {
[scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, self.lastContentOffset)];
}
self.lastContentOffset = scrollView.contentOffset.y;
}
}
using these 2 conveniences:
- (BOOL)innerScrollIsAtTop {
return _innerCollectionView.contentOffset.y <= 0;
}
- (BOOL)innerScrollIsAtBottom {
CGFloat zoom = self.zoomScale;
CGFloat height = _innerCollectionView.frame.size.height;
CGFloat contentHeight = _innerCollectionView.contentSize.height;
CGPoint offset = _innerCollectionView.contentOffset;
return offset.y + height / zoom >= contentHeight;
}
And you'll need 2 class variables, a float to hold the previous y content offset of the outer scroll, and a BOOL to hold whether you want to allow the outer scroll view to scroll, which you can set to YES while zooming or programatically scrolling. This solution fixes the double scroll, but does have a cumbersome hack within scrollviewDidScroll that may bite you later and you constantly need to work around, but for now this is the solution I've been using.

How to trick UIScrollView into starting scrolling in the middle of panning?

Example:
You have a UIScrollView with scrollEnabled = NO.
After user pans a certain distance, you want the scroll view to start scrolling.
When finger goes down on screen and I disable scrolling, the scroll view is dead until the finger is lifted. Enabling scrolling in middle of a pan doesn't cause it to start.
I suspect it is because UIScrollView will decide to ignore the touch sequence if it was scrollEnabled=NO during its internal touchesBegan:withEvent: (or its private pan gesture recognizer).
How would you trick it into starting to scroll natively (with bounce effect) in the middle of a touch sequence?
Reason: For a simple UIKit based game that requires this mechanic.
Okay, this still needs a little bit of tweaking to handle scrolling again after the first scroll has stopped, but I think the key to what you're trying to achieve is to implement the UIScrollViewDelegate method scrollViewDidScroll:. From here, you can save the starting content offset of the scroll view, and compare the scroll view's current offset to the starting offset added to the y translation of the scroll view's pan gesture recognizer.
The code below successfully doesn't allow scrolling to start until the user has panned at least 100 pts. Like I said, this needs a little tweaking, but should be enough to get you going.
- (void)viewDidLoad
{
[super viewDidLoad];
[self setStartingOffset:CGPointMake(0.0, -1.0)];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (self.startingOffset.y < 0.0) {
[self setStartingOffset:scrollView.contentOffset];
}else{
static CGFloat min = 100.0;
CGFloat yTranslation = fabs([scrollView.panGestureRecognizer translationInView:scrollView].y);
if (yTranslation < self.startingOffset.y + min) {
[scrollView setContentOffset:self.startingOffset];
}else{
if (self.startingOffset.y >= 0.0) {
[self setStartingOffset:CGPointMake(0.0, -1.0)];
}
}
}
}

Make 2 UIScrollViews zoom and scroll identically

I have a screen which has two UIScrollViews. Inside the scrollview is a zoomable UIImageView.
I'd like to achieve the same scrolling and zooming inside one scrollView to be applied to the other one. i.e. if the user pans across the image, both scrollviews pan their images at the exact same rate. If the user pinch zooms the image in one, the other zooms exactly the same amount.
I've read on here about using the zoomToRect:animated: call. I'm not sure exactly how to implement that, so I've tried the following - but it doesn't seem to yield the right results. NB. the scrollView contain self.imageViewLeft. self.scrollViewRight is the scrollView not being touched.
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
CGRect visibleRect = [scrollView convertRect:scrollView.bounds toView:self.imageViewLeft];
[self.scrollViewRight zoomToRect:visibleRect animated:false];
}
I solved it guys! Props to me.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == self.scrollViewLeft) {
[self.scrollViewRight setZoomScale:[scrollView zoomScale]];
[self.scrollViewRight setContentOffset:[scrollView contentOffset]];
} else {
[self.scrollViewLeft setZoomScale:[scrollView zoomScale]];
[self.scrollViewLeft setContentOffset:[scrollView contentOffset]];
}
}

UIScrollView events for scrolling that definitely occurred

I am working with aUIScrollview, and based on if the user scrolls left or right, I reconfigure the UI. The problem is that I need to verify that the user definitely crossed from one screen to another (something along contentOffset).
I've tried using this method:
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
But this will fire if the user kind of moves the scrollview partially in one direction, but then doesn't complete the gesture.
I've also tried this method:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView;
but mainly the same issue; the scrollview scrolls left and right, but on an iPhone, with a content with of 640 ( 320 * 2). I am trying to figure out if the scroll did cross over or not, from one location to the other.
Any suggestions?
I am not entirely sure what you mean by "crossed from one screen to another" I assume you mean paging? If so, here's what you can do:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender {
int page = sender.contentOffset.x / width;
[self.pageControl setCurrentPage:page]; // in case you need it for updating a UIPageControl
}
I found a way of doing this :
I have a variable to maintain the x location of the contentOffset
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
currX = self.scrollView.contentOffset.x;
}
And then in this event :
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
if(self.scrollView.contentOffset.x == currX ) {
return;//This is what I needed, If I haven't panned to another view return
}
//Here I do my thing.

Resources