欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

通過React-Native實(shí)現(xiàn)自定義橫向滑動(dòng)進(jìn)度條的 ScrollView組件

 更新時(shí)間:2024年02月05日 11:36:09   作者:清風(fēng)不暖人  
開發(fā)一個(gè)首頁擺放菜單入口的ScrollView可滑動(dòng)組件,允許自定義橫向滑動(dòng)進(jìn)度條,且內(nèi)部渲染的菜單內(nèi)容支持自定義展示的行數(shù)和列數(shù),在內(nèi)容超出屏幕后,渲染順序?yàn)榭v向由上至下依次排列,對React Native橫向滑動(dòng)進(jìn)度條相關(guān)知識(shí)感興趣的朋友一起看看吧

概要

本篇文章概述了通過React-Native實(shí)現(xiàn)一個(gè)允許自定義橫向滑動(dòng)進(jìn)度條的ScrollView組件。

需求

開發(fā)一個(gè)首頁擺放菜單入口的ScrollView可滑動(dòng)組件(類似某淘首頁上的菜單效果),允許自定義橫向滑動(dòng)進(jìn)度條,且內(nèi)部渲染的菜單內(nèi)容支持自定義展示的行數(shù)和列數(shù),在內(nèi)容超出屏幕后,渲染順序?yàn)榭v向由上至下依次排列。

Animated 動(dòng)畫

點(diǎn)此進(jìn)入學(xué)習(xí)

ScrollView 滑動(dòng)組件

點(diǎn)此進(jìn)入學(xué)習(xí)

自定義滑動(dòng)進(jìn)度條

確定參數(shù)

首先,讓我們確定一下自定義滑動(dòng)進(jìn)度條需要哪些參數(shù)來支持:

  • 初始位置時(shí),確定顯示進(jìn)度的條的寬度(barWidth)
  • 滑動(dòng)進(jìn)度,以此來確定上面這個(gè)條的位置現(xiàn)在應(yīng)該到哪里了(marLeftAnimated)

計(jì)算參數(shù)

1.想要確定顯示進(jìn)度的條的寬度(barWidth),那么必須先知道三個(gè)值:

  • ScrollView總寬度(containerStyle傳入)
  • 進(jìn)度條背景的寬度(indicatorBgStyle傳入)
  • ScrollView內(nèi)部內(nèi)容總寬度(childWidth,通過onContentSizeChange方法測量)

然后我們就可以進(jìn)行如下計(jì)算,這樣得到的_barWidth就是顯示進(jìn)度的條的寬度(barWidth):

let _barWidth = (this.props.indicatorBgStyle.width * this.props.containerStyle.width) / this.state.childWidth;

2.想要確定顯示進(jìn)度的條的位置(marLeftAnimated),那么必須先知道兩個(gè)值:

  • ScrollView可滑動(dòng)距離(scrollDistance)
  • 進(jìn)度部分可滑動(dòng)距離(leftDistance)

然后我們就可以進(jìn)行如下定義,這樣得到的marLeftAnimated,輸出值即為進(jìn)度條的距左距離:

let scrollDistance = this.state.childWidth - this.props.containerStyle.width
	...
    //顯示滑動(dòng)進(jìn)度部分的距左距離
    let leftDistance = this.props.indicatorBgStyle.width - _barWidth;
    const scrollOffset = this.state.scrollOffset
    this.marLeftAnimated = scrollOffset.interpolate({
      inputRange: [0, scrollDistance],  //輸入值區(qū)間為內(nèi)容可滑動(dòng)距離
      outputRange: [0, leftDistance],  //映射輸出區(qū)間為進(jìn)度部分可改變距離
      extrapolate: 'clamp',  //鉗制輸出值
      useNativeDriver: true,
    })

滑動(dòng)進(jìn)度條的實(shí)現(xiàn)

通過Animated.View,定義絕對位置,將兩個(gè)條在Z軸上下重疊一起。

<View style={[{alignSelf:'center'},this.props.indicatorBgStyle]}>
      <Animated.View
        style={[this.props.indicatorStyle,{
          position: 'absolute',
          width: this.state.barWidth,
          top: 0,
          left: this.marLeftAnimated,
        }]}
      />
    </View>

之后就通過onSroll事件獲取滑動(dòng)偏移量,然后通過偏移量改變動(dòng)畫的值,這里我就不多說了,不明白的可以看我上一篇文章。

首頁定制菜單

確定參數(shù)

