Skip to content

Definable distance pagination for ScrollView#1532

Closed
rxb wants to merge 2 commits into
react:masterfrom
rxb:master
Closed

Definable distance pagination for ScrollView#1532
rxb wants to merge 2 commits into
react:masterfrom
rxb:master

Conversation

@rxb

@rxb rxb commented Jun 6, 2015

Copy link
Copy Markdown
Contributor

This is an enhancement for ScrollView that adds the ability to paginate based on a width other than the width of the ScrollView itself. This is a fairly common pattern used on apps like Facebook, App Store, and Twitter to scroll through a horizontal set of cards or icons:

img_8726 2 img_8727 2 img_8728 2

After trying to accomplish this only with JS, it appears that attempting to take over an in-progress native scroll animation with JS is always going to result in some amount of jankiness and jumping.

This pull request uses scrollViewWillEndDragging in RCTScrollView.m to adjust targetContentOffset based on two new optional props added to ScrollView. snapToInterval sets the multiple that the ScrollView will come to rest on. snapToAlignment sets the relative alignment of the snap start, center, or end.

Here's an example of it in action:
https://vid.me/aoby

Here is some sample code to try it out yourself:

var SnapTest = React.createClass({

  render: function() {
    var blocks = [];
    for(var i=0; i<=30; i++){
      blocks.push("i");
    }
    var blockW = 100;
    return (
      <ScrollView 
        horizontal={true} 
        decelerationRate={0}
        snapToInterval={blockW}
        snapToAlignment="start"
        >
        {blocks.map(function(m,i){
          return (
            <View key={i} style={{width: blockW, height: blockW, padding:16, backgroundColor: (i%2==0)?'cornflowerblue':'royalblue', borderWidth: 1, borderColor: "#fff"}}>
              <Text style={{color: 'white', fontWeight: '800'}}>{i}</Text>
            </View>
          );
        })}
      </ScrollView>
    );
  }
});

Would love to get your thoughts on this direction!

cc: @brentvatne #1362

@facebook-github-bot facebook-github-bot added GH Review: review-needed CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. labels Jun 6, 2015
@brentvatne

Copy link
Copy Markdown
Collaborator

This looks great, I'll read over more carefully and try it out tonight 😄 edit: scratch that, went on massive run today and am totally exhausted, tomorrow 👍

Comment thread React/Views/RCTScrollView.m Outdated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment can go

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@brentvatne

Copy link
Copy Markdown
Collaborator

@rxb - could you also squash these commits into one?

@brentvatne

Copy link
Copy Markdown
Collaborator

Not sure who owns ScrollView cc @tadeuzagallo @nicklockwood

@rxb

rxb commented Jun 8, 2015

Copy link
Copy Markdown
Contributor Author

@brentvatne Thanks for the notes. Everything except for the isHorizontal question is fixed and squashed into 1 commit.

@rxb

rxb commented Jun 11, 2015

Copy link
Copy Markdown
Contributor Author

What do you think about tweaking the api to match up with the CSS scroll-snap-points spec?
http://www.w3.org/TR/css-snappoints-1/#scroll-snap-type

Looks like it will be in most browsers soon:
http://caniuse.com/#feat=css-snappoints
https://www.chromestatus.com/features/5721832506261504

@brentvatne

Copy link
Copy Markdown
Collaborator

@rxb - Absolutely! I think the closer that we can be to the w3 spec the better. Great point, can you adjust accordingly? cc @vjeux

@vjeux

vjeux commented Jun 11, 2015

Copy link
Copy Markdown
Contributor

Have you tried paginate={true} on ScrollView, doesn't it solve your use case?

@brentvatne

Copy link
Copy Markdown
Collaborator

@vjeux - there are several problems with paginate={true}:

  • Fixed page size to the viewport width
    • If it were to support variable widths, it would need to have an option to specify where to snap to (middle, left-side, right-side)
  • Horizontal paging only

Like in the screenshots that @rxb posted in the original comment above, it's quite common to want to snap to something other than the viewport width

@ide

ide commented Jun 11, 2015

Copy link
Copy Markdown
Contributor

You can support variable widths with pagination with a couple of tricks -- that is how the Apple Photos app works.

The core difference between pagination and scroll snapping is that pagination snaps to the next page even if you swipe hard, while scroll snapping accounts for momentum so you could end up several pages away.

@rxb

rxb commented Jun 11, 2015

Copy link
Copy Markdown
Contributor Author

I think where that difference matters most is when you are scrolling through items that are not close to the screen width, like photos on FB profiles:
https://vid.me/V4Bz

It would be rough if it forced one-at-a-time, but free scrolling would feel like driving on a greased track.

@sahrens

sahrens commented Jun 13, 2015

Copy link
Copy Markdown
Contributor

@nicklockwood: what do you think of this?

@rxb

rxb commented Jun 17, 2015

Copy link
Copy Markdown
Contributor Author

@brentvatne Awesome, I'll sync things up with the W3C spec.

After testing this in a more realistic screen -- where the horizontal scrolling section is one part of a longer vertical scrollview -- ran into that nested scrolling bug from: #41 .

@vjeux

vjeux commented Jul 15, 2015

Copy link
Copy Markdown
Contributor

Just wanted to said that I patched this to prototype a use case that we wanted to do internally and it works really well :)

