Permalink
Browse files

Add setPageWithoutAnimation

Summary: In some cases it's desirable to set the page in the ViewPager without animating it -- we have this in ScrollView with `scrollWithoutAnimationTo`. This PR adds `setPageWithoutAnimation` on ViewPager.

cc ide kmagiera
Closes #3621

Reviewed By: svcscm

Differential Revision: D2652056

Pulled By: mkonicek

fb-gh-sync-id: 6f1f38558c41ffdd863c0ebb2f046c75b5c0392c
  • Loading branch information...
brentvatne authored and facebook-github-bot-3 committed Nov 13, 2015
1 parent 88a92f8 commit 50b8b00768af7602c10efd6a8675fbf0b6cb691f
@@ -96,23 +96,39 @@ var ViewPagerAndroidExample = React.createClass({
description: 'Container that allows to flip left and right between child views.'
},
getInitialState: function() {
- return {page: 0, progress: {position: 0, offset: 0}};
+ return {
+ page: 0,
+ animationsAreEnabled: true,
+ progress: {
+ position: 0,
+ offset: 0,
+ },
+ };
},
+
onPageSelected: function(e) {
this.setState({page: e.nativeEvent.position});
},
+
onPageScroll: function(e) {
this.setState({progress: e.nativeEvent});
},
+
move: function(delta) {
var page = this.state.page + delta;
- this.viewPager && this.viewPager.setPage(page);
- this.setState({page});
+ this.go(page);
},
+
go: function(page) {
- this.viewPager && this.viewPager.setPage(page);
+ if (this.state.animationsAreEnabled) {
+ this.viewPager.setPage(page);
+ } else {
+ this.viewPager.setPageWithoutAnimation(page);
+ }
+
this.setState({page});
},
+
render: function() {
var pages = [];
for (var i = 0; i < PAGES; i++) {
@@ -131,7 +147,7 @@ var ViewPagerAndroidExample = React.createClass({
</View>
);
}
- var page = this.state.page;
+ var { page, animationsAreEnabled } = this.state;
return (
<View style={styles.container}>
<ViewPagerAndroid
@@ -142,6 +158,19 @@ var ViewPagerAndroidExample = React.createClass({
ref={viewPager => { this.viewPager = viewPager; }}>
{pages}
</ViewPagerAndroid>
+ <View style={styles.buttons}>
+ { animationsAreEnabled ?
+ <Button
+ text="Turn off animations"
+ enabled={true}
+ onPress={() => this.setState({animationsAreEnabled: false})}
+ /> :
+ <Button
+ text="Turn animations back on"
+ enabled={true}
+ onPress={() => this.setState({animationsAreEnabled: true})}
+ /> }
+ </View>
<View style={styles.buttons}>
<Button text="Start" enabled={page > 0} onPress={() => this.go(0)}/>
<Button text="Prev" enabled={page > 0} onPress={() => this.move(-1)}/>
@@ -2,24 +2,24 @@
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ViewPagerAndroid
+ * @flow
*/
'use strict';
+var NativeModules = require('NativeModules');
var NativeMethodsMixin = require('NativeMethodsMixin');
var React = require('React');
var ReactElement = require('ReactElement');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var ReactPropTypes = require('ReactPropTypes');
+var RCTUIManager = NativeModules.UIManager;
+
var createReactNativeComponentClass = require('createReactNativeComponentClass');
var dismissKeyboard = require('dismissKeyboard');
var VIEWPAGER_REF = 'viewPager';
-var ViewPagerValidAttributes = {
- selectedPage: true,
-};
-
/**
* Container that allows to flip left and right between child views. Each
* child view of the `ViewPagerAndroid` will be treated as a separate page
@@ -97,17 +97,17 @@ var ViewPagerAndroid = React.createClass({
]),
},
- getInitialState: function() {
- return {
- selectedPage: this.props.initialPage,
- };
+ componentDidMount: function() {
+ if (this.props.initialPage) {
+ this.setPageWithoutAnimation(this.props.initialPage);
+ }
},
- getInnerViewNode: function() {
+ getInnerViewNode: function(): ReactComponent {
return this.refs[VIEWPAGER_REF].getInnerViewNode();
},
- _childrenWithOverridenStyle: function() {
+ _childrenWithOverridenStyle: function(): Array {
// Override styles so that each page will fill the parent. Native component
// will handle positioning of elements, so it's not important to offset
// them correctly.
@@ -134,34 +134,51 @@ var ViewPagerAndroid = React.createClass({
return ReactElement.createElement(child.type, newProps);
});
},
- _onPageScroll: function(event) {
+
+ _onPageScroll: function(e: Event) {
if (this.props.onPageScroll) {
- this.props.onPageScroll(event);
+ this.props.onPageScroll(e);
}
if (this.props.keyboardDismissMode === 'on-drag') {
dismissKeyboard();
}
},
- _onPageSelected: function(event) {
- var selectedPage = event.nativeEvent.position;
- this.setState({
- selectedPage,
- });
+
+ _onPageSelected: function(e: Event) {
if (this.props.onPageSelected) {
- this.props.onPageSelected(event);
+ this.props.onPageSelected(e);
}
},
- setPage: function(selectedPage) {
- this.setState({
- selectedPage,
- });
+
+ /**
+ * A helper function to scroll to a specific page in the ViewPager.
+ * The transition between pages will be animated.
+ */
+ setPage: function(selectedPage: number) {
+ RCTUIManager.dispatchViewManagerCommand(
+ React.findNodeHandle(this),
+ RCTUIManager.AndroidViewPager.Commands.setPage,
+ [selectedPage],
+ );
},
+
+ /**
+ * A helper function to scroll to a specific page in the ViewPager.
+ * The transition between pages will be *not* be animated.
+ */
+ setPageWithoutAnimation: function(selectedPage: number) {
+ RCTUIManager.dispatchViewManagerCommand(
+ React.findNodeHandle(this),
+ RCTUIManager.AndroidViewPager.Commands.setPageWithoutAnimation,
+ [selectedPage],
+ );
+ },
+
render: function() {
return (
<NativeAndroidViewPager
ref={VIEWPAGER_REF}
style={this.props.style}
- selectedPage={this.state.selectedPage}
onPageScroll={this._onPageScroll}
onPageSelected={this._onPageSelected}
children={this._childrenWithOverridenStyle()}
@@ -171,10 +188,7 @@ var ViewPagerAndroid = React.createClass({
});
var NativeAndroidViewPager = createReactNativeComponentClass({
- validAttributes: {
- ...ReactNativeViewAttributes.UIView,
- ...ViewPagerValidAttributes,
- },
+ validAttributes: ReactNativeViewAttributes.UIView,
uiViewClassName: 'AndroidViewPager',
});
@@ -133,6 +133,12 @@ public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
+ public void setCurrentItemFromJs(int item, boolean animated) {
+ mIsCurrentItemFromJs = true;
+ setCurrentItem(item, animated);
+ mIsCurrentItemFromJs = false;
+ }
+
/*package*/ void addViewToAdapter(View child, int index) {
getAdapter().addView(child, index);
}
@@ -148,10 +154,4 @@ public boolean onInterceptTouchEvent(MotionEvent ev) {
/*package*/ View getViewFromAdapter(int index) {
return getAdapter().getViewAt(index);
}
-
- /*package*/ void setCurrentItemFromJs(int item) {
- mIsCurrentItemFromJs = true;
- setCurrentItem(item);
- mIsCurrentItemFromJs = false;
- }
}
@@ -13,18 +13,24 @@
import android.view.View;
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.common.MapBuilder;
-import com.facebook.react.uimanager.ReactProp;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
+import javax.annotation.Nullable;
+
/**
* Instance of {@link ViewManager} that provides native {@link ViewPager} view.
*/
public class ReactViewPagerManager extends ViewGroupManager<ReactViewPager> {
private static final String REACT_CLASS = "AndroidViewPager";
+ public static final int COMMAND_SET_PAGE = 1;
+ public static final int COMMAND_SET_PAGE_WITHOUT_ANIMATION = 2;
+
@Override
public String getName() {
return REACT_CLASS;
@@ -35,12 +41,6 @@ protected ReactViewPager createViewInstance(ThemedReactContext reactContext) {
return new ReactViewPager(reactContext);
}
- @ReactProp(name = "selectedPage")
- public void setSelectedPage(ReactViewPager view, int page) {
- // TODO(8496821): Handle selectedPage property cleanup correctly, now defaults to 0
- view.setCurrentItemFromJs(page);
- }
-
@Override
public boolean needsCustomLayoutForChildren() {
return true;
@@ -54,6 +54,39 @@ public Map getExportedCustomDirectEventTypeConstants() {
);
}
+ @Override
+ public Map<String,Integer> getCommandsMap() {
+ return MapBuilder.of(
+ "setPage",
+ COMMAND_SET_PAGE,
+ "setPageWithoutAnimation",
+ COMMAND_SET_PAGE_WITHOUT_ANIMATION);
+ }
+
+ @Override
+ public void receiveCommand(
+ ReactViewPager viewPager,
+ int commandType,
+ @Nullable ReadableArray args) {
+ Assertions.assertNotNull(viewPager);
+ Assertions.assertNotNull(args);
+ switch (commandType) {
+ case COMMAND_SET_PAGE: {
+ viewPager.setCurrentItemFromJs(args.getInt(0), true);
+ return;
+ }
+ case COMMAND_SET_PAGE_WITHOUT_ANIMATION: {
+ viewPager.setCurrentItemFromJs(args.getInt(0), false);
+ return;
+ }
+ default:
+ throw new IllegalArgumentException(String.format(
+ "Unsupported command %d received by %s.",
+ commandType,
+ getClass().getSimpleName()));
+ }
+ }
+
@Override
public void addView(ReactViewPager parent, View child, int index) {
parent.addViewToAdapter(child, index);

0 comments on commit 50b8b00

Please sign in to comment.