首先,讓我們確定一下實(shí)現(xiàn)首頁定制菜單需要哪些參數(shù)來支持:

  • 列數(shù)量(columnLimit)
  • 行數(shù)量(rowLimit)

渲染方式

根據(jù)行列數(shù)量,決定每屏的菜單總數(shù)。根據(jù)行數(shù)量,決定渲染結(jié)果數(shù)組里有幾組,一行就是一組。

let optionTotalArr = [];  //存放所有option樣式的數(shù)組
	//根據(jù)行數(shù),聲明用于存放每一行渲染內(nèi)容的數(shù)組
	for( let i = 0; i < rowLimit; i++ ) optionTotalArr.push([])

1.沒超出屏幕時(shí),確定渲染行的方式如下:

if(index < columnLimit * rowLimit){
		//沒超出一屏數(shù)量時(shí),根據(jù)列數(shù)更新行標(biāo)識(shí)
		rowIndex = parseInt(index / columnLimit)
	}

2.超出屏幕時(shí),確定渲染行的方式如下:

//當(dāng)超出一屏數(shù)量時(shí),根據(jù)行數(shù)更新行標(biāo)識(shí)
	rowIndex = index % rowLimit;

遍歷輸出

根據(jù)行數(shù),遍歷存放計(jì)算后的行內(nèi)容數(shù)組。

optionTotalArr[rowIndex].push(
        <TouchableOpacity 
          key={index} 
          activeOpacity={0.7}
          style={[styles.list_item,{width:size}]} 
          onPress={()=>alert(item.name)}
        >
          <View style={{width:size-20,backgroundColor:'#FFCC00',alignItems:'center',justifyContent:'center'}}>
           <Text style={{ fontSize:18, color:'#333',marginVertical:20}}>{item.name}</Text>
          </View>
		</TouchableOpacity>
	)

效果圖

在這里插入圖片描述

源碼

IndicatorScrollView.js

import React, { PureComponent } from 'react';
import {
  StyleSheet,
  View,
  ScrollView,
  Animated,
  Dimensions,
} from 'react-native';
import PropTypes from 'prop-types';
const { width, height } = Dimensions.get('window');
export default class IndicatorScrollView extends PureComponent {
  static propTypes = {
    //最外層樣式(包含ScrollView及滑動(dòng)進(jìn)度條的全部區(qū)域
    containerStyle: PropTypes.oneOfType([  
      PropTypes.object,
      PropTypes.array,
    ]),
    //ScrollView的樣式
    style: PropTypes.oneOfType([
      PropTypes.object,
      PropTypes.array,
    ]),
    //滑動(dòng)進(jìn)度條底部樣式
    indicatorBgStyle: PropTypes.oneOfType([
      PropTypes.object,
      PropTypes.array,
    ]),
    //滑動(dòng)進(jìn)度條樣式
    indicatorStyle: PropTypes.oneOfType([
      PropTypes.object,
      PropTypes.array,
    ]),
  }
  static defaultProps = {
    containerStyle: { width: width },
    style: {},
    indicatorBgStyle:{
      width: 200,
      height: 20, 
      backgroundColor: '#ddd'
    },
    indicatorStyle:{
      height:20,
      backgroundColor:'#000'
    },
  }
  constructor(props) {
    super(props);
    this.state = {
      //滑動(dòng)偏移量
      scrollOffset: new Animated.Value(0),
      //ScrollView子布局寬度
      childWidth: this.props.containerStyle.width,
      //顯示滑動(dòng)進(jìn)度部分條的長度
      barWidth: props.indicatorBgStyle.width / 2,
    };
  }
  UNSAFE_componentWillMount() {
    this.animatedEvent = Animated.event(
      [{
          nativeEvent: {
            contentOffset: { x: this.state.scrollOffset }
          }
      }]
    )
  }
  componentDidUpdate(prevProps, prevState) {
    //內(nèi)容可滑動(dòng)距離
    let scrollDistance = this.state.childWidth - this.props.containerStyle.width
    if( scrollDistance > 0 && prevState.childWidth != this.state.childWidth){
      let _barWidth = (this.props.indicatorBgStyle.width * this.props.containerStyle.width) / this.state.childWidth;
      this.setState({
        barWidth: _barWidth,
      })
      //顯示滑動(dòng)進(jìn)度部分的距左距離
      let leftDistance = this.props.indicatorBgStyle.width - _barWidth;
      const scrollOffset = this.state.scrollOffset
      this.marLeftAnimated = scrollOffset.interpolate({
        inputRange: [0, scrollDistance],  //輸入值區(qū)間為內(nèi)容可滑動(dòng)距離
        outputRange: [0, leftDistance],  //映射輸出區(qū)間為進(jìn)度部分可改變距離
        extrapolate: 'clamp',  //鉗制輸出值
        useNativeDriver: true,
      })
    }
  }
  render() {
    return (
      <View style={[styles.container,this.props.containerStyle]}>
        <ScrollView
          style={this.props.style}
          horizontal={true}  //橫向
          alwaysBounceVertical={false}
          alwaysBounceHorizontal={false}
          showsHorizontalScrollIndicator={false}  //自定義滑動(dòng)進(jìn)度條,所以這里設(shè)置不顯示
          scrollEventThrottle={0.1}  //滑動(dòng)監(jiān)聽調(diào)用頻率
          onScroll={this.animatedEvent}  //滑動(dòng)監(jiān)聽事件,用來映射動(dòng)畫值
          scrollEnabled={ this.state.childWidth - this.props.containerStyle.width>0 ? true : false }
          onContentSizeChange={(width,height)=>{
            if(this.state.childWidth != width){
              this.setState({ childWidth: width })
            }
          }}
        >
          {this.props.children??      
            <View 
              style={{ flexDirection: 'row', height: 200 }}
            >
              <View style={{ width: 300, backgroundColor: 'red' }} />
              <View style={{ width: 300, backgroundColor: 'yellow' }} />
              <View style={{ width: 300, backgroundColor: 'blue' }} />
            </View>
          }
        </ScrollView>
        {this.state.childWidth - this.props.containerStyle.width>0?
          <View style={[{alignSelf:'center'},this.props.indicatorBgStyle]}>
            <Animated.View
              style={[this.props.indicatorStyle,{
                position: 'absolute',
                width: this.state.barWidth,
                top: 0,
                left: this.marLeftAnimated,
              }]}
            />
          </View>:null
        }
      </View>
    );
  };
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
});

