美文网首页
react-native ScrollView吸顶效果

react-native ScrollView吸顶效果

作者: MasterPaul | 来源:发表于2019-04-23 11:08 被阅读0次
QQ20190423-105919-HD.gif

原理在屏幕外部渲染一个fixHeader,通过监听scrollview的滚动offset,控制是否显示fixHeader
全部代码如下


/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View,ScrollView,Image,TouchableWithoutFeedback,TextInput,Animated} from 'react-native';
import screen from '../util/Screen'
import appColor from '../util/appColor'
import Swiper  from 'react-native-swiper'
import  {ImageButton, BaseHeader} from '../widget'
import HouseRateView from '../components/Detail/HouseRateView'
import {Card} from 'react-native-shadow-cards'
import testJson from '../assets/detail'

const Pixel_644 = screen.scaleSize(644)
const Pixel_108 = screen.scaleSize(108)
const navHeight = screen.statusBarHeight + screen.headerHeight



const similerHouse = [
    {
        id:2553, circ:'一拍', start_time:'2018年09月20日',   title:'深圳市宝安区观澜镇高尔夫大道观澜豪园*假日*赛维纳E栋L座0701',
        similer_id:575627984615,    currentPrice:1208600,   consultPrice:1637000,   discount:73.8,
        area:65,    price:'18,594', house_id:108779049
    },
    {
        id:2553, circ:'一拍', start_time:'2018年09月20日',   title:'深圳市宝安区观澜镇高尔夫大道观澜豪园*假日*赛维纳E栋L座0701',
        similer_id:575627984615,    currentPrice:1208600,   consultPrice:1637000,   discount:73.8,
        area:65,    price:'18,594', house_id:108779049
    },
    {
        id:2553, circ:'一拍', start_time:'2018年09月20日',   title:'深圳市宝安区观澜镇高尔夫大道观澜豪园*假日*赛维纳E栋L座0701',
        similer_id:575627984615,    currentPrice:1208600,   consultPrice:1637000,   discount:73.8,
        area:65,    price:'18,594', house_id:108779049
    },
]

const menuItems =  [
    {
        image:require('../image/basic_info.png'),
        title:'基本信息'
    },
    {
        image:require('../image/court_announce.png'),
        title:'法院公告'
    },
    {
        image:require('../image/house_value.png'),
        title:'房产价值'
    },
    {
        image:require('../image/school.png'),
        title:'学校'
    },
]


export default class Detail extends Component<Props> {


    static navigationOptions = ({navigation}) =>({
        header:null
    })


    constructor(props){
        super(props);
        this._onScroll = this._onScroll.bind(this)
        this._onStop = this._onStop.bind(this)
        this.renderFixHeader = this.renderFixHeader.bind(this)

        this.fixHeaderY = 500
    }

    state = {
        swiperItems: [require('../image/01.jpg'),require('../image/02.jpg'),require('../image/banner1.jpg')],
        page: 1,
        data:[1,2,3,4,5],
        navOpacity:0,
        scrollY:new Animated.Value(0),
        currentPage:0
    }

    renderHeaderView(){
        return (
            <View style={{height:Pixel_644 ,width:screen.width}}>

                <Swiper
                    style={{position:'absolute',left:0,top:0, width: screen.width}}
                    height={Pixel_644}
                    showsButtons={false}
                    removeClippedSubviews={false} //这个很主要啊,解决白屏问题
                    autoplay={true}
                    horizontal={true}
                    antoplayTimeout={2}
                    autoplayDirection={true}
                    dotStyle={styles.dotStyle}
                    activeDotStyle={styles.activeDotStyle}
                    paginationStyle={styles.paginationStyle}
                >
                    {
                        this.state.swiperItems.map((item, index) => {
                            return (<Image style={{ height:Pixel_644, width: screen.width }}
                                           key={index}
                                           resizeMode='cover'
                                           source={item} />)
                        })
                    }
                </Swiper>

            </View>
        )
    }

