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 https://github.com/facebook/react-native/pull/3621 Reviewed By: svcscm Differential Revision: D2652056 Pulled By: mkonicek fb-gh-sync-id: 6f1f38558c41ffdd863c0ebb2f046c75b5c0392c
This commit is contained in:
parent
88a92f8f52
commit
50b8b00768
|
@ -96,23 +96,39 @@ var ViewPagerAndroidExample = React.createClass({
|
||||||
description: 'Container that allows to flip left and right between child views.'
|
description: 'Container that allows to flip left and right between child views.'
|
||||||
},
|
},
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {page: 0, progress: {position: 0, offset: 0}};
|
return {
|
||||||
|
page: 0,
|
||||||
|
animationsAreEnabled: true,
|
||||||
|
progress: {
|
||||||
|
position: 0,
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
onPageSelected: function(e) {
|
onPageSelected: function(e) {
|
||||||
this.setState({page: e.nativeEvent.position});
|
this.setState({page: e.nativeEvent.position});
|
||||||
},
|
},
|
||||||
|
|
||||||
onPageScroll: function(e) {
|
onPageScroll: function(e) {
|
||||||
this.setState({progress: e.nativeEvent});
|
this.setState({progress: e.nativeEvent});
|
||||||
},
|
},
|
||||||
|
|
||||||
move: function(delta) {
|
move: function(delta) {
|
||||||
var page = this.state.page + delta;
|
var page = this.state.page + delta;
|
||||||
this.viewPager && this.viewPager.setPage(page);
|
this.go(page);
|
||||||
this.setState({page});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
go: function(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});
|
this.setState({page});
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var pages = [];
|
var pages = [];
|
||||||
for (var i = 0; i < PAGES; i++) {
|
for (var i = 0; i < PAGES; i++) {
|
||||||
|
@ -131,7 +147,7 @@ var ViewPagerAndroidExample = React.createClass({
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
var page = this.state.page;
|
var { page, animationsAreEnabled } = this.state;
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<ViewPagerAndroid
|
<ViewPagerAndroid
|
||||||
|
@ -142,6 +158,19 @@ var ViewPagerAndroidExample = React.createClass({
|
||||||
ref={viewPager => { this.viewPager = viewPager; }}>
|
ref={viewPager => { this.viewPager = viewPager; }}>
|
||||||
{pages}
|
{pages}
|
||||||
</ViewPagerAndroid>
|
</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}>
|
<View style={styles.buttons}>
|
||||||
<Button text="Start" enabled={page > 0} onPress={() => this.go(0)}/>
|
<Button text="Start" enabled={page > 0} onPress={() => this.go(0)}/>
|
||||||
<Button text="Prev" enabled={page > 0} onPress={() => this.move(-1)}/>
|
<Button text="Prev" enabled={page > 0} onPress={() => this.move(-1)}/>
|
||||||
|
|
|
@ -2,24 +2,24 @@
|
||||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* @providesModule ViewPagerAndroid
|
* @providesModule ViewPagerAndroid
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var NativeModules = require('NativeModules');
|
||||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||||
var React = require('React');
|
var React = require('React');
|
||||||
var ReactElement = require('ReactElement');
|
var ReactElement = require('ReactElement');
|
||||||
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
||||||
var ReactPropTypes = require('ReactPropTypes');
|
var ReactPropTypes = require('ReactPropTypes');
|
||||||
|
|
||||||
|
var RCTUIManager = NativeModules.UIManager;
|
||||||
|
|
||||||
var createReactNativeComponentClass = require('createReactNativeComponentClass');
|
var createReactNativeComponentClass = require('createReactNativeComponentClass');
|
||||||
var dismissKeyboard = require('dismissKeyboard');
|
var dismissKeyboard = require('dismissKeyboard');
|
||||||
|
|
||||||
var VIEWPAGER_REF = 'viewPager';
|
var VIEWPAGER_REF = 'viewPager';
|
||||||
|
|
||||||
var ViewPagerValidAttributes = {
|
|
||||||
selectedPage: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container that allows to flip left and right between child views. Each
|
* Container that allows to flip left and right between child views. Each
|
||||||
* child view of the `ViewPagerAndroid` will be treated as a separate page
|
* child view of the `ViewPagerAndroid` will be treated as a separate page
|
||||||
|
@ -97,17 +97,17 @@ var ViewPagerAndroid = React.createClass({
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
componentDidMount: function() {
|
||||||
return {
|
if (this.props.initialPage) {
|
||||||
selectedPage: this.props.initialPage,
|
this.setPageWithoutAnimation(this.props.initialPage);
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getInnerViewNode: function() {
|
getInnerViewNode: function(): ReactComponent {
|
||||||
return this.refs[VIEWPAGER_REF].getInnerViewNode();
|
return this.refs[VIEWPAGER_REF].getInnerViewNode();
|
||||||
},
|
},
|
||||||
|
|
||||||
_childrenWithOverridenStyle: function() {
|
_childrenWithOverridenStyle: function(): Array {
|
||||||
// Override styles so that each page will fill the parent. Native component
|
// Override styles so that each page will fill the parent. Native component
|
||||||
// will handle positioning of elements, so it's not important to offset
|
// will handle positioning of elements, so it's not important to offset
|
||||||
// them correctly.
|
// them correctly.
|
||||||
|
@ -134,34 +134,51 @@ var ViewPagerAndroid = React.createClass({
|
||||||
return ReactElement.createElement(child.type, newProps);
|
return ReactElement.createElement(child.type, newProps);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
_onPageScroll: function(event) {
|
|
||||||
|
_onPageScroll: function(e: Event) {
|
||||||
if (this.props.onPageScroll) {
|
if (this.props.onPageScroll) {
|
||||||
this.props.onPageScroll(event);
|
this.props.onPageScroll(e);
|
||||||
}
|
}
|
||||||
if (this.props.keyboardDismissMode === 'on-drag') {
|
if (this.props.keyboardDismissMode === 'on-drag') {
|
||||||
dismissKeyboard();
|
dismissKeyboard();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_onPageSelected: function(event) {
|
|
||||||
var selectedPage = event.nativeEvent.position;
|
_onPageSelected: function(e: Event) {
|
||||||
this.setState({
|
|
||||||
selectedPage,
|
|
||||||
});
|
|
||||||
if (this.props.onPageSelected) {
|
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() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<NativeAndroidViewPager
|
<NativeAndroidViewPager
|
||||||
ref={VIEWPAGER_REF}
|
ref={VIEWPAGER_REF}
|
||||||
style={this.props.style}
|
style={this.props.style}
|
||||||
selectedPage={this.state.selectedPage}
|
|
||||||
onPageScroll={this._onPageScroll}
|
onPageScroll={this._onPageScroll}
|
||||||
onPageSelected={this._onPageSelected}
|
onPageSelected={this._onPageSelected}
|
||||||
children={this._childrenWithOverridenStyle()}
|
children={this._childrenWithOverridenStyle()}
|
||||||
|
@ -171,10 +188,7 @@ var ViewPagerAndroid = React.createClass({
|
||||||
});
|
});
|
||||||
|
|
||||||
var NativeAndroidViewPager = createReactNativeComponentClass({
|
var NativeAndroidViewPager = createReactNativeComponentClass({
|
||||||
validAttributes: {
|
validAttributes: ReactNativeViewAttributes.UIView,
|
||||||
...ReactNativeViewAttributes.UIView,
|
|
||||||
...ViewPagerValidAttributes,
|
|
||||||
},
|
|
||||||
uiViewClassName: 'AndroidViewPager',
|
uiViewClassName: 'AndroidViewPager',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,12 @@ import com.facebook.react.uimanager.events.NativeGestureUtil;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCurrentItemFromJs(int item, boolean animated) {
|
||||||
|
mIsCurrentItemFromJs = true;
|
||||||
|
setCurrentItem(item, animated);
|
||||||
|
mIsCurrentItemFromJs = false;
|
||||||
|
}
|
||||||
|
|
||||||
/*package*/ void addViewToAdapter(View child, int index) {
|
/*package*/ void addViewToAdapter(View child, int index) {
|
||||||
getAdapter().addView(child, index);
|
getAdapter().addView(child, index);
|
||||||
}
|
}
|
||||||
|
@ -148,10 +154,4 @@ import com.facebook.react.uimanager.events.NativeGestureUtil;
|
||||||
/*package*/ View getViewFromAdapter(int index) {
|
/*package*/ View getViewFromAdapter(int index) {
|
||||||
return getAdapter().getViewAt(index);
|
return getAdapter().getViewAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ void setCurrentItemFromJs(int item) {
|
|
||||||
mIsCurrentItemFromJs = true;
|
|
||||||
setCurrentItem(item);
|
|
||||||
mIsCurrentItemFromJs = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,14 @@ import java.util.Map;
|
||||||
|
|
||||||
import android.view.View;
|
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.common.MapBuilder;
|
||||||
import com.facebook.react.uimanager.ReactProp;
|
|
||||||
import com.facebook.react.uimanager.ThemedReactContext;
|
import com.facebook.react.uimanager.ThemedReactContext;
|
||||||
import com.facebook.react.uimanager.ViewGroupManager;
|
import com.facebook.react.uimanager.ViewGroupManager;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instance of {@link ViewManager} that provides native {@link ViewPager} view.
|
* Instance of {@link ViewManager} that provides native {@link ViewPager} view.
|
||||||
*/
|
*/
|
||||||
|
@ -25,6 +28,9 @@ public class ReactViewPagerManager extends ViewGroupManager<ReactViewPager> {
|
||||||
|
|
||||||
private static final String REACT_CLASS = "AndroidViewPager";
|
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
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return REACT_CLASS;
|
return REACT_CLASS;
|
||||||
|
@ -35,12 +41,6 @@ public class ReactViewPagerManager extends ViewGroupManager<ReactViewPager> {
|
||||||
return new ReactViewPager(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
|
@Override
|
||||||
public boolean needsCustomLayoutForChildren() {
|
public boolean needsCustomLayoutForChildren() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -54,6 +54,39 @@ public class ReactViewPagerManager extends ViewGroupManager<ReactViewPager> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
public void addView(ReactViewPager parent, View child, int index) {
|
public void addView(ReactViewPager parent, View child, int index) {
|
||||||
parent.addViewToAdapter(child, index);
|
parent.addViewToAdapter(child, index);
|
||||||
|
|
Loading…
Reference in New Issue