国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

react-native 圓弧拖動進度條實現的示例代碼

2019-11-19 14:01:48
字體:
來源:轉載
供稿:網友

本文介紹了react-native 圓弧拖動進度條實現的示例代碼,分享給大家,具體如下:

先上效果圖

因為需求需要實現這個效果圖 非原生實現,

  1. 難點1:繪制 使用svg
  2. 難點2:點擊事件的處理
  3. 難點3:封裝

由于繪制需要是使用svg

此處自行百度 按照svg以及api 教學

視圖代碼塊

 render() { return (  <View pointerEvents={'box-only'}  //事件處理  {...this._panResponder.panHandlers}>  //實際圓環  {this._renderCircleSvg()}  // 計算中心距離  <View   style={{   position: 'relative',   top: -this.props.height / 2 - this.props.r,   left: this.props.width / 2 - this.props.r,   flex: 1,   }}>   // 暴露給外部渲染圓環中心的接口   {this.props.renderCenterView(this.state.temp)}  </View>  </View> ); _renderCircleSvg() { //中心點 const cx = this.props.width / 2; const cy = this.props.height / 2; //計算是否有偏差角 對應圖就是下面缺了一塊的 const prad = this.props.angle / 2 * (Math.PI / 180); //三角計算起點 const startX = -(Math.sin(prad) * this.props.r) + cx; const startY = cy + Math.cos(prad) * this.props.r;  //終點 const endX = Math.sin(prad) * this.props.r + cx; const endY = cy + Math.cos(prad) * this.props.r; // 計算進度點 const progress = parseInt(  this._circlerate() * (360 - this.props.angle) / 100,  10 ); // 根據象限做處理 苦苦苦 高中數學全忘了,參考輔助線 const t = progress + this.props.angle / 2; const progressX = cx - Math.sin(t * (Math.PI / 180)) * this.props.r; const progressY = cy + Math.cos(t * (Math.PI / 180)) * this.props.r;// SVG的描述 這里百度下就知道什么意思 const descriptions = [  'M',  startX,  startY,  'A',  this.props.r,  this.props.r,  0,  1,  1,  endX,  endY, ].join(' '); const progressdescription = [  'M',  startX,  startY,  'A',  this.props.r,  this.props.r,  0,  //根據角度是否是0,1 看下效果就知道了  t >= 180 + this.props.angle / 2 ? 1 : 0,  1,  progressX,  progressY, ].join(' '); return (  <Svg  height={this.props.height}  width={this.props.width}  style={styles.svg}>  <Path   d={descriptions}   fill="none"   stroke={this.props.outArcColor}   strokeWidth={this.props.strokeWidth} />  <Path   d={progressdescription}   fill="none"   stroke={this.props.progressvalue}   strokeWidth={this.props.strokeWidth} />  <Circle   cx={progressX}   cy={progressY}   r={this.props.tabR}   stroke={this.props.tabStrokeColor}   strokeWidth={this.props.tabStrokeWidth}   fill={this.props.tabColor} />  </Svg> ); }}

事件處理代碼塊

// 參考react native 官網對手勢的講解 iniPanResponder() { this.parseToDeg = this.parseToDeg.bind(this); this._panResponder = PanResponder.create({  // 要求成為響應者:  onStartShouldSetPanResponder: () => true,  onStartShouldSetPanResponderCapture: () => true,  onMoveShouldSetPanResponder: () => true,  onMoveShouldSetPanResponderCapture: () => true,  onPanResponderGrant: evt => {  // 開始手勢操作。給用戶一些視覺反饋,讓他們知道發生了什么事情!  if (this.props.enTouch) {   this.lastTemper = this.state.temp;   const x = evt.nativeEvent.locationX;   const y = evt.nativeEvent.locationY;   this.parseToDeg(x, y);  }  },  onPanResponderMove: (evt, gestureState) => {  if (this.props.enTouch) {   let x = evt.nativeEvent.locationX;   let y = evt.nativeEvent.locationY;   if (Platform.OS === 'android') {   x = evt.nativeEvent.locationX + gestureState.dx;   y = evt.nativeEvent.locationY + gestureState.dy;   }   this.parseToDeg(x, y);  }  },  onPanResponderTerminationRequest: () => true,  onPanResponderRelease: () => {  if (this.props.enTouch) this.props.complete(this.state.temp);  },  // 另一個組件已經成為了新的響應者,所以當前手勢將被取消。  onPanResponderTerminate: () => {},  // 返回一個布爾值,決定當前組件是否應該阻止原生組件成為JS響應者  // 默認返回true。目前暫時只支持android。  onShouldBlockNativeResponder: () => true, }); }//畫象限看看就知道了 就是和中線點計算角度parseToDeg(x, y) { const cx = this.props.width / 2; const cy = this.props.height / 2; let deg; let temp; if (x >= cx && y <= cy) {  deg = Math.atan((cy - y) / (x - cx)) * 180 / Math.PI;  temp =  (270 - deg - this.props.angle / 2) /   (360 - this.props.angle) *   (this.props.max - this.props.min) +  this.props.min; } else if (x >= cx && y >= cy) {  deg = Math.atan((cy - y) / (cx - x)) * 180 / Math.PI;  temp =  (270 + deg - this.props.angle / 2) /   (360 - this.props.angle) *   (this.props.max - this.props.min) +  this.props.min; } else if (x <= cx && y <= cy) {  deg = Math.atan((x - cx) / (y - cy)) * 180 / Math.PI;  temp =  (180 - this.props.angle / 2 - deg) /   (360 - this.props.angle) *   (this.props.max - this.props.min) +  this.props.min; } else if (x <= cx && y >= cy) {  deg = Math.atan((cx - x) / (y - cy)) * 180 / Math.PI;  if (deg < this.props.angle / 2) {  deg = this.props.angle / 2;  }  temp =  (deg - this.props.angle / 2) /   (360 - this.props.angle) *   (this.props.max - this.props.min) +  this.props.min; } if (temp <= this.props.min) {  temp = this.props.min; } if (temp >= this.props.max) {  temp = this.props.max; } //因為提供步長,所欲需要做接近步長的數 temp = this.getTemps(temp); this.setState({  temp, }); this.props.valueChange(this.state.temp); } getTemps(tmps) { const k = parseInt((tmps - this.props.min) / this.props.step, 10); const k1 = this.props.min + this.props.step * k; const k2 = this.props.min + this.props.step * (k + 1); if (Math.abs(k1 - tmps) > Math.abs(k2 - tmps)) return k2; return k1; }

完整代碼塊

import React, { Component } from 'react';import { View, StyleSheet, PanResponder, Platform, Text } from 'react-native';import Svg, { Circle, Path } from 'react-native-svg';export default class CircleView extends Component { static propTypes = { height: React.PropTypes.number, width: React.PropTypes.number, r: React.PropTypes.number, angle: React.PropTypes.number, outArcColor: React.PropTypes.object, progressvalue: React.PropTypes.object, tabColor: React.PropTypes.object, tabStrokeColor: React.PropTypes.object, strokeWidth: React.PropTypes.number, value: React.PropTypes.number, min: React.PropTypes.number, max: React.PropTypes.number, tabR: React.PropTypes.number, step: React.PropTypes.number, tabStrokeWidth: React.PropTypes.number, valueChange: React.PropTypes.func, renderCenterView: React.PropTypes.func, complete: React.PropTypes.func, enTouch: React.PropTypes.boolean, }; static defaultProps = { width: 300, height: 300, r: 100, angle: 60, outArcColor: 'white', strokeWidth: 10, value: 20, min: 10, max: 70, progressvalue: '#ED8D1B', tabR: 15, tabColor: '#EFE526', tabStrokeWidth: 5, tabStrokeColor: '#86BA38', valueChange: () => {}, complete: () => {}, renderCenterView: () => {}, step: 1, enTouch: true, }; constructor(props) { super(props); this.state = {  temp: this.props.value, }; this.iniPanResponder(); } iniPanResponder() { this.parseToDeg = this.parseToDeg.bind(this); this._panResponder = PanResponder.create({  // 要求成為響應者:  onStartShouldSetPanResponder: () => true,  onStartShouldSetPanResponderCapture: () => true,  onMoveShouldSetPanResponder: () => true,  onMoveShouldSetPanResponderCapture: () => true,  onPanResponderGrant: evt => {  // 開始手勢操作。給用戶一些視覺反饋,讓他們知道發生了什么事情!  if (this.props.enTouch) {   this.lastTemper = this.state.temp;   const x = evt.nativeEvent.locationX;   const y = evt.nativeEvent.locationY;   this.parseToDeg(x, y);  }  },  onPanResponderMove: (evt, gestureState) => {  if (this.props.enTouch) {   let x = evt.nativeEvent.locationX;   let y = evt.nativeEvent.locationY;   if (Platform.OS === 'android') {   x = evt.nativeEvent.locationX + gestureState.dx;   y = evt.nativeEvent.locationY + gestureState.dy;   }   this.parseToDeg(x, y);  }  },  onPanResponderTerminationRequest: () => true,  onPanResponderRelease: () => {  if (this.props.enTouch) this.props.complete(this.state.temp);  },  // 另一個組件已經成為了新的響應者,所以當前手勢將被取消。  onPanResponderTerminate: () => {},  // 返回一個布爾值,決定當前組件是否應該阻止原生組件成為JS響應者  // 默認返回true。目前暫時只支持android。  onShouldBlockNativeResponder: () => true, }); } componentWillReceiveProps(nextProps) { if (nextProps.value != this.state.temp) {  this.state = {  temp: nextProps.value,  }; } } parseToDeg(x, y) { const cx = this.props.width / 2; const cy = this.props.height / 2; let deg; let temp; if (x >= cx && y <= cy) {  deg = Math.atan((cy - y) / (x - cx)) * 180 / Math.PI;  temp =  (270 - deg - this.props.angle / 2) /   (360 - this.props.angle) *   (this.props.max - this.props.min) +  this.props.min; } else if (x >= cx && y >= cy) {  deg = Math.atan((cy - y) / (cx - x)) * 180 / Math.PI;  temp =  (270 + deg - this.props.angle / 2) /   (360 - this.props.angle) *   (this.props.max - this.props.min) +  this.props.min; } else if (x <= cx && y <= cy) {  deg = Math.atan((x - cx) / (y - cy)) * 180 / Math.PI;  temp =  (180 - this.props.angle / 2 - deg) /   (360 - this.props.angle) *   (this.props.max - this.props.min) +  this.props.min; } else if (x <= cx && y >= cy) {  deg = Math.atan((cx - x) / (y - cy)) * 180 / Math.PI;  if (deg < this.props.angle / 2) {  deg = this.props.angle / 2;  }  temp =  (deg - this.props.angle / 2) /   (360 - this.props.angle) *   (this.props.max - this.props.min) +  this.props.min; } if (temp <= this.props.min) {  temp = this.props.min; } if (temp >= this.props.max) {  temp = this.props.max; } temp = this.getTemps(temp); this.setState({  temp, }); this.props.valueChange(this.state.temp); } getTemps(tmps) { const k = parseInt((tmps - this.props.min) / this.props.step, 10); const k1 = this.props.min + this.props.step * k; const k2 = this.props.min + this.props.step * (k + 1); if (Math.abs(k1 - tmps) > Math.abs(k2 - tmps)) return k2; return k1; } render() { return (  <View pointerEvents={'box-only'} {...this._panResponder.panHandlers}>  {this._renderCircleSvg()}  <View   style={{   position: 'relative',   top: -this.props.height / 2 - this.props.r,   left: this.props.width / 2 - this.props.r,   flex: 1,   }}>   {this.props.renderCenterView(this.state.temp)}  </View>  </View> ); } _circlerate() { let rate = parseInt(  (this.state.temp - this.props.min) *  100 /  (this.props.max - this.props.min),  10 ); if (rate < 0) {  rate = 0; } else if (rate > 100) {  rate = 100; } return rate; } _renderCircleSvg() { const cx = this.props.width / 2; const cy = this.props.height / 2; const prad = this.props.angle / 2 * (Math.PI / 180); const startX = -(Math.sin(prad) * this.props.r) + cx; const startY = cy + Math.cos(prad) * this.props.r; // // 最外層的圓弧配置 const endX = Math.sin(prad) * this.props.r + cx; const endY = cy + Math.cos(prad) * this.props.r; // 計算進度點 const progress = parseInt(  this._circlerate() * (360 - this.props.angle) / 100,  10 ); // 根據象限做處理 苦苦苦 高中數學全忘了,參考輔助線 const t = progress + this.props.angle / 2; const progressX = cx - Math.sin(t * (Math.PI / 180)) * this.props.r; const progressY = cy + Math.cos(t * (Math.PI / 180)) * this.props.r; const descriptions = [  'M',  startX,  startY,  'A',  this.props.r,  this.props.r,  0,  1,  1,  endX,  endY, ].join(' '); const progressdescription = [  'M',  startX,  startY,  'A',  this.props.r,  this.props.r,  0,  t >= 180 + this.props.angle / 2 ? 1 : 0,  1,  progressX,  progressY, ].join(' '); return (  <Svg  height={this.props.height}  width={this.props.width}  style={styles.svg}>  <Path   d={descriptions}   fill="none"   stroke={this.props.outArcColor}   strokeWidth={this.props.strokeWidth} />  <Path   d={progressdescription}   fill="none"   stroke={this.props.progressvalue}   strokeWidth={this.props.strokeWidth} />  <Circle   cx={progressX}   cy={progressY}   r={this.props.tabR}   stroke={this.props.tabStrokeColor}   strokeWidth={this.props.tabStrokeWidth}   fill={this.props.tabColor} />  </Svg> ); }}const styles = StyleSheet.create({ svg: {},});

外部調用

<View style={styles.container}>  <CircleProgress   width={width}   height={height}   r={r}   angle={60}   min={5}   max={35}   step={0.5}   value={22}   complete={temp => {   }}   valueChange={temp => {}}   renderCenterView={temp => (   <View style={{ flex: 1 }}>   </View>   )}   enTouch={true} />  </View>

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 新化县| 龙游县| 德庆县| 临夏市| 四平市| 社会| 西吉县| 永泰县| 隆子县| 鄂尔多斯市| 正镶白旗| 祁阳县| 威海市| 华蓥市| 郸城县| 清流县| 兴城市| 河北区| 云龙县| 固镇县| 墨脱县| 九台市| 灌云县| 和顺县| 井研县| 肥西县| 亳州市| 红河县| 陇川县| 虞城县| 浏阳市| 张家口市| 鹰潭市| 蒙自县| 连州市| 聂荣县| 乳源| 抚顺县| 科尔| 彩票| 阳高县|