问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

react native在安卓和ios中进度条怎么适配

发布网友 发布时间:2022-04-22 21:09

我来回答

2个回答

懂视网 时间:2022-04-23 01:31

这次给大家带来react-native做出圆弧拖动进度条,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>

相信看了本文案例你已经掌握了方法,更多精彩请关注Gxl网其它相关文章!

推荐阅读:

vuex页面刷新后无法保存数据怎么处理

vue全局组件总结

热心网友 时间:2022-04-22 22:39

React Native 结合了 Web 应用和 Native 应用的优势,可以使用 JavaScript 来开发
iOS 和 Android 原生应用。在 JavaScript 中用 React 抽象操作系统原生的 UI 组件,代替 DOM 元素来渲染等。
React Native 使你能够使用基于 JavaScript 和 React
一致的开发体验在本地平台上构建世界一流的应用程序体验。React Native
把重点放在所有开发人员关心的平台的开发效率上——开发者只需学习一种语言就能轻易为任何平台高效地编写代码。*
在多个应用程序产品中使用了 React Native,并将继续为 React Native 投资。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
柿的同音字 趣填“shi”的同音字。 各( )各样 不甘( 一个人穷游韩国二万元人民币够吗 solidworks 装配体如何备份,使原装配体发生更改时,备份文件不会重建... ...塞翁失马焉知非福的故事---.八仙过海的故事- ...转身就忘前面唱妖兽……(我忘了,,)是周杰伦的什么歌?求歌名_百度知... 求《哈里波特 与火焰杯 》电影里面的 一段 配乐 初中学校的篮球比赛要注意哪些?自己回答别复制! 什么是 开放申赎 开放申赎什么意思 德国姨妈小福罐止痛效果好还是白兔的止痛片效果好? 菲士康上新的这款硅水凝胶的小蓝片,大家有用过吗? 都邦财产保险股份有限公司投诉电话 女用小蓝片是什么 痘痘全长在右脸是怎么回事 只是右脸长痘是为什么 为什么痘痘只长在右边的脸上? 为什么我的痘痘都是长到右边脸的。左边没有的,是什么原因呢 ? 通过安检X光机怎样辨别是否为可疑物品? 为什么我只有右脸长痘痘呢 被核定为高风险客户,前台柜员在开户环节应做哪些步骤 农行高风险客户好久解除 反洗钱法至少每多久进行一次审核 农村房屋建筑合同范本 react native 进度条怎么实现 网络连接服务器超时,是怎么回事? 服务器超时是怎么回事 连接网络时请求服务器超时怎么办 电脑服务器老超时怎么办? 陇东学院是省部级共建院校吗 我使用的云高通怎么录像回放怎么显示没有录像文件 金立手机怎么安装驱动程序 为什么金立手机的驱动程序和USB插口都安装好了还是连接不上电脑啊? 金立usb网络驱动程序 现在是需要考会计证,不是从会计从业资格证开始而是从初级?初级的难不难考?如果必须需要会计证怎么办? 金立M5 plus怎么在电脑上安装手机USB驱动程序 金立手机摄像头怎样驱动 金立V6200手机驱动 怎么添加门禁卡到手机上 react native怎么实现加载进度 十五道三国演义选择题 求三国演义测试题20道,要有答案 关于三国演义的试题 跟我爱我家签合同,突然变成了爱家营,爱家营是什么玩意儿? 关于三国演义的练习题 三国演义经典试题及答案30道 三国演义填空题100道 请给我出10道关于《三国演义》的题目。要答案 《三国演义》选择题,希望能有较直接的解析。 三国演义 选择题