    renderHouseCard(){
        return(
            <Card
                style={{padding:screen.PIXEL_20,marginTop:-10, marginLeft:screen.PIXEL_10,marginBottom:screen.PIXEL_20,
                    marginRight:screen.PIXEL_10,width:screen.width - screen.PIXEL_20}}
            >
                <View style={{flexDirection:'row',alignItems:'center'}}>
                    <Text style={{flex:1,fontSize:25,color:'#000'}} numberOfLines={2}>{testJson.title}</Text>
                    <View style={{marginLeft:screen.PIXEL_70}}>
                        <View style={{flexDirection:'row',alignItems:'center'}}>
                            <Image source={require('../image/alert.png')} style={{width:screen.PIXEL_30,height:screen.PIXEL_30}}/>
                            <Text>提醒</Text>
                        </View>
                        <View style={{flexDirection:'row', marginTop:screen.PIXEL_10,alignItems:'center'}}>
                            <Image source={require('../image/share.png')} style={{width:screen.PIXEL_30,height:screen.PIXEL_30}}/>
                            <Text>分享</Text>
                        </View>
                    </View>
                </View>
                <View style={{marginTop:screen.PIXEL_10}}>
                    <Text style={{color:appColor.textColor3,fontSize:18}}>{testJson.start_time}
                        <Text style={{color:'#000',fontSize:23}}> 至 </Text>
                        <Text> {testJson.end_time} </Text>
                    </Text>
                    <Text style={{color:appColor.textColor4}}>{testJson.applyCount}人报名  {testJson.noticeCnt}人设置提醒  {testJson.viewerCount}次围观</Text>
                    <View style={{height:1,marginTop:screen.PIXEL_10,marginLeft:0, marginRight:0,backgroundColor:appColor.textColor4}}/>
                </View>

                <View style={{flexDirection:'row',marginTop:screen.PIXEL_10}}>
                    <View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
                        <Text style={{fontSize:18,color:appColor.textColor4}}>起拍价</Text>
                        <Text style={{fontSize:18,color:'#e98d75',fontWeight:'bold'}}>1143万</Text>
                    </View>
                    <View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
                        <Text style={{fontSize:18,color:appColor.textColor4}}>法院评估价</Text>
                        <Text style={{fontSize:18,color:'#e98d75',fontWeight:'bold'}}>1143万</Text>
                    </View>
                    <View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
                        <Text style={{fontSize:18,color:appColor.textColor4}}>市场评估价</Text>
                        <Text style={{fontSize:18,color:'#e98d75',fontWeight:'bold'}}>1143万</Text>
                    </View>

                </View>

                <View style={{marginTop:screen.PIXEL_20,flexDirection:'row',justifyContent:'space-around'}}>
                    <View style={{width:screen.scaleSize(196),height:screen.scaleSize(45),backgroundColor:'#e8f3f7',
                        justifyContent:'center',alignItems:'center',borderRadius:screen.PIXEL_10
                    }}>
                        <Text style={{fontSize:10,color:appColor.textBlueColor}}>8折</Text>
                    </View>
                    <View style={{width:screen.scaleSize(196),height:screen.scaleSize(45),backgroundColor:'#e8f3f7',
                        justifyContent:'center',alignItems:'center',borderRadius:screen.PIXEL_10
                    }}>
                        <Text style={{fontSize:10,color:'#a1ccd7'}}>一拍</Text>
                    </View>
                    <View style={{width:screen.scaleSize(196),height:screen.scaleSize(45),backgroundColor:'#e3f3eb',
                        justifyContent:'center',alignItems:'center',borderRadius:screen.PIXEL_10
                    }}>
                        <Text style={{fontSize:10,color:'#76b999'}}>住宅</Text>
                    </View>
                </View>

            </Card>
        )
    }

