React Native 滚动页面置顶
来源:互联网 发布:腾讯网络加速器独立版 编辑:程序博客网 时间:2024/06/14 20:00
封装:
import React, {Component} from 'react';import PropTypes from 'prop-types';import {StyleSheet, Animated, View, PanResponder, Dimensions} from 'react-native';const screen = Dimensions.get("window");class VerticalSwipe extends Component { _panResponder = null; _movable = null; _initialPositionTop = null; _hasActivatedThreshold = false; _hasMoveAction = false; stylesheets = null; static propTypes: { // Amount of pixel the user can use to swipe the window in swipeOffset: PropTypes.number.isRequired, // Threshold after which window is considered opened when moving openSwipeThreshold: PropTypes.number.isRequired, // Threshold after which window is considered closed when moving closeSwipeThreshold: PropTypes.number.isRequired, // The offset to stop when opening offsetTop: PropTypes.number.isRequired, //内容布局偏移 contentOffsetTop: PropTypes.number, //状态变化通知 onChange: PropTypes.func, //禁止拖动超过初始化swipe content ui高度(跟contentOffsetTop,offsetTop有关) lockContentTopOffset: PropTypes.bool, //拖放阈值 thresholdDrag: PropTypes.number, //Y轴变化通知 onTopChange: PropTypes.func, }; static defaultProps = { swipeOffset: 100, openSwipeThreshold: 100, closeSwipeThreshold: 50, offsetTop: 0, contentOffsetTop: 0, lockContentTopOffset: false, thresholdDrag: 8, }; initialize = () => { this._initialPositionTop = Math.floor(screen.height - this.props.contentOffsetTop - this.props.swipeOffset); let positionTopAnimatedValue = new Animated.Value(this._initialPositionTop); positionTopAnimatedValue.addListener(({value}) => { this.props.onTopChange && this.props.onTopChange(value) }); this.state = { isAnimating: false, isOpen: false, positionTop: positionTopAnimatedValue, }; const styles = { container: { flex: 1, }, swiper: { // We put a transparent background color as a hack because otherwise, moving doesn't work backgroundColor: "rgba(0, 0, 0, 0)", width: "100%", height: screen.height + 75 - this.props.offsetTop, // this.props.swipeOffset, position: "absolute", left: 0, top: this._initialPositionTop, }, innerBottom: { marginTop: this.props.swipeOffset, }, }; this.stylesheets = StyleSheet.create(styles); this.stylesheets.content = this.props.style; }; checkTopValue(top) { let result = top; if (this.props.lockContentTopOffset) { if (top < this.props.offsetTop) { result = this.props.offsetTop; } if (top > this.props.offsetTop && (top > (screen.height - this.props.contentOffsetTop - this.props.swipeOffset))) { result = this._initialPositionTop; } } return result; } onStartShouldSetPanResponder = (evt, gestureState) => { Log('onStartShouldSetPanResponder', gestureState.dy) if (this.state.isOpen) { if ((evt.nativeEvent.pageY < (this.props.openSwipeThreshold + this.props.offsetTop) && evt.nativeEvent.pageY > this.props.offsetTop)) { return false; } return true; } else { } return true; }; onStartShouldSetPanResponderCapture = (evt, gestureState) => { this._hasMoveAction = false; Log('onStartShouldSetPanResponderCapture', gestureState.dy) if (this.state.isAnimating === true) { return false; } if (Math.abs(gestureState.dy) < 5) { // Log('onStartShouldSetPanResponder false') return false; } else { return true; } if (this.state.isOpen) { if ((evt.nativeEvent.pageY < (this.props.openSwipeThreshold + this.props.offsetTop) && evt.nativeEvent.pageY > this.props.offsetTop)) { return false; } } return true; }; onPanResponderMove = (evt, gestureState) => { Log('onPanResponderMove', evt.nativeEvent.pageY, gestureState.dy) if (this.state.isAnimating === true) { return; } if(!this._hasMoveAction){ this._hasMoveAction = true; return ; } // Log(gestureState) let top; if (this.state.isOpen === false) { if (gestureState.dy < -(this.props.openSwipeThreshold) && this._hasActivatedThreshold === false) { this._hasActivatedThreshold = true; } else if (gestureState.dy >= -(this.props.openSwipeThreshold) && this._hasActivatedThreshold === true) { this._hasActivatedThreshold = false; } //增加禁止拖动超过初始化swipe content ui高度 top = screen.height - this.props.contentOffsetTop - this.props.swipeOffset + gestureState.dy; // Log('close state _hasActivatedThreshold',this._hasActivatedThreshold,gestureState.dy,top) top = this.checkTopValue(top); this._movable.setNativeProps({ style: [this.stylesheets.swiper, { top: top }] }); } else { if (gestureState.dy > this.props.closeSwipeThreshold && this._hasActivatedThreshold === false) { this._hasActivatedThreshold = true; } else if (gestureState.dy <= this.props.closeSwipeThreshold && this._hasActivatedThreshold === true) { this._hasActivatedThreshold = false; } top = -this.props.swipeOffset + this.props.offsetTop + gestureState.dy; // Log('open state _hasActivatedThreshold',this._hasActivatedThreshold,gestureState.dy,top); top = this.checkTopValue(top); //增加禁止拖动超过初始化swipe content ui高度 this._movable.setNativeProps({ style: [this.stylesheets.swiper, { top: top }] }); } this.props.onTopChange && this.props.onTopChange(top) }; onPanResponderRelease = (evt, gestureState) => { Log('onPanResponderRelease', gestureState.dy,this._hasMoveAction,this.state.isOpen) if (this._hasMoveAction) { if (this._hasActivatedThreshold) { if (this.state.isOpen === false) { let top = screen.height - this.props.contentOffsetTop - this.props.swipeOffset + gestureState.dy; top = this.checkTopValue(top); this.state.positionTop.setValue(top); this.open(); } else { let top = -this.props.swipeOffset + this.props.offsetTop + gestureState.dy; top = this.checkTopValue(top); this.state.positionTop.setValue(top); this.close(); } } else { let newTop=0; if (this.state.isOpen === false) { newTop=this._initialPositionTop; this._movable.setNativeProps({ style: [this.stylesheets.swiper, { top: newTop, }] }); } else { newTop= -this.props.swipeOffset + this.props.offsetTop; this._movable.setNativeProps({ style: [this.stylesheets.swiper, { top: newTop, }] }); } this.props.onTopChange && this.props.onTopChange(newTop) } } this._hasMoveAction = false; }; open = () => { if (this.state.isAnimating) { return; } this.setState({isAnimating: true, isOpen: true}); Animated.timing( this.state.positionTop, { toValue: -this.props.swipeOffset + this.props.offsetTop, duration: 300, } ).start(() => { if (this.props.onChange) { this.props.onChange(this.state.isOpen) } this.setState({isAnimating: false}); }) }; close = () => { if (this.state.isAnimating) { return; } this.setState({isAnimating: true, isOpen: false}); Animated.timing( this.state.positionTop, { toValue: this._initialPositionTop, duration: 300, } ).start(() => { if (this.props.onChange) { this.props.onChange(this.state.isOpen) } this.setState({isAnimating: false}); }) }; getMovableStyle = () => { return [this.stylesheets.swiper, { top: this.state.positionTop, }] }; constructor(props) { super(props); this.initialize(); } componentWillMount() { this._panResponder = PanResponder.create({ onStartShouldSetPanResponder: this.onStartShouldSetPanResponder, onStartShouldSetPanResponderCapture: this.onStartShouldSetPanResponderCapture, onMoveShouldSetPanResponder: this.onStartShouldSetPanResponder, onMoveShouldSetPanResponderCapture: this.onStartShouldSetPanResponder, onPanResponderMove: this.onPanResponderMove, onPanResponderRelease: this.onPanResponderRelease, onPanResponderTerminate: this.onPanResponderRelease }) } render() { return ( <View style={this.stylesheets.container}> <View style={this.stylesheets.content}> {this.props.children} </View> <Animated.View style={this.getMovableStyle()} ref={(ref) => this._movable = ref} {...this._panResponder.panHandlers}> <View style={this.stylesheets.innerBottom}> {this.props.content} </View> </Animated.View> </View> ); }}export default VerticalSwipe;
实现:
import React, {Component} from 'react';import { StyleSheet, View, TouchableOpacity, Alert, ScrollView, ART, TouchableHighlight, ListView, Dimensions, Text, Image} from 'react-native';const {width, height} = Dimensions.get('window');import VerticalSwipe from './VerticalSwipe'const TabState = [{title: '已发布'}, {title: '审核中'}, {title: '审核不通过'}];export default class extends React.Component { constructor(props) { super(props); this.state = { topOffset: ContentTopOffset, }; } render() { return ( <View style={styles.container} > <VerticalSwipe swipeOffset={0} lockContentTopOffset closeSwipeThreshold={50} openSwipeThreshold={50} contentOffsetTop={ContentTopOffset} offsetTop={64} style={styles.dragContainer} onTopChange={(top) => { this.setState({ topOffset: top, }) }} onChange={(isOpen) => { }} content={( <View style={styles.innerContainer}> <View style={{flexDirection: 'row', height: TabHeight}}> { TabState.map((item, index) => { return this.renderTab(index) }) } </View> <View style={{backgroundColor:'pink', height:height, width: width}} > </View> </View> )}> {this.renderTopView()} </VerticalSwipe> </View> ); } renderTab(index) { return ( <TouchableOpacity style={{flex: 1, height: TabHeight}} onPress={() => {}}> <View style={{flex: 1, justifyContent: 'center', alignItems: "center"}}> <Text style={[styles.tabTxtStyle, {marginTop: 3}]}>0</Text> <Text style={[styles.tabTxtStyle, {marginTop: 3}]}>{TabState[index].title}</Text> </View> </TouchableOpacity> ) } renderTopView = () => { let maxOffsetTop = height - ContentTopOffset; let offsetPercent = ((this.state.topOffset - 64) / (maxOffsetTop - 64)); if(offsetPercent<0.3){ offsetPercent=0; } return ( <View style={{opacity: offsetPercent,width: width, height:TopHeight}}> <Image style={{width: width, height:TopHeight, alignItems:'center', justifyContent:'center'}} source={require('../img/cellar/bg_cellar_top@2x.png')}> <Image style={{width:60, height:60, borderRadius:30}} source={require('../img/mine/ic_default@2x.png')}/> </Image> </View> ) }};const TabHeight = 56;const TopHeight = 268;const ContentTopOffset = height - TopHeight + TabHeight;const styles = StyleSheet.create({ container: { backgroundColor:'#350400', flex: 1, }, tabTxtStyle: { textAlign: 'center', color: '#c9a88d' }, tabHeightLineStyle: { width: 75, height: 1, backgroundColor: '#c9a88d', marginTop: 5 },});
效果如图:
阅读全文
0 0
- React Native 滚动页面置顶
- react native 使webview里面的页面自动滚动
- iframe页面滚动条置顶
- react-native 页面跳转
- React-native ListView不滚动
- React Native scrollview滚动事件
- react native ScrollView滚动不起作用
- react-native页面的跳转
- 加载一个react native 页面
- 加载一个react native 页面
- React Native 仿登录页面
- React Native 页面间传值总结
- react-native Navigator 页面跳转
- react-native试玩(15)-滚动视图
- react native scrollview 滚动停止事件
- React Native ListView的滚动scrollTo
- react-native ScrollView触摸与滚动事件
- react-native 页面切换的实现
- C# Event/UnityEvent辨析
- 自然语言处理-中文分词方法总结
- 今日给我办公室的电脑安装了Oracle VM VirtualBox
- 前端页面实现报警器提示音效果
- Jenkin插件开发最新方式(mvn archetype:generate -Dfilter=io.jenkins.archetypes:plugin)
- React Native 滚动页面置顶
- 软件系统开发到哪里做
- React Native 自定义实现【Toast】提示框
- 将时间格式化成字符串共同函数暂存
- GPIO及中断API函数
- CentOS7 firewall设置
- linux 命令之 curl 指定ip访问对应的域名地址
- Unity(OpenGL)实现“阴阳师画符”、划线功能
- Java技术——你真的了解String类的intern()方法吗