{"action":"created","comment":{"url":"https://api.github.com/repos/facebook/react-native/pulls/comments/31883550","id":31883550,"diff_hunk":"@@ -560,6 +560,54 @@ - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView\n \n - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset\n {\n+\n+  // snapToInterval\n+  // An alternative to enablePaging which allows setting custom stopping intervals,\n+  // smaller than a full page size. Often seen in apps which feature horizonally\n+  // scrolling items. snapToInterval does not enforce scrolling one interval at a time\n+  // but guarantees that the scroll will stop at an interval point.\n+  if(self.snapToInterval){\n+    \n+    CGFloat snapToIntervalF = (CGFloat)self.snapToInterval;\n+\n+    // Find which axis to snap\n+    BOOL isHorizontal = (scrollView.contentSize.width > self.frame.size.width);\n+\n+    // What is the current offset?\n+    CGFloat targetContentOffsetAlongAxis = isHorizontal ? targetContentOffset->x : targetContentOffset->y;\n+    //CGFloat targetContentOffsetAlongAxis = isHorizontal ? scrollView.contentOffset.x : scrollView.contentOffset.y;\n+\n+    // Which direction is the scroll travelling?\n+    CGPoint translation = [scrollView.panGestureRecognizer translationInView:scrollView];\n+    CGFloat translationAlongAxis = isHorizontal ? translation.x : translation.y;\n+    \n+    // Offset based on desired alignment \n+    CGFloat frameLength = isHorizontal ? self.frame.size.width : self.frame.size.height;\n+    CGFloat alignmentOffset = 0.0f;\n+    if([self.snapToAlignment  isEqualToString: @\"center\"]){\n+      alignmentOffset = (frameLength * 0.5f) + (snapToIntervalF * 0.5f);\n+    }\n+    else if ([self.snapToAlignment  isEqualToString: @\"end\"]) {\n+      alignmentOffset = frameLength;\n+    }\n+\n+    // Pick snap point based on direction and proximity\n+    NSInteger snapIndex = floor((targetContentOffsetAlongAxis + alignmentOffset) / snapToIntervalF);\n+    if(translationAlongAxis < 0) {\n+      snapIndex++;\n+    }\n+    CGFloat newTargetContentOffset = ( snapIndex * snapToIntervalF ) - alignmentOffset;\n+    \n+    // Set new targetContentOffset\n+    if(isHorizontal) {\n+      targetContentOffset->x = newTargetContentOffset;\n+    }\n+    else {","path":"React/Views/RCTScrollView.m","position":null,"original_position":46,"commit_id":"8c2fc9021c7b6d67220ad34cb7eabbc158543bc7","original_commit_id":"1ae08c09fef59863d426ad59465122238d77e370","user":{"login":"rxb","id":451050,"avatar_url":"https://avatars.githubusercontent.com/u/451050?v=3","gravatar_id":"","url":"https://api.github.com/users/rxb","html_url":"https://github.com/rxb","followers_url":"https://api.github.com/users/rxb/followers","following_url":"https://api.github.com/users/rxb/following{/other_user}","gists_url":"https://api.github.com/users/rxb/gists{/gist_id}","starred_url":"https://api.github.com/users/rxb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rxb/subscriptions","organizations_url":"https://api.github.com/users/rxb/orgs","repos_url":"https://api.github.com/users/rxb/repos","events_url":"https://api.github.com/users/rxb/events{/privacy}","received_events_url":"https://api.github.com/users/rxb/received_events","type":"User","site_admin":false},"body":"fixed","created_at":"2015-06-08T01:23:56Z","updated_at":"2015-06-08T01:23:56Z","html_url":"https://github.com/facebook/react-native/pull/1532#discussion_r31883550","pull_request_url":"https://api.github.com/repos/facebook/react-native/pulls/1532","_links":{"self":{"href":"https://api.github.com/repos/facebook/react-native/pulls/comments/31883550"},"html":{"href":"https://github.com/facebook/react-native/pull/1532#discussion_r31883550"},"pull_request":{"href":"https://api.github.com/repos/facebook/react-native/pulls/1532"}}},"pull_request":{"url":"https://api.github.com/repos/facebook/react-native/pulls/1532","id":37083627,"html_url":"https://github.com/facebook/react-native/pull/1532","diff_url":"https://github.com/facebook/react-native/pull/1532.diff","patch_url":"https://github.com/facebook/react-native/pull/1532.patch","issue_url":"https://api.github.com/repos/facebook/react-native/issues/1532","number":1532,"state":"open","locked":false,"title":"Definable distance pagination for ScrollView","user":{"login":"rxb","id":451050,"avatar_url":"https://avatars.githubusercontent.com/u/451050?v=3","gravatar_id":"","url":"https://api.github.com/users/rxb","html_url":"https://github.com/rxb","followers_url":"https://api.github.com/users/rxb/followers","following_url":"https://api.github.com/users/rxb/following{/other_user}","gists_url":"https://api.github.com/users/rxb/gists{/gist_id}","starred_url":"https://api.github.com/users/rxb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rxb/subscriptions","organizations_url":"https://api.github.com/users/rxb/orgs","repos_url":"https://api.github.com/users/rxb/repos","events_url":"https://api.github.com/users/rxb/events{/privacy}","received_events_url":"https://api.github.com/users/rxb/received_events","type":"User","site_admin":false},"body":"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:\r\n\r\n![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)\r\n\r\nAfter 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. \r\n\r\nThis 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`.  \r\n\r\nHere's an example of it in action:\r\nhttps://vid.me/aoby\r\n\r\nHere is some sample code to try it out yourself:\r\n\r\n```\r\nvar SnapTest = React.createClass({\r\n\r\n  render: function() {\r\n    var blocks = [];\r\n    for(var i=0; i<=30; i++){\r\n      blocks.push(\"i\");\r\n    }\r\n    var blockW = 100;\r\n    return (\r\n      <ScrollView \r\n        horizontal={true} \r\n        decelerationRate={0}\r\n        snapToInterval={blockW}\r\n        snapToAlignment=\"start\"\r\n        >\r\n        {blocks.map(function(m,i){\r\n          return (\r\n            <View key={i} style={{width: blockW, height: blockW, padding:16, backgroundColor: (i%2==0)?'cornflowerblue':'royalblue', borderWidth: 1, borderColor: \"#fff\"}}>\r\n              <Text style={{color: 'white', fontWeight: '800'}}>{i}</Text>\r\n            </View>\r\n          );\r\n        })}\r\n      </ScrollView>\r\n    );\r\n  }\r\n});\r\n```\r\n\r\nWould love to get your thoughts on this direction! \r\n\r\ncc: @brentvatne https://github.com/facebook/react-native/issues/1362","created_at":"2015-06-06T02:55:58Z","updated_at":"2015-06-08T01:23:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ae807ffbfb8a3ab04a48dc129e112e831b7a3829","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/facebook/react-native/pulls/1532/commits","review_comments_url":"https://api.github.com/repos/facebook/react-native/pulls/1532/comments","review_comment_url":"https://api.github.com/repos/facebook/react-native/pulls/comments{/number}","comments_url":"https://api.github.com/repos/facebook/react-native/issues/1532/comments","statuses_url":"https://api.github.com/repos/facebook/react-native/statuses/8c2fc9021c7b6d67220ad34cb7eabbc158543bc7","head":{"label":"rxb:master","ref":"master","sha":"8c2fc9021c7b6d67220ad34cb7eabbc158543bc7","user":{"login":"rxb","id":451050,"avatar_url":"https://avatars.githubusercontent.com/u/451050?v=3","gravatar_id":"","url":"https://api.github.com/users/rxb","html_url":"https://github.com/rxb","followers_url":"https://api.github.com/users/rxb/followers","following_url":"https://api.github.com/users/rxb/following{/other_user}","gists_url":"https://api.github.com/users/rxb/gists{/gist_id}","starred_url":"https://api.github.com/users/rxb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rxb/subscriptions","organizations_url":"https://api.github.com/users/rxb/orgs","repos_url":"https://api.github.com/users/rxb/repos","events_url":"https://api.github.com/users/rxb/events{/privacy}","received_events_url":"https://api.github.com/users/rxb/received_events","type":"User","site_admin":false},"repo":{"id":36778592,"name":"react-native","full_name":"rxb/react-native","owner":{"login":"rxb","id":451050,"avatar_url":"https://avatars.githubusercontent.com/u/451050?v=3","gravatar_id":"","url":"https://api.github.com/users/rxb","html_url":"https://github.com/rxb","followers_url":"https://api.github.com/users/rxb/followers","following_url":"https://api.github.com/users/rxb/following{/other_user}","gists_url":"https://api.github.com/users/rxb/gists{/gist_id}","starred_url":"https://api.github.com/users/rxb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rxb/subscriptions","organizations_url":"https://api.github.com/users/rxb/orgs","repos_url":"https://api.github.com/users/rxb/repos","events_url":"https://api.github.com/users/rxb/events{/privacy}","received_events_url":"https://api.github.com/users/rxb/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rxb/react-native","description":"A framework for building native apps with React.","fork":true,"url":"https://api.github.com/repos/rxb/react-native","forks_url":"https://api.github.com/repos/rxb/react-native/forks","keys_url":"https://api.github.com/repos/rxb/react-native/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rxb/react-native/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rxb/react-native/teams","hooks_url":"https://api.github.com/repos/rxb/react-native/hooks","issue_events_url":"https://api.github.com/repos/rxb/react-native/issues/events{/number}","events_url":"https://api.github.com/repos/rxb/react-native/events","assignees_url":"https://api.github.com/repos/rxb/react-native/assignees{/user}","branches_url":"https://api.github.com/repos/rxb/react-native/branches{/branch}","tags_url":"https://api.github.com/repos/rxb/react-native/tags","blobs_url":"https://api.github.com/repos/rxb/react-native/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rxb/react-native/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rxb/react-native/git/refs{/sha}","trees_url":"https://api.github.com/repos/rxb/react-native/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rxb/react-native/statuses/{sha}","languages_url":"https://api.github.com/repos/rxb/react-native/languages","stargazers_url":"https://api.github.com/repos/rxb/react-native/stargazers","contributors_url":"https://api.github.com/repos/rxb/react-native/contributors","subscribers_url":"https://api.github.com/repos/rxb/react-native/subscribers","subscription_url":"https://api.github.com/repos/rxb/react-native/subscription","commits_url":"https://api.github.com/repos/rxb/react-native/commits{/sha}","git_commits_url":"https://api.github.com/repos/rxb/react-native/git/commits{/sha}","comments_url":"https://api.github.com/repos/rxb/react-native/comments{/number}","issue_comment_url":"https://api.github.com/repos/rxb/react-native/issues/comments{/number}","contents_url":"https://api.github.com/repos/rxb/react-native/contents/{+path}","compare_url":"https://api.github.com/repos/rxb/react-native/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rxb/react-native/merges","archive_url":"https://api.github.com/repos/rxb/react-native/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rxb/react-native/downloads","issues_url":"https://api.github.com/repos/rxb/react-native/issues{/number}","pulls_url":"https://api.github.com/repos/rxb/react-native/pulls{/number}","milestones_url":"https://api.github.com/repos/rxb/react-native/milestones{/number}","notifications_url":"https://api.github.com/repos/rxb/react-native/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rxb/react-native/labels{/name}","releases_url":"https://api.github.com/repos/rxb/react-native/releases{/id}","created_at":"2015-06-03T03:51:11Z","updated_at":"2015-06-03T03:51:13Z","pushed_at":"2015-06-08T01:22:00Z","git_url":"git://github.com/rxb/react-native.git","ssh_url":"git@github.com:rxb/react-native.git","clone_url":"https://github.com/rxb/react-native.git","svn_url":"https://github.com/rxb/react-native","homepage":"http://facebook.github.io/react-native/","size":15244,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"facebook:master","ref":"master","sha":"e71230631812fe73f8887b84bb9686a41c9fed31","user":{"login":"facebook","id":69631,"avatar_url":"https://avatars.githubusercontent.com/u/69631?v=3","gravatar_id":"","url":"https://api.github.com/users/facebook","html_url":"https://github.com/facebook","followers_url":"https://api.github.com/users/facebook/followers","following_url":"https://api.github.com/users/facebook/following{/other_user}","gists_url":"https://api.github.com/users/facebook/gists{/gist_id}","starred_url":"https://api.github.com/users/facebook/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/facebook/subscriptions","organizations_url":"https://api.github.com/users/facebook/orgs","repos_url":"https://api.github.com/users/facebook/repos","events_url":"https://api.github.com/users/facebook/events{/privacy}","received_events_url":"https://api.github.com/users/facebook/received_events","type":"Organization","site_admin":false},"repo":{"id":29028775,"name":"react-native","full_name":"facebook/react-native","owner":{"login":"facebook","id":69631,"avatar_url":"https://avatars.githubusercontent.com/u/69631?v=3","gravatar_id":"","url":"https://api.github.com/users/facebook","html_url":"https://github.com/facebook","followers_url":"https://api.github.com/users/facebook/followers","following_url":"https://api.github.com/users/facebook/following{/other_user}","gists_url":"https://api.github.com/users/facebook/gists{/gist_id}","starred_url":"https://api.github.com/users/facebook/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/facebook/subscriptions","organizations_url":"https://api.github.com/users/facebook/orgs","repos_url":"https://api.github.com/users/facebook/repos","events_url":"https://api.github.com/users/facebook/events{/privacy}","received_events_url":"https://api.github.com/users/facebook/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/facebook/react-native","description":"A framework for building native apps with React.","fork":false,"url":"https://api.github.com/repos/facebook/react-native","forks_url":"https://api.github.com/repos/facebook/react-native/forks","keys_url":"https://api.github.com/repos/facebook/react-native/keys{/key_id}","collaborators_url":"https://api.github.com/repos/facebook/react-native/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/facebook/react-native/teams","hooks_url":"https://api.github.com/repos/facebook/react-native/hooks","issue_events_url":"https://api.github.com/repos/facebook/react-native/issues/events{/number}","events_url":"https://api.github.com/repos/facebook/react-native/events","assignees_url":"https://api.github.com/repos/facebook/react-native/assignees{/user}","branches_url":"https://api.github.com/repos/facebook/react-native/branches{/branch}","tags_url":"https://api.github.com/repos/facebook/react-native/tags","blobs_url":"https://api.github.com/repos/facebook/react-native/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/facebook/react-native/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/facebook/react-native/git/refs{/sha}","trees_url":"https://api.github.com/repos/facebook/react-native/git/trees{/sha}","statuses_url":"https://api.github.com/repos/facebook/react-native/statuses/{sha}","languages_url":"https://api.github.com/repos/facebook/react-native/languages","stargazers_url":"https://api.github.com/repos/facebook/react-native/stargazers","contributors_url":"https://api.github.com/repos/facebook/react-native/contributors","subscribers_url":"https://api.github.com/repos/facebook/react-native/subscribers","subscription_url":"https://api.github.com/repos/facebook/react-native/subscription","commits_url":"https://api.github.com/repos/facebook/react-native/commits{/sha}","git_commits_url":"https://api.github.com/repos/facebook/react-native/git/commits{/sha}","comments_url":"https://api.github.com/repos/facebook/react-native/comments{/number}","issue_comment_url":"https://api.github.com/repos/facebook/react-native/issues/comments{/number}","contents_url":"https://api.github.com/repos/facebook/react-native/contents/{+path}","compare_url":"https://api.github.com/repos/facebook/react-native/compare/{base}...{head}","merges_url":"https://api.github.com/repos/facebook/react-native/merges","archive_url":"https://api.github.com/repos/facebook/react-native/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/facebook/react-native/downloads","issues_url":"https://api.github.com/repos/facebook/react-native/issues{/number}","pulls_url":"https://api.github.com/repos/facebook/react-native/pulls{/number}","milestones_url":"https://api.github.com/repos/facebook/react-native/milestones{/number}","notifications_url":"https://api.github.com/repos/facebook/react-native/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/facebook/react-native/labels{/name}","releases_url":"https://api.github.com/repos/facebook/react-native/releases{/id}","created_at":"2015-01-09T18:10:16Z","updated_at":"2015-06-07T23:47:07Z","pushed_at":"2015-06-08T01:22:00Z","git_url":"git://github.com/facebook/react-native.git","ssh_url":"git@github.com:facebook/react-native.git","clone_url":"https://github.com/facebook/react-native.git","svn_url":"https://github.com/facebook/react-native","homepage":"http://facebook.github.io/react-native/","size":42103,"stargazers_count":14684,"watchers_count":14684,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":1723,"mirror_url":null,"open_issues_count":287,"forks":1723,"open_issues":287,"watchers":14684,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/facebook/react-native/pulls/1532"},"html":{"href":"https://github.com/facebook/react-native/pull/1532"},"issue":{"href":"https://api.github.com/repos/facebook/react-native/issues/1532"},"comments":{"href":"https://api.github.com/repos/facebook/react-native/issues/1532/comments"},"review_comments":{"href":"https://api.github.com/repos/facebook/react-native/pulls/1532/comments"},"review_comment":{"href":"https://api.github.com/repos/facebook/react-native/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/facebook/react-native/pulls/1532/commits"},"statuses":{"href":"https://api.github.com/repos/facebook/react-native/statuses/8c2fc9021c7b6d67220ad34cb7eabbc158543bc7"}}}}