ReactNative實(shí)現(xiàn)弧形拖動(dòng)條的代碼案例
我們直接看效果
先看下面的使用代碼
<CircularSlider5 step={2} min={0} max={100} radius={100} value={30} onComplete={(changeValue: number) => this.handleEmailSbp(changeValue)} onChange={(changeValue: number) => this.handleEmailDpd(changeValue)} contentContainerStyle={styles.contentContainerStyle} strokeWidth={10} buttonBorderColor="#3FE3EB" buttonFillColor="#fff" buttonStrokeWidth={10} openingRadian={Math.PI / 4} buttonRadius={10} triangleLinerGradient={[ {stop: '0%', color: '#FF7B4C'}, {stop: '50%', color: '#FFFFFF'}, {stop: '100%', color: '#317AF7'}, ]} linearGradient={[ {stop: '0%', color: '#3FE3EB'}, {stop: '100%', color: '#7E84ED'}, ]}></CircularSlider5> { radius: 100, // 半徑 strokeWidth: 20, // 線寬 openingRadian: Math.PI / 4, // 開口弧度,為了便于計(jì)算值為實(shí)際開口弧度的一半 backgroundTrackColor: '#e8e8e8', // 底部軌道顏色 linearGradient: [ {stop: '0%', color: '#1890ff'}, {stop: '100%', color: '#f5222d'}, ], // 漸變色 min: 0, // 最小值 max: 100, // 最大值 buttonRadius: 12, // 按鈕半徑 buttonBorderColor: '#fff', // 按鈕邊框顏色 buttonStrokeWidth: 1, // 按鈕線寬 };
本組件使用到了
1.react-native-svg
2.PanResponder
具體代碼如下
import React, {PureComponent} from 'react'; import Svg, { Path, G, Defs, LinearGradient, Stop, Circle, } from 'react-native-svg'; import {StyleSheet, View, PanResponder} from 'react-native'; export default class CircularSlider extends PureComponent { static defaultProps = { radius: 100, // 半徑 strokeWidth: 20, // 線寬 openingRadian: Math.PI / 4, // 開口弧度,為了便于計(jì)算值為實(shí)際開口弧度的一半 backgroundTrackColor: '#e8e8e8', // 底部軌道顏色 linearGradient: [ {stop: '0%', color: '#1890ff'}, {stop: '100%', color: '#f5222d'}, ], // 漸變色 min: 0, // 最小值 max: 100, // 最大值 buttonRadius: 12, // 按鈕半徑 buttonBorderColor: '#fff', // 按鈕邊框顏色 buttonStrokeWidth: 1, // 按鈕線寬 }; constructor(props) { super(props); this._panResponder = PanResponder.create({ onStartShouldSetPanResponder: () => true, onMoveShouldSetPanResponder: () => false, onPanResponderGrant: this._handlePanResponderGrant, onPanResponderMove: this._handlePanResponderMove, onPanResponderRelease: this._handlePanResponderEnd, onPanResponderTerminationRequest: () => false, onPanResponderTerminate: this._handlePanResponderEnd, }); this.state = { value: props.value || props.min, }; this._containerRef = React.createRef(); } _handlePanResponderGrant = () => { /* * 記錄開始滑動(dòng)開始時(shí)的滑塊值、弧度和坐標(biāo),用戶后續(xù)值的計(jì)算 */ const {value} = this.state; this._moveStartValue = value; // 獲取開始移動(dòng)的弧度 this._moveStartRadian = this.getRadianByValue(value); // 根據(jù)弧度獲取開始的極坐標(biāo) this._startCartesian = this.polarToCartesian(this._moveStartRadian); // console.log(`開始滑動(dòng)弧度${this._startCartesian}`); // console.log(`開始滑動(dòng)${this._startCartesian.x}:${this._startCartesian.y}`); }; _handlePanResponderMove = (e, gestureState) => { const {min, max, step, openingRadian} = this.props; let {x, y} = this._startCartesian; x += gestureState.dx; y += gestureState.dy; // console.log(`滑動(dòng)過程中${x}:${y}`); const radian = this.cartesianToPolar(x, y); // 當(dāng)前弧度 console.log(`滑動(dòng)過程中的弧度${radian}`); const ratio = (this._moveStartRadian - radian) / ((Math.PI - openingRadian) * 2); // 弧度變化所占比例 const diff = max - min; // 最大值和最小值的差 let value; if (step) { value = this._moveStartValue + Math.round((ratio * diff) / step) * step; } else { value = this._moveStartValue + ratio * diff; } // 處理極值 value = Math.max(min, Math.min(max, value)); this.setState({ value, }); // this.setState(({value: curValue}) => { // value = Math.abs(value - curValue) > diff / 4 ? curValue : value; // 避免直接從最小值變?yōu)樽畲笾? // return {value: Math.round(value)}; // }); this._fireChangeEvent('onChange'); }; _handlePanResponderEnd = (e, gestureState) => { if (this.props.disabled) { return; } this._fireChangeEvent('onComplete'); }; _fireChangeEvent = event => { if (this.props[event]) { this.props[event](this.state.value); } }; /** * 極坐標(biāo)轉(zhuǎn)笛卡爾坐標(biāo) * @param {number} radian - 弧度表示的極角 */ polarToCartesian(radian) { const {radius} = this.props; const distance = radius + this._getExtraSize() / 2; // 圓心距離坐標(biāo)軸的距離 const x = distance + radius * Math.sin(radian); const y = distance + radius * Math.cos(radian); return {x, y}; } /** * 笛卡爾坐標(biāo)轉(zhuǎn)極坐標(biāo) * @param {*} x * @param {*} y */ cartesianToPolar(x, y) { const {radius} = this.props; const distance = radius + this._getExtraSize() / 2; // 圓心距離坐標(biāo)軸的距離 if (x === distance) { return y > distance ? 0 : Math.PI / 2; } const a = Math.atan((y - distance) / (x - distance)); // 計(jì)算點(diǎn)與圓心連線和 x 軸的夾角 return (x < distance ? (Math.PI * 3) / 2 : Math.PI / 2) - a; } /** * 獲取當(dāng)前弧度 */ getCurrentRadian() { return this.getRadianByValue(this.state.value); } /** * 根據(jù)滑塊的值獲取弧度 * @param {*} value */ getRadianByValue(value) { const {openingRadian, min, max} = this.props; return ( ((Math.PI - openingRadian) * 2 * (max - value)) / (max - min) + openingRadian ); } /** * 獲取除半徑外額外的大小,返回線寬和按鈕直徑中較大的 */ _getExtraSize() { const {strokeWidth, buttonRadius, buttonStrokeWidth} = this.props; return Math.max(strokeWidth, (buttonRadius + buttonStrokeWidth) * 2); } _onLayout = () => { const ref = this._containerRef.current; if (ref) { ref.measure((x, y, width, height, pageX, pageY) => { this.vertexX = pageX; this.vertexY = pageY; }); } }; render() { const { radius, strokeWidth, backgroundTrackColor, openingRadian, linearGradient, buttonRadius, buttonBorderColor, buttonFillColor, buttonStrokeWidth, style, contentContainerStyle, children, } = this.props; const svgSize = radius * 2 + this._getExtraSize(); const startRadian = 2 * Math.PI - openingRadian; // 起點(diǎn)弧度 const startPoint = this.polarToCartesian(startRadian); const endPoint = this.polarToCartesian(openingRadian); const currentRadian = this.getCurrentRadian(); // 當(dāng)前弧度 const curPoint = this.polarToCartesian(currentRadian); const contentStyle = [styles.content, contentContainerStyle]; return ( <View onLayout={this._onLayout} ref={this._containerRef} style={[styles.container, style]}> <Svg width={svgSize} height={svgSize}> <Defs> <LinearGradient x1="0%" y1="100%" x2="100%" y2="0%" id="gradient"> {linearGradient.map((item, index) => ( <Stop key={index} offset={item.stop} stopColor={item.color} /> ))} </LinearGradient> </Defs> <G rotation={0} origin={`${svgSize / 2}, ${svgSize / 2}`}> <Path strokeWidth={strokeWidth} stroke={backgroundTrackColor} fill="none" strokeLinecap="round" d={`M${startPoint.x},${startPoint.y} A ${radius},${radius},0,${ startRadian - openingRadian >= Math.PI ? '1' : '0' },1,${endPoint.x},${endPoint.y}`} /> <Path strokeWidth={strokeWidth} stroke="url(#gradient)" fill="none" strokeLinecap="round" d={`M${startPoint.x},${startPoint.y} A ${radius},${radius},0,${ startRadian - currentRadian >= Math.PI ? '1' : '0' },1,${curPoint.x},${curPoint.y}`} /> <Circle cx={curPoint.x} cy={curPoint.y} r={buttonRadius} fill={buttonFillColor || buttonBorderColor} stroke={buttonBorderColor} strokeWidth={buttonStrokeWidth} {...this._panResponder.panHandlers} /> </G> </Svg> <View style={contentStyle} pointerEvents="box-none"> {children} </View> </View> ); } } const styles = StyleSheet.create({ container: { justifyContent: 'center', alignItems: 'center', }, content: { position: 'absolute', left: 0, top: 0, bottom: 0, right: 0, }, });
到此這篇關(guān)于ReactNative實(shí)現(xiàn)弧形拖動(dòng)條的文章就介紹到這了,更多相關(guān)ReactNative弧形拖動(dòng)條內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react-intl實(shí)現(xiàn)React國(guó)際化多語言的方法
這篇文章主要介紹了react-intl實(shí)現(xiàn)React國(guó)際化多語言的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09react如何使用mobx6動(dòng)態(tài)加載數(shù)據(jù)
MobX是一個(gè)強(qiáng)大而簡(jiǎn)單的狀態(tài)管理工具,它可以幫助我們更好地組織和管理React應(yīng)用程序中的數(shù)據(jù)流,本文給大家介紹react如何使用mobx6動(dòng)態(tài)加載數(shù)據(jù),感興趣的朋友跟隨小編一起看看吧2024-02-02React、Vue中key的作用詳解 (key的內(nèi)部原理解析)
key是虛擬DOM對(duì)象的標(biāo)識(shí),當(dāng)狀態(tài)中的數(shù)據(jù)發(fā)生變化時(shí),Vue會(huì)根據(jù)[新數(shù)據(jù)]生成[新的虛擬DOM],本文給大家介紹React、Vue中key的作用詳解 (key的內(nèi)部原理解析),感興趣的朋友一起看看吧2023-10-10react事件對(duì)象無法獲取offsetLeft,offsetTop,X,Y等元素問題及解決
這篇文章主要介紹了react事件對(duì)象無法獲取offsetLeft,offsetTop,X,Y等元素問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。2022-08-08antd4里table滾動(dòng)的實(shí)現(xiàn)
本文主要介紹了antd4里table滾動(dòng)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03