Skip to content

Commit

Permalink
Add onPageScrollStateChanged for ViewPagerAndroid
Browse files Browse the repository at this point in the history
Summary:
I have an issue when combining `PullToRefreshViewAndroid` and `ViewPagerAndroid`.
`ViewPagerAndroid` will not able to scroll that gesture handler is being taken by `PullToRefreshViewAndroid`
One solution is to disable `PullToRefreshViewAndroid` if `ViewPagerAndroid` is scrolling (i.e. not idle).
[Reference solution here](http://stackoverflow.com/a/29946734/2590265)

So here need to expose the `onPageScrollStateChanged` event.
Some code referenced from  DrawerLayoutAndroid, especially the `VIEWPAGER_PAGE_SCROLL_STATES` array.
Please feel free give me comments.
Thanks.
Closes facebook#5026

Reviewed By: svcscm

Differential Revision: D2830623

Pulled By: andreicoman11

fb-gh-sync-id: c2a6920c6f4c7daab0115f13864db83b93b31abf
  • Loading branch information
Kudo authored and facebook-github-bot-9 committed Jan 29, 2016
1 parent 5e82094 commit 8de86a0
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 1 deletion.
11 changes: 11 additions & 0 deletions Examples/UIExplorer/ViewPagerAndroidExample.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ var {
ViewPagerAndroid,
} = React;

import type { ViewPagerScrollState } from 'ViewPagerAndroid';

var PAGES = 5;
var BGCOLOR = ['#fdc08e', '#fff6b9', '#99d1b7', '#dde5fe', '#f79273'];
var IMAGE_URIS = [
Expand Down Expand Up @@ -114,6 +116,10 @@ var ViewPagerAndroidExample = React.createClass({
this.setState({progress: e.nativeEvent});
},

onPageScrollStateChanged: function(state : ViewPagerScrollState) {
this.setState({scrollState: state});
},

move: function(delta) {
var page = this.state.page + delta;
this.go(page);
Expand Down Expand Up @@ -155,6 +161,7 @@ var ViewPagerAndroidExample = React.createClass({
initialPage={0}
onPageScroll={this.onPageScroll}
onPageSelected={this.onPageSelected}
onPageScrollStateChanged={this.onPageScrollStateChanged}
ref={viewPager => { this.viewPager = viewPager; }}>
{pages}
</ViewPagerAndroid>
Expand All @@ -170,6 +177,7 @@ var ViewPagerAndroidExample = React.createClass({
enabled={true}
onPress={() => this.setState({animationsAreEnabled: true})}
/> }
<Text style={styles.scrollStateText}>ScrollState[ {this.state.scrollState} ]</Text>
</View>
<View style={styles.buttons}>
<Button text="Start" enabled={page > 0} onPress={() => this.go(0)}/>
Expand Down Expand Up @@ -207,6 +215,9 @@ var styles = StyleSheet.create({
buttonText: {
color: 'white',
},
scrollStateText: {
color: '#99d1b7',
},
container: {
flex: 1,
backgroundColor: 'white',
Expand Down
25 changes: 25 additions & 0 deletions Libraries/Components/ViewPager/ViewPagerAndroid.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ var requireNativeComponent = require('requireNativeComponent');

var VIEWPAGER_REF = 'viewPager';

type Event = Object;

export type ViewPagerScrollState = $Enum<{
idle: string;
dragging: string;
settling: string;
}>;

/**
* Container that allows to flip left and right between child views. Each
* child view of the `ViewPagerAndroid` will be treated as a separate page
Expand Down Expand Up @@ -78,6 +86,16 @@ var ViewPagerAndroid = React.createClass({
*/
onPageScroll: ReactPropTypes.func,

/**
* Function called when the page scrolling state has changed.
* The page scrolling state can be in 3 states:
* - idle, meaning there is no interaction with the page scroller happening at the time
* - dragging, meaning there is currently an interaction with the page scroller
* - settling, meaning that there was an interaction with the page scroller, and the
* page scroller is now finishing it's closing or opening animation
*/
onPageScrollStateChanged: ReactPropTypes.func,

/**
* This callback will be called once ViewPager finish navigating to selected page
* (when user swipes between pages). The `event.nativeEvent` object passed to this
Expand Down Expand Up @@ -147,6 +165,12 @@ var ViewPagerAndroid = React.createClass({
}
},

_onPageScrollStateChanged: function(e: Event) {
if (this.props.onPageScrollStateChanged) {
this.props.onPageScrollStateChanged(e.nativeEvent.pageScrollState);
}
},

_onPageSelected: function(e: Event) {
if (this.props.onPageSelected) {
this.props.onPageSelected(e);
Expand Down Expand Up @@ -183,6 +207,7 @@ var ViewPagerAndroid = React.createClass({
ref={VIEWPAGER_REF}
style={this.props.style}
onPageScroll={this._onPageScroll}
onPageScrollStateChanged={this._onPageScrollStateChanged}
onPageSelected={this._onPageSelected}
children={this._childrenWithOverridenStyle()}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

package com.facebook.react.views.viewpager;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;

/**
* Event emitted by {@link ReactViewPager} when user scrolling state changed.
*
* Additional data provided by this event:
* - pageScrollState - {Idle,Dragging,Settling}
*/
class PageScrollStateChangedEvent extends Event<PageScrollStateChangedEvent> {

public static final String EVENT_NAME = "topPageScrollStateChanged";

private final String mPageScrollState;

protected PageScrollStateChangedEvent(int viewTag, long timestampMs, String pageScrollState) {
super(viewTag, timestampMs);
mPageScrollState = pageScrollState;
}

@Override
public String getEventName() {
return EVENT_NAME;
}

@Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
}

private WritableMap serializeEventData() {
WritableMap eventData = Arguments.createMap();
eventData.putString("pageScrollState", mPageScrollState);
return eventData;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,22 @@ public void onPageSelected(int position) {

@Override
public void onPageScrollStateChanged(int state) {
// don't send events
String pageScrollState;
switch (state) {
case SCROLL_STATE_IDLE:
pageScrollState = "idle";
break;
case SCROLL_STATE_DRAGGING:
pageScrollState = "dragging";
break;
case SCROLL_STATE_SETTLING:
pageScrollState = "settling";
break;
default:
throw new IllegalStateException("Unsupported pageScrollState");
}
mEventDispatcher.dispatchEvent(
new PageScrollStateChangedEvent(getId(), SystemClock.uptimeMillis(), pageScrollState));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public boolean needsCustomLayoutForChildren() {
public Map getExportedCustomDirectEventTypeConstants() {
return MapBuilder.of(
PageScrollEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageScroll"),
PageScrollStateChangedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageScrollStateChanged"),
PageSelectedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageSelected")
);
}
Expand Down

0 comments on commit 8de86a0

Please sign in to comment.