    renderMenuItem(item,index){

        let isSelect = this.state.currentPage == index

        return (
            <TouchableWithoutFeedback
                key={index}
                onPress={()=>{
                    if(index > 0){
                        //法院公告
                        this.props.navigation.navigate('DetailSecond',{index:index-1})
                    }

                    // this.setState({
                    //     currentPage:index
                    // })
                }}
            >
                <View style={{flex:1,justifyContent:'center',alignItems:'center',
                    borderBottomColor:'#fff',borderBottomWidth:isSelect ? 3 : 0,
                }}>
                    <Image source={item.image} style={{width:screen.PIXEL_40,height:screen.PIXEL_40}}/>
                    <Text style={{fontSize:16,color:'#fff',marginTop:screen.PIXEL_10}}>{item.title}</Text>
                </View>
            </TouchableWithoutFeedback>
        )
    }

    renderSelectView(){

        let itemViews = []
        menuItems.map((item,index)=>{

            let itemView = this.renderMenuItem(item,index)
            itemViews.push(itemView)
        })

        return(
            <View style={ {width:screen.width,height:screen.PIXEL_120,backgroundColor:'#2198f2',flexDirection:'row'} }
                  onLayout={(e)=>{
                      console.log(e.nativeEvent)
                      this.fixHeaderY = e.nativeEvent.layout.y
                  }}
            >
                {itemViews}
            </View>
        )
    }

    renderInfoView(){
        return(
            <View style={{width:screen.width,paddingLeft:screen.PIXEL_20,paddingRight:screen.PIXEL_20}}>
                <View style={{flexDirection:'row',marginTop:screen.PIXEL_10}}>
                    <View style={{flex:1}}>
                        <Text style={{fontSize:18,color:appColor.textColor4}}>保证金:
                            <Text style={{color:appColor.textColor2}}>  {(testJson.forecast_safe/10000).toFixed(0)}万</Text>
                        </Text>
                    </View>
                    <View style={{flex:1}}>
                        <Text style={{fontSize:18,color:appColor.textColor4}}>单价:
                            <Text style={{color:appColor.textColor2}}>  {testJson.average.toFixed(0)}/㎡</Text>
                        </Text>
                    </View>
                </View>
                <View style={{flexDirection:'row',marginTop:screen.PIXEL_10}}>
                    <View style={{flex:1}}>
                        <Text style={{fontSize:18,color:appColor.textColor4}}>楼层:
                            <Text style={{color:appColor.textColor2}}>  {testJson.floor}</Text>
                        </Text>
                    </View>
                    <View style={{flex:1}}>
                        <Text style={{fontSize:18,color:appColor.textColor4}}>年代:
                            <Text style={{color:appColor.textColor2}}>  {testJson.build_time}</Text>
                        </Text>
                    </View>
                </View>

                <Text style={{fontSize:18,color:appColor.textColor4,marginTop:screen.PIXEL_10}}>面积:
                    <Text style={{color:appColor.textColor2}}>  {testJson.area}㎡</Text>
                </Text>
                <Text style={{fontSize:18,color:appColor.textColor4,marginTop:screen.PIXEL_10}}>税费:
                    <Text style={{color:appColor.textColor2}}>  {testJson.tax}</Text>
                </Text>
                <Text style={{fontSize:18,color:appColor.textColor4,marginTop:screen.PIXEL_10}}>小区:
                    <Text style={{color:appColor.textColor2}}>  {testJson.community_name}</Text>
                </Text>
                <Text style={{fontSize:18,color:appColor.textColor4,marginTop:screen.PIXEL_10}}>学校:
                    <Text style={{color:appColor.textColor2}}>  {testJson.area}㎡</Text>
                </Text>
                <Text style={{fontSize:18,color:appColor.textColor4,marginTop:screen.PIXEL_10}}>轨交:
                    <Text style={{color:appColor.textColor2}}>  {testJson.area}㎡</Text>
                </Text>
                <View style={{flexDirection:'row',width:screen.width,marginTop:screen.PIXEL_10}}>
                    <Text style={{fontSize:18,color:appColor.textColor4,width:screen.PIXEL_90}}>位置:</Text>
                    <Text style={{fontSize:18,color:appColor.textColor2,width:screen.width-screen.PIXEL_120}} numberOfLines={2}>  {testJson.location}</Text>

                </View>

                <View style={{flex:1,height:0.3,backgroundColor:appColor.textColor4,marginTop:screen.PIXEL_10,}}/>


            </View>
        )
    }