Scroll.js

import React, { Component } from 'react';
import {
  StyleSheet, 
  View,
  Dimensions,
  TouchableOpacity,
  Text,
} from 'react-native';
import IndicatorScrollView from '../../component/scroll/IndicatorScrollView';
const { width, height } = Dimensions.get('window');
const columnLimit = 4;  //option列數(shù)量
const rowLimit = 2;  //option行數(shù)量
// 編寫UI組件
export default class Scroll extends Component {
  constructor(props) {
    super(props);
    this.state = {
    };
    this.itemArr = [
      {
        name: '1'
      },
      {
        name: '2'
      },
      {
        name: '3'
      },
      {
        name: '4'
      },
      {
        name: '5'
      },
      {
        name: '6'
      },
      {
        name: '7'
      },
      {
        name: '8'
      },
      {
        name: '9'
      },
      {
        name: '10'
      },
      {
        name: '11'
      },
      {
        name: '12'
      }
    ]
  }
	renderOption(){
		let size = (width-20)/columnLimit; //每個(gè)option的寬度
		let optionTotalArr = [];  //存放所有option樣式的數(shù)組
		//根據(jù)行數(shù),聲明用于存放每一行渲染內(nèi)容的數(shù)組
		for( let i = 0; i < rowLimit; i++ ) optionTotalArr.push([])
		this.itemArr.map((item,index) => {
			let rowIndex = 0;  //行標(biāo)識(shí)
			if(index < columnLimit * rowLimit){
				//沒超出一屏數(shù)量時(shí),根據(jù)列數(shù)更新行標(biāo)識(shí)
				rowIndex = parseInt(index / columnLimit)
			}else{
				//當(dāng)超出一屏數(shù)量時(shí),根據(jù)行數(shù)更新行標(biāo)識(shí)
				rowIndex = index % rowLimit;
			}
			optionTotalArr[rowIndex].push(
        <TouchableOpacity 
          key={index} 
          activeOpacity={0.7}
          style={[styles.list_item,{width:size}]} 
          onPress={()=>alert(item.name)}
        >
          <View style={{width:size-20,backgroundColor:'#FFCC00',alignItems:'center',justifyContent:'center'}}>
           <Text style={{ fontSize:18, color:'#333',marginVertical:20}}>{item.name}</Text>
          </View>
				</TouchableOpacity>
			)
		})
    return(
			<View
				style={{flex:1,justifyContent:'center',paddingHorizontal:10}}
		  >
				{
					optionTotalArr.map((item,index)=>{
						return <View key={index} style={{flexDirection:'row'}}>{item}</View>
					})
				}
			</View>
    )
	}
  render() {
    return (
      <View style={styles.container}>
        <View style={{flex:1}}/>
        <IndicatorScrollView 
          containerStyle={styles.list_style}
          indicatorBgStyle={{marginBottom:10,borderRadius:2,width:40,height:4,backgroundColor:'#BFBFBF'}}
          indicatorStyle={{borderRadius:2,height:4,backgroundColor:'#CC0000'}}
        >
          {this.renderOption()}
        </IndicatorScrollView>
        <View style={{flex:1}}/>
      </View >
    );
  };
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    backgroundColor: '#fff',
  },
  list_style:{
		flex: 1,
    width: width,
    backgroundColor:'#6699FF'
  },
  list_item:{
    marginVertical:20,
		justifyContent:'center',
    alignItems:'center',
	},
});