Sorry it takes so long to review :(

Comment thread React/Views/RCTScrollView.m Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge conflict artifact?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the catch, fixed.

@rxb

rxb commented Jul 15, 2015

Copy link
Copy Markdown
Contributor Author

@vjeux Happy to hear it worked for you.

I keep meaning to get back to this and tweak to match the W3C scroll snap points spec. Would love to get anyone's thoughts on this interface:

Enable snapping
http://www.w3.org/TR/css-snappoints-1/#scroll-snap-type
prop: scrollSnapType
values: none proximity (mandatory could be supported in the future )

Set snapping interval
http://www.w3.org/TR/css-snappoints-1/#propdef-scroll-snap-points-x
prop: scrollSnapPoints (W3C spec defines scroll-snap-points-x and scroll-snap-points-y independently, but it seems that RN encourages scrolling in one direction at a time)
values: none repeat([interval in pixels]) (The repeat seems unnecessary, but it is part of the spec.)

Set alignment of snap relative to scroll container
http://www.w3.org/TR/css-snappoints-1/#propdef-scroll-snap-destination
prop: scrollSnapDestination
values: [offset in pixels] (Spec defines values for x and y offsets together, but this seems unnecessary if RN ScrollViews are only scrolling in one direction. Setting this explicitly in pixels gives more flexibility, but is more work than start, center, end )

@sahrens

sahrens commented Jul 15, 2015

Copy link
Copy Markdown
Contributor

ping @nicklockwood

@chirag04

Copy link
Copy Markdown
Contributor

+1

Just stumbled upon this while looking to detect page changes on a horizontal listview. This could be useful i guess.

@chirag04

Copy link
Copy Markdown
Contributor

@vjeux Does it make sense to emulate css api if it is not part of style?

My 2cents: I liked the initial api suggested by @rxb.

@vjeux

vjeux commented Jul 24, 2015

Copy link
Copy Markdown
Contributor

The guideline is to first try to design the best API based on what exists on iOS, Android, web... Then once we found one, if it is close enough to the web one, it's preferable to use it. If the web one doesn't make sense, we shouldn't tie ourself to it

@chirag04

Copy link
Copy Markdown
Contributor

any thoughts one this one?

cc @nicklockwood

@chirag04

chirag04 commented Aug 2, 2015

Copy link
Copy Markdown
Contributor

@vjeux Mind sharing the patch? Wondering if anyone is having any opinions on this. Happy to implement thoughts that others may have.

@syrusakbary

Copy link
Copy Markdown

Would love having this patch merged into react native!
👍

@vjeux

vjeux commented Sep 15, 2015

Copy link
Copy Markdown
Contributor

@facebook-github-bot shipit

@facebook-github-bot

Copy link
Copy Markdown
Contributor

Thanks for importing. If you are an FB employee go to https://our.intern.facebook.com/intern/opensource/github/pull_request/437412899771084/int_phab to review.

@chirag04

Copy link
Copy Markdown
Contributor

Awesome. Thanks 👍

Lrn flashcards will use this ;)

@vjeux

vjeux commented Sep 15, 2015

Copy link
Copy Markdown
Contributor

"Failed to apply patch". @rxb would you be willing to rebase? Sorry for the wait

@rxb

rxb commented Sep 15, 2015

Copy link
Copy Markdown
Contributor Author

Should be back in business, rebased with master. The Travis e2e test is failing, but I can't tell if that's because of something in this PR or a general thing that's happening. Seems like almost all the recent PRs are failing that.

@vjeux

vjeux commented Sep 15, 2015

Copy link
Copy Markdown
Contributor

Travis is broken because of our android push. Unlikely your fault

miracle2k added a commit to miracle2k/react-native that referenced this pull request Sep 16, 2015
@vjeux

vjeux commented Sep 22, 2015

Copy link
Copy Markdown
Contributor

@facebook-github-bot shipit

@facebook-github-bot

Copy link
Copy Markdown
Contributor

Thanks for importing. If you are an FB employee go to https://our.intern.facebook.com/intern/opensource/github/pull_request/437412899771084/int_phab to review.

@ghost ghost closed this in dcf245a Sep 23, 2015
@rxb

rxb commented Sep 23, 2015

Copy link
Copy Markdown
Contributor Author

Thanks, everybody!

@vjeux

vjeux commented Sep 23, 2015

Copy link
Copy Markdown
Contributor

Thanks for sticking with us and sorry it took that much time!

MattFoley pushed a commit to skillz/react-native that referenced this pull request Nov 9, 2015
Summary: This is an enhancement for ScrollView that adds the ability to paginate based on a width other than the width of the ScrollView itself. This is a fairly common pattern used on apps like Facebook, App Store, and Twitter to scroll through a horizontal set of cards or icons:

![img_8726 2](https://cloud.githubusercontent.com/assets/451050/8017899/39f9f47c-0bd2-11e5-9c1d-889452f20cf7.PNG) ![img_8727 2](https://cloud.githubusercontent.com/assets/451050/8017898/39f962dc-0bd2-11e5-98b4-461ac0f7f21b.PNG)  ![img_8728 2](https://cloud.githubusercontent.com/assets/451050/8017900/39fd91a4-0bd2-11e5-8786-4cf0316295a0.PNG)

After trying to accomplish this only with JS, it appears that attempting to take over an in-progress native scroll animation with JS is always going to result in some amount of jankiness and jumping.

This pull request uses `scrollViewWillEndDragging` in RCTScrollView.m to adjust `targetContentOffset` based on two new optional props added to ScrollView. `snapToInterval` sets the multiple that the
Closes react#1532

Reviewed By: @​svcscm, @​trunkagent

Differential Revision: D2443701

Pulled By: @vjeux
@aleclarson

Copy link
Copy Markdown
Contributor

I'm surprised an onSnap prop wasn't included. Thoughts?

@erickreutz

Copy link
Copy Markdown
Contributor

Any plans to bring this functionality to Android?

@me-abhinav

Copy link
Copy Markdown

+1 for Android

@me-abhinav

me-abhinav commented Oct 6, 2016

Copy link
Copy Markdown

I can create a pull request for Android if the owner wants.

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.