    //同区历史成交
    renderSimilerHouse(){

        let cells = [];
        similerHouse.map((item,index)=>{

            let subtitle = `${item.discount}折 单价${item.price}/㎡ 面积${item.area}㎡`;
                let cell = (
                <View style={{flex:1,height:screen.PIXEL_230,flexDirection:'row'}}
                      key={index}
                >
                    <View style={{alignItems:'center'}}>
                        <View style={{width:screen.PIXEL_30,height:screen.PIXEL_30,borderRadius:screen.PIXEL_30/2,backgroundColor:appColor.navBgColor,overflow:'hidden'}}/>
                        <View style={{width:screen.PIXEL_10/2,flex:1,backgroundColor:appColor.navBgColor}}/>
                    </View>
                    <View style={{flex:1,marginLeft:screen.PIXEL_40,marginRight:screen.PIXEL_20}}>
                        <Text style={{fontSize:18,color:appColor.textColor2,marginTop:screen.PIXEL_10}} numberOfLines={3}>{item.title}</Text>
                        <Text style={{fontSize:17,color:appColor.textColor4,marginTop:screen.PIXEL_20}} numberOfLines={1}>{subtitle}</Text>
                    </View>
                    <Text style={{fontSize:18,color:'#d6949b',alignSelf:'center'}}>{(item.currentPrice/10000).toFixed(0)}万</Text>
                </View>
            )
            cells.push(cell)
        })

        return(
            <View style={{width:screen.width,padding:screen.PIXEL_20}}>
                <View style={{flex:1, flexDirection:'row',marginBottom:screen.PIXEL_10}}>
                    <Text style={{fontSize:18,color:appColor.textColor2,flex:1}}>同区历史成交</Text>
                    <TouchableWithoutFeedback
                        onPress={()=>{
                            this.props.navigation.navigate('DetailSecond',{index:1})
                        }}
                    >
                        <View style={{flexDirection:'row', alignItems:'center'}}>
                            <Text style={{fontSize:18,color:appColor.textBlueColor}}>更多</Text>
                            <Image source={require('../image/right.png')} style={{width:screen.PIXEL_30,height:screen.PIXEL_30,tintColor:appColor.textBlueColor}}/>
                        </View>
                    </TouchableWithoutFeedback>

                </View>

                {cells}
            </View>
        )
    }

    renderBottomView(){
        return(
            <View style={{height:screen.PIXEL_120,flexDirection:'row',alignItems:'center',backgroundColor:'#fff'}}>
                <TouchableWithoutFeedback>
                <View style={{width:screen.PIXEL_230,alignItems:'center'}}>
                    <Image source={require('../image/collect1.png')} style={{width:screen.PIXEL_50,height:screen.PIXEL_50}}/>
                    <Text style={{fontSize:17,color:appColor.textColor4}}>加入收藏</Text>
                </View>
                </TouchableWithoutFeedback>
                <View style={{flex:1,flexDirection:'row',height:screen.PIXEL_100}}>
                    <TouchableWithoutFeedback>
                    <View style={{flex:1,justifyContent:'center',alignItems:'center',backgroundColor:'#ffae7a'}}>
                        <Text style={{color:'#fff',fontSize:20}}>一键贷款</Text>
                    </View>
                    </TouchableWithoutFeedback>
                    <TouchableWithoutFeedback>
                        <View style={{flex:1,justifyContent:'center',alignItems:'center',backgroundColor:appColor.navBgColor}}>
                            <Text style={{color:'#fff',fontSize:20}}>马上咨询</Text>
                        </View>
                    </TouchableWithoutFeedback>
                </View>
            </View>
        )
    }