注:本文為作者原創(chuàng),轉(zhuǎn)載請注明作者及出處。

到此這篇關(guān)于通過React-Native實(shí)現(xiàn)自定義橫向滑動(dòng)進(jìn)度條的 ScrollView組件的文章就介紹到這了,更多相關(guān)React Native橫向滑動(dòng)進(jìn)度條內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React中Context的用法總結(jié)

    React中Context的用法總結(jié)

    Context?提供了一種在組件樹中共享數(shù)據(jù)的方式,而不必通過?props?顯式地逐層傳遞,主要用于共享那些對于組件樹中許多組件來說是"全局"的數(shù)據(jù),下面小編就來和大家簡單講講Context的用法吧
    2025-01-01
  • 關(guān)于react-router-dom路由入門教程

    關(guān)于react-router-dom路由入門教程

    這篇文章主要介紹了關(guān)于react-router-dom路由入門教程,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • React Umi國際化配置方法

    React Umi國際化配置方法

    這篇文章主要介紹了React Umi國際化配置方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-04-04
  • React-Native中一些常用組件的用法詳解(一)

    React-Native中一些常用組件的用法詳解(一)

    這篇文章主要跟大家分享了關(guān)于React-Native中一些常用組件的用法,其中包括View組件、Text組件、Touchable類組件、TextInput組件以及Image組件的使用方法,分別給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),需要的朋友們下面來一起看看吧。
    2017-06-06
  • 使用React?SSR寫Demo一學(xué)就會(huì)

    使用React?SSR寫Demo一學(xué)就會(huì)

    這篇文章主要為大家介紹了使用React?SSR寫Demo實(shí)現(xiàn)教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • 高性能React開發(fā)React Server Components詳解

    高性能React開發(fā)React Server Components詳解

    ReactServerComponents通過服務(wù)器端渲染、自動(dòng)代碼分割等技術(shù),實(shí)現(xiàn)了高性能的React開發(fā),它解決了客戶端數(shù)據(jù)請求鏈?zhǔn)窖舆t、敏感數(shù)據(jù)暴露風(fēng)險(xiǎn)等問題,提供了更好的用戶體驗(yàn)和安全性,本文介紹高性能React開發(fā)React Server Components詳解,感興趣的朋友一起看看吧
    2025-03-03
  • Redux thunk中間件及執(zhí)行原理詳細(xì)分析

    Redux thunk中間件及執(zhí)行原理詳細(xì)分析

    redux的核心概念其實(shí)很簡單:將需要修改的state都存入到store里,發(fā)起一個(gè)action用來描述發(fā)生了什么,用reducers描述action如何改變state tree,這篇文章主要介紹了Redux thunk中間件及執(zhí)行原理分析
    2022-09-09
  • react中braft-editor的基本使用方式

    react中braft-editor的基本使用方式

    這篇文章主要介紹了react中braft-editor的基本使用方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 深入理解React與閉包的關(guān)系

    深入理解React與閉包的關(guān)系

    本文將深入探討React與閉包之間的關(guān)系,我們將首先介紹React和閉包的基本概念,然后詳細(xì)解釋React組件中如何使用閉包來處理狀態(tài)和作用域的問題,希望通過本文的閱讀,你將對React中閉包的概念有更深入的理解,并能夠在開發(fā)React應(yīng)用時(shí)更好地應(yīng)用閉包
    2023-07-07
  • React Fragment 和空標(biāo)簽(<></>)用法及區(qū)別詳解

    React Fragment 和空標(biāo)簽(<></>)用法及區(qū)別詳解

    本文詳細(xì)介紹了React中的Fragment和空標(biāo)簽的使用,包括它們的區(qū)別、使用場景、性能考慮以及最佳實(shí)踐,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2025-01-01

最新評論