4

I am trying to achieve something like flash cards for iPhone requirement. Where text contents will be in the center of card and left side (previous card), right side (next card) partially visible.

enter image description here

So far I tried with nicklockwood/SwipeView from github . But I failed to meet left /right side cards partial visibility requirement.

Is there any workaround / library? Please let me know here.

byJeevan
  • 3,728
  • 3
  • 37
  • 60

4 Answers4

3

I would simply use a UICollectionView.

Snapping behaviour: UICollectionView with paging - setting page width

layout:

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(200, 400);
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;

The cool thing about this is, you can easily implement centering behaviour when the user taps on the left or right partially visible cell (this is not so easy with some of the UIScrollView hacks out there):

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    [self.collectionView scrollToItemAtIndexPath:indexPath
                                atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
                                        animated:YES];
}
Community
  • 1
  • 1
stefreak
  • 1,460
  • 12
  • 30
  • I can attest to that working quite well. Most of these classes are just subclasses of UIScrollView, so they're quite customisable by iterating though their subviews until you get to the UIScrollview. –  Jan 13 '15 at 15:25
  • @stefreak - Wow! That's good idea. I will surly try this. Thanks for reply – byJeevan Jan 13 '15 at 15:27
  • 1
    @Rollo `UICollectionView` is a subclass of `UIScrollView`, no need to iterate through it's subviews – stefreak Jan 13 '15 at 15:28
  • 1
    @jeekOnline hehe no problem! I use UICollectionView for everything because it's so awesome! – stefreak Jan 13 '15 at 15:28
1

If you want to achieve this with the available UIScrollView pagination api there is a simple trick. Besides from setting pagingEnabled to YES, also ensure that clipsToBounds is set to NO.

UIScrollView *scrollView = [UIScrollView new];
self.scrollView.pagingEnabled = YES;
self.scrollView.clipsToBounds = NO;

You now need to set the size of the scroll view to the size of your page. The scroll view will draw outside its bounds, revealing the other pages.

To be able to also start dragging outside the scroll view, you need to create a container view that contains the scroll view. You then override hitTest: in this container view, returning the scroll view all the time:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    return self.scrollView;
}

If the container view has clipToBounds set to YES, this will be the area where the scroll view is visible.

Michael Ochs
  • 2,846
  • 3
  • 27
  • 33
1

As my scrollview is very small (only 100p tall), the hitTest method gets the whole ViewController which is not what I want. This solution covers any size of ScrollView and is done using Swift 4:

class ScrollViewContainer: UIView {

@IBOutlet weak var scrollView: UIScrollView!

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

    guard self.bounds.contains(point) else {
        return super.hitTest(point, with: event)
    }

    guard self.scrollView.frame.contains(point) else {
        return self.scrollView
    }

    return super.hitTest(point, with: event)
   }
}

The first Guard returns the default UIView hitTest if the hit is outside of its boundaries.

The second one returns the UIScrollView if the hit is inside of my container but outside of the ScrollView (which is exactly the objective of this question).

And if the hit is inside of the ScrollView, there is no need to do anything different, just let UIView handle it with its default implementation.

The only thing that needs to be handled is when your touch is inside of the container but outside of the scrollview.

This code can be reduced to only one guard, but I thought that this way was clearer to explain the logic.

Roberto Ferraz
  • 2,511
  • 24
  • 43
  • 1
    Exactly what I needed! If someone has a container with a UIScrollView as the child and want to pass the events to the UIScrollView event if you don't touch it this is the code! – Yetispapa Mar 15 '19 at 16:38
1

For my after of hours of try and try with hitTest and not get positive results i found this way.

class PassThruScrollView: UIScrollView {

    var passThruViewRef: UIView?

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {

        return point.y > passThruViewRef?.frame.height ?? 0        
    }    
}

Just I had use this class in the component scroll view that i have inside the container view and everything was good.

Image like i had use my class

enter image description here

Irf
  • 4,285
  • 3
  • 36
  • 49
Wilman Rojas
  • 33
  • 1
  • 5