Preface: A week has passed, has been in demand, in addition to their own use of spare time to study the outside there is no time to study new things, Alas ~ Program Ape is so, live to learn old!! Nonsense not to say, the company's products feel a certain e-commerce Product Details page very nice, asked if we can achieve (baby heart bitter ), so studied a wave, the following to my study of things to share, small partners have what good way to achieve also thank you for sharing oh ~ humbly!
Let's look at the results of the final implementation:
Ios/android
Simply put is divided into two parts (up and down), two are (ScrollView, flatlist) and other sliding components, the first scrollview sliding to the bottom, continue to pull up the second ScrollView, When the second scrollview down to the top, continue to pull back to the first ScrollView and the first scrollview back to the top.
Here's my general idea:
The first way:
Using the RN gesture, and then listening to ScrollView's sliding events, we all know that the event delivery in Rn is passed down from the parent control layer to the next level, so the parent control can intercept the ability of the ScrollView, which is the child control. When ScrollView slides to the bottom or top of the block ScrollView event, the event to the parent control, and then through the control of the parent control of the vertical offset first paging function, said so much theory of things small partner estimates are tired, we followed together with the code to say a bit.
The second way:
Encapsulating a native component for pull-up and pull-down operations, RN only needs to do some simple listening.
Two ways to compare, can use RN to achieve the best, because the purpose of RN is to achieve cross-platform purposes, are using native to achieve the use of Rn do!! That said, but RN still provides developers with a custom method, the second way to achieve a bit is the performance and experience is better than the RN implementation, I will follow the combination of two ways to achieve.
Let's start with the first way.
First step (divide the page into two parts):
Render () {return (<view Style={[styles.container]} > {/* First part */} <animated.view style={[styles.container1,{ma Rgintop:this._aniback.interpolate ({inputrange:[0,1], Outputrange:
[0,-screen_h],})}]} {... this._panresponder.panhandlers} > <animated.view ref={(ref) = This._container1 = ref } style={{width:screen_w, Height:screen_h, Margintop:this._aniback1.
Interpolate ({inputrange:[0,1], outputrange:[0,-100], })}} > <scrollview r ef={(ref) =>this._scroLl1=ref} Bounces={false} scrolleventthrottle={10}
Onscroll={this._onscroll.bind (This)} overscrollmode={' Never '}
> {this._getcontent ()} </ScrollView> </Animated.View> <view style={{width:screen_w,height:100,backgroundcolor: ' White ', Alignitems: ' Center ', justifycontent: ' Center '}}> <Text> Pull-up view details </Text> </vie W> </Animated.View> {/* Second part */} <view Styl
E={styles.container2} {... this._panresponder2.panhandlers} >
<animated.view ref={(ref) = This._container2 = ref} style={{ WiDth:screen_w,height:100,backgroundcolor: ' White ', Alignitems: ' Center ', justifycontent: ' Center ', m Argintop:this._aniback2.interpolate ({inputrange:[0,1], ou
tputrange:[-100,0],})} >
<Text> pull back to top </Text> </Animated.View> <view
Style={{width:screen_w, Height:screen_h,}} > <scrollview
ref={(ref) =>this._scroll2=ref} Bounces={false}
SCROLLEVENTTHROTTLE={10} onscroll={this._onscroll2.bind (This)}
overscrollmode={' Never '} > {this._getcontent ()} </scrollview> </View> </View> </View>); }
Code I will post it later, the principle is very simple, I basically say my implementation of the idea, run the code you will find that the page is showing a red page (that is, the upper part).
Let's margintop the first page to-screen_h (screen height), we will see the second screen Blue page
So we just need to swipe the ScrollView on the first red page, then intercept the event, and when the finger is lifted, the margintop of the first page is shifted from (0 to-screen height), and we animate it at the same time. So here's the problem. How do we listen to the ScrollView to the top or the bottom? How do we intercept ScrollView's events?
The monitor ScrollView reaches the top or bottom:
at the top we all know that when the ScrollView y-axis offsets =0 We think ScrollView is at the top and the code is:
_onscroll2 (event) {
this._reachend2=false;
Let y = event.nativeevent.contentoffset.y;
if (y<=0) {
//arrive at the top of
this._reachend2=true;
}
}
at the bottom is when (the height of the child control =y the distance of the axis sliding + the height of the parent control), the transition code is:
_onscroll (event) {
this._reachend1=false;
Let y = event.nativeevent.contentoffset.y;
let height = event.nativeEvent.layoutMeasurement.height;
Let contentheight = Event.nativeEvent.contentSize.height;
if (Contentheight > Height && (y + height >= contentheight)) {
//reach top of
this._reachend1=true;
}
}
The parent control intercepts the events of the child control:
We return true in Onmoveshouldsetpanrespondercapture, the parent control is to intercept the slide event and then hand it to itself (onpanrespondermove), then our red page (i.e. the first page) When the scrollview reaches the bottom, and then pulls up, we intercept the event
_handlemoveshouldsetpanrespondercapture (Event:object, Gesturestate:object,): boolean {
Console.log (' _ Handlemoveshouldsetpanrespondercapture ');
Console.log (gesturestate.dy);
When you swipe to the bottom and continue to pull up,
return this._reachend1&&gesturestate.dy<0;
}
Our second page (the Blue page) intercepts the event when ScrollView slides to the top and continues to pull down:
_handlemoveshouldsetpanrespondercapture2 (Event:object, Gesturestate:object,): boolean {
console.log ( Gesturestate.dy);
Console.log (' _handlemoveshouldsetpanrespondercapture2 ');
When you swipe to the top and continue to pull down,
return this._reachend2&&gesturestate.dy>=0;
}
Okay ~ Our first page of the parent control gets the swipe event, we continue to pull up, that is, to pull up the distance to our "Pull up View Details" component:
_handlepanrespondermove (Event:object, gesturestate:object): void {
Prevent the event interception is not allowed, we set ScrollView's Scrollenabled:false to False
This._scroll1.setnativeprops ({
Scrollenabled:false
})
Let Nowleft =gesturestate.dy*0.5;
Controls the "pull-up View Details" component display for a page
This._container1.setnativeprops ({
Margintop:nowleft
})
Console.log (' _handlepanrespondermove ', gesturestate.dy);
<animated.view ref={(ref) = This._container1 = ref} Style={{width
: Screen_w, Height:screen_h, Margintop:this._aniback1.interpolate ({
inputrange:[0,1], outputrange:[0,-100],})}}
> <scrollview ref={(ref) =>this._scroll1=ref} Bounces={false} scrolleventthrottle={10} OnS
Croll={this._onscroll.bind (This)} overscrollmode={' Never '} > {this._getcontent ()} </ScrollView> </ANIMATED.V iew> <view style={{width:screen_w,height:100,backgroundcolor: ' White ', Alignitems: ' Center ', justify
Content: ' Center '}}> <Text> Pull-up view details </Text> </View>
The
Code is very simple, I do not explain, the small partner to run their own look at Ha, the following is the first way of all implementation code, run directly on it:
/** * Sample React Native App * https://github.com/facebook/react-native * @flow */import React, {Component} from ' r
Eact '; Import {Platform, StyleSheet, Text, View, touchableopacity, Dimensions, ScrollView, panre
Sponder, Animated, StatusBar,} from ' react-native ';
Const SCREEN_W = dimensions.get (' window '). Width; Const SCREEN_H = dimensions.get (' window '). height-(platform.os=== ' Android '?
statusbar.currentheight:0);
Import Swiperow from './swiperow ';
Export default class App extends Component {//construct constructor (props) {super (props); Initial state//initial state This._panresponder = Panresponder.create ({Onmoveshouldsetpanresponderca Pture:this._handlemoveshouldsetpanrespondercapture.bind (this), Onstartshouldsetrespondercapture:this._handl
Emoveshouldsetpanrespondercapture.bind (This), Onpanrespondermove:this._handlepanrespondermove.bind (this), OnpanrespoNderrelease:this._handlepanresponderend.bind (This), Onpanrespondergrant:this._handlepangrant.bind (this),
Onpanresponderterminate: () =>{console.log (' onpanresponderterminate ');
This._aniback1.setvalue (0);
Animated.spring (this._aniback1,{tovalue:1}). Start (() =>{
This._handlepanresponderend ();
}); }, Onshouldblocknativeresponder: (event, gesturestate) = false,//Indicates whether to use the Native platform event handling, default is disabled, all use JS of things
This function is currently only available on Android platforms}); This._panresponder2 = Panresponder.create ({Onmoveshouldsetpanrespondercapture:this._handlemoveshouldsetpan Respondercapture2.bind (this), Onstartshouldsetrespondercapture:this._handlemoveshouldsetpanrespondercapture2
. Bind (this), Onpanrespondermove:this._handlepanrespondermove2.bind (this), Onpanresponderrelease:this._handlepanresponderend2.bind (this), onpanrespondergrant:this._handlepangrant2.b
IND (this), Onpanresponderterminate: () =>{This._container2.setnativeprops ({
margintop:0})
This._aniback2.setvalue (0);
Animated.spring (this._aniback2,{tovalue:1}). Start (() =>{
This._handlepanresponderend2 ();
});
Console.log (' OnPanResponderTerminate2 '); }, Onshouldblocknativeresponder: (event, gesturestate) = false,//Indicates whether to use the Native platform event handling, default is disabled, all use JS of things
This function is currently only available on Android platforms});
This._reachend1=false;
This._reachend2=true;
This._aniback=new animated.value (0);
This._aniback1=new animated.value (0);
This._aniback2=new animated.value (0); } _handlepangranT (Event:object, Gesturestate:object,) {This._scroll1.setnativeprops ({scrollenabled:false}) } _handlemoveshouldsetpanrespondercapture (Event:object, Gesturestate:object,): boolean {Console.log (' _
Handlemoveshouldsetpanrespondercapture ');
Console.log (Gesturestate.dy);
Return this._reachend1&&gesturestate.dy<0;
} _handlepanrespondermove (Event:object, gesturestate:object): void {This._scroll1.setnativeprops ({
Scrollenabled:false}) let Nowleft =gesturestate.dy*0.5; This._container1.setnativeprops ({margintop:nowleft}) console.log (' _handlepanrespondermove ', g
Esturestate.dy);
} _handlepanresponderend (Event:object, gesturestate:object): void {this._aniback.setvalue (0);
This._scroll1.setnativeprops ({scrollenabled:true}) This._scroll1.scrollto ({y:0},true); Animated.tiMing (This._aniback, {duration:500, tovalue:1}). Start ();
This._aniback1.setvalue (1);
Animated.spring (This._aniback1, {tovalue:0}). Start (); } _handlemoveshouldsetpanrespondercapture2 (Event:object, Gesturestate:object,): boolean {console.log (GES
Turestate.dy);
Console.log (' _handlemoveshouldsetpanrespondercapture2 ');
Return this._reachend2&&gesturestate.dy>=0; } _handlepanrespondermove2 (Event:object, gesturestate:object): void {console.log (' _handlepanrespondermove
2 ');
Let Nowleft =gesturestate.dy*0.5;
This._scroll2.setnativeprops ({scrollenabled:false}) This._container2.setnativeprops ({
Margintop:-100+nowleft}) Console.log (' _handlepanrespondermove2 ', gesturestate.dy);
} _handlepangrant2 (Event:object, Gesturestate:object,) {This._scroll2.setnativeprops ({ Scrollenabled:false})} _handlepanresponderend2 (Event:object, gesturestate:object): void {
This._aniback.setvalue (1);
This._scroll2.setnativeprops ({scrollenabled:true}) animated.timing (This._aniback, {
duration:500, tovalue:0}). Start ();
This._aniback2.setvalue (1);
Animated.spring (This._aniback2, {tovalue:0}). Start ();
} render () {return (<view Style={[styles.container]} >
{/* First part */} <animated.view style={[styles.container1,{ Margintop:this._aniback.interpolate ({inputrange:[0,1], output Range:[0,-screen_h],})}]} {... This._panresponder.panhand
Lers} > <animated.view ref={(ref) = This._container1 = ref} style=
{{width:screen_w, Height:screen_h, Margintop:this._aniback1.interpolate ({
inputrange:[0,1], outputrange:[0,-100],})}}
> <scrollview ref={(ref) =>this._scroll1=ref}
Bounces={false} scrolleventthrottle={10}
Onscroll={this._onscroll.bind (This)} overscrollmode={' Never '} > {this._getcontent ()} </ScrollView> </ani Mated. view> <view style={{width:screen_w,height:100,backgroundcolor: ' White ', Alignitems: ' Center ', justif Ycontent: ' Center '}}> <Text> Pull-up View details </Text> </View> </anima Ted.
view> {/* Second part */} <view Style={styles.container2}
{... this._panresponder2.panhandlers} > <animated.view ref={(ref) = This._container2 = ref} style={{Width:screen_w , Height:100,backgroundcolor: ' White ', Alignitems: ' Center ', justifycontent: ' Center ', Margintop:thi S._aniback2.interpolate ({inputrange:[