    renderFixHeader() {

        let showY = this.state.scrollY.interpolate({

            inputRange: [0, this.fixHeaderY, this.fixHeaderY, this.fixHeaderY],

            outputRange: [-9999, -9999, 0, 0]

        })

        console.log(showY)

        let itemViews = []
        menuItems.map((item,index)=>{
            let itemView = this.renderMenuItem(item,index)
            itemViews.push(itemView)
        })

        return(
            <Animated.View style={ {
                position: 'absolute', top: navHeight, left: 0,
                width:screen.width,height:screen.PIXEL_120,backgroundColor:'#2198f2',flexDirection:'row',
                transform: [
                    {translateY: showY}
                ]

            }}

            >
                {itemViews}
            </Animated.View>
        )
    }


    render() {

        let leftItem = (
            <TouchableWithoutFeedback
                onPress={()=>{
                    this.props.navigation.goBack()
                }}
            >
                <View >

                    <View style={{width:screen.PIXEL_80, height:screen.PIXEL_80,
                        borderRadius:screen.PIXEL_40,backgroundColor:'#000',opacity:this.state.navOpacity < 0.5 ?  0.5 : 0}}/>
                    <View style={{position:'absolute',justifyContent:'center',alignItems:'center',top:0,left:0,bottom:0,right:0}}>
                        <Image source={require('../image/back_white.png')}
                               resizeMode={'contain'}
                               style={{width:screen.PIXEL_50,height:screen.PIXEL_50}}/>
                    </View>


                </View>
            </TouchableWithoutFeedback>
        )
        let rightItem = (

            <TouchableWithoutFeedback
                onPress={()=>{
                    this.props.navigation.goBack()
                }}
            >
                <View >
                    <View style={{width:screen.PIXEL_80, height:screen.PIXEL_80,
                        borderRadius:screen.PIXEL_40,backgroundColor:'#000',opacity:this.state.navOpacity < 1 ? 0.5 : 0}}/>

                    <View style={{position:'absolute',justifyContent:'center',alignItems:'center',top:0,left:0,bottom:0,right:0}}>
                        <Image source={require('../image/collect.png')}
                               resizeMode={'contain'}
                               style={{width:screen.PIXEL_50,height:screen.PIXEL_50}}/>
                    </View>


                </View>
            </TouchableWithoutFeedback>
        )

        return (
            <View style={styles.container}>
                <BaseHeader
                    ref={ref=>this.navBar = ref}
                    title={'详情'}
                    opacity={this.state.navOpacity}
                    leftItem={leftItem}
                    rightItem={rightItem}

                />
                <ScrollView
                    ref={ref=>{ this._scrollView = ref }}
                    style={{marginTop:-navHeight}}
                    // onScroll={this._onScroll}
                    onScroll={Animated.event(
                        [{nativeEvent: {contentOffset: {y: this.state.scrollY}}}],
                        {listener:this._onScroll}
                    )}
                    onScrollEndDrag={this._onStop}
                    scrollEventThrottle={16}
                >

                    {this.renderHeaderView()}

                    {this.renderHouseCard()}

                    {this.renderSelectView()}

                    {this.renderInfoView()}

                    {this.renderSimilerHouse()}

                    <HouseRateView />


                </ScrollView>

                {this.renderBottomView()}

                {this.renderFixHeader()}
            </View>
        );
    }

    _onScroll(event){
        let y = event.nativeEvent.contentOffset.y + navHeight;
        console.log(y)

        if (y < Pixel_644) {
            this.setState({
                navOpacity:0
            })

        } else {

            this.setState({
                navOpacity:1
            })
        }
    }

    _onStop(e){
        let {x,y}= e.nativeEvent.contentOffset
        // console.log(y)
        // let fixY = this.fixHeaderY - screen.statusBarHeight - screen.headerHeight;

    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    paginationStyle: {
        bottom: 20,
    },
    dotStyle: {
        width: 8,
        height: 8,
        backgroundColor: '#fff',
        opacity: 0.4,
        borderRadius: 4,
    },
    activeDotStyle: {
        width: 8,
        height: 8,
        backgroundColor: '#00ad63',
        borderRadius: 4,
    },
});


相关文章

网友评论

      本文标题:react-native ScrollView吸顶效果

      本文链接:https://www.haomeiwen.com/subject/nawmgqtx.html