【移动应用开发技术】怎么用react native实现圆弧拖动进度条_第1页
【移动应用开发技术】怎么用react native实现圆弧拖动进度条_第2页
【移动应用开发技术】怎么用react native实现圆弧拖动进度条_第3页
【移动应用开发技术】怎么用react native实现圆弧拖动进度条_第4页
【移动应用开发技术】怎么用react native实现圆弧拖动进度条_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

【移动应用开发技术】怎么用reactnative实现圆弧拖动进度条

这篇“怎么用reactnative实现圆弧拖动进度条”文章的知识点大部分人都不太理解,所以在下给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么用reactnative实现圆弧拖动进度条”文章吧。先上效果图因为需求需要实现这个效果图非原生实现,难点1:绘制使用svg难点2:点击事件的处理难点3:封装由于绘制需要是使用svg此处自行百度按照svg以及api教学视图代码块

render()

{

return

(

<View

pointerEvents={'box-only'}

//事件处理

{...this._panResponder.panHandlers}>

//实际圆环

{this._renderCircleSvg()}

//

计算中心距离

<View

style={{

position:

'relative',

top:

-ps.height

/

2

-

ps.r,

left:

ps.width

/

2

-

ps.r,

flex:

1,

}}>

//

暴露给外部渲染圆环中心的接口

{ps.renderCenterView(this.state.temp)}

</View>

</View>

);

_renderCircleSvg()

{

//中心点

const

cx

=

ps.width

/

2;

const

cy

=

ps.height

/

2;

//计算是否有偏差角

对应图就是下面缺了一块的

const

prad

=

ps.angle

/

2

*

(Math.PI

/

180);

//三角计算起点

const

startX

=

-(Math.sin(prad)

*

ps.r)

+

cx;

const

startY

=

cy

+

Math.cos(prad)

*

ps.r;

//终点

const

endX

=

Math.sin(prad)

*

ps.r

+

cx;

const

endY

=

cy

+

Math.cos(prad)

*

ps.r;

//

计算进度点

const

progress

=

parseInt(

this._circlerate()

*

(360

-

ps.angle)

/

100,

10

);

//

根据象限做处理

苦苦苦

高中数学全忘了,参考辅助线

const

t

=

progress

+

ps.angle

/

2;

const

progressX

=

cx

-

Math.sin(t

*

(Math.PI

/

180))

*

ps.r;

const

progressY

=

cy

+

Math.cos(t

*

(Math.PI

/

180))

*

ps.r;

//

SVG的描述

这里百度下就知道什么意思

const

descriptions

=

[

'M',

startX,

startY,

'A',

ps.r,

ps.r,

0,

1,

1,

endX,

endY,

].join('

');

const

progressdescription

=

[

'M',

startX,

startY,

'A',

ps.r,

ps.r,

0,

//根据角度是否是0,1

看下效果就知道了

t

>=

180

+

ps.angle

/

2

?

1

:

0,

1,

progressX,

progressY,

].join('

');

return

(

<Svg

height={ps.height}

width={ps.width}

style={styles.svg}>

<Path

d={descriptions}

fill="none"

stroke={ps.outArcColor}

strokeWidth={ps.strokeWidth}

/>

<Path

d={progressdescription}

fill="none"

stroke={gressvalue}

strokeWidth={ps.strokeWidth}

/>

<Circle

cx={progressX}

cy={progressY}

r={ps.tabR}

stroke={ps.tabStrokeColor}

strokeWidth={ps.tabStrokeWidth}

fill={ps.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

(ps.enTouch)

{

this.lastTemper

=

this.state.temp;

const

x

=

evt.nativeEvent.locationX;

const

y

=

evt.nativeEvent.locationY;

this.parseToDeg(x,

y);

}

},

onPanResponderMove:

(evt,

gestureState)

=>

{

if

(ps.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

(ps.enTouch)

plete(this.state.temp);

},

//

另一个组件已经成为了新的响应者,所以当前手势将被取消。

onPanResponderTerminate:

()

=>

{},

//

返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者

//

默认返回true。目前暂时只支持android。

onShouldBlockNativeResponder:

()

=>

true,

});

}

//画象限看看就知道了

就是和中线点计算角度

parseToDeg(x,

y)

{

const

cx

=

ps.width

/

2;

const

cy

=

ps.height

/

2;

let

deg;

let

temp;

if

(x

>=

cx

&&

y

<=

cy)

{

deg

=

Math.atan((cy

-

y)

/

(x

-

cx))

*

180

/

Math.PI;

temp

=

(270

-

deg

-

ps.angle

/

2)

/

(360

-

ps.angle)

*

(ps.max

-

ps.min)

+

ps.min;

}

else

if

(x

>=

cx

&&

y

>=

cy)

{

deg

=

Math.atan((cy

-

y)

/

(cx

-

x))

*

180

/

Math.PI;

temp

=

(270

+

deg

-

ps.angle

/

2)

/

(360

-

ps.angle)

*

(ps.max

-

ps.min)

+

ps.min;

}

else

if

(x

<=

cx

&&

y

<=

cy)

{

deg

=

Math.atan((x

-

cx)

/

(y

-

cy))

*

180

/

Math.PI;

temp

=

(180

-

ps.angle

/

2

-

deg)

/

(360

-

ps.angle)

*

(ps.max

-

ps.min)

+

ps.min;

}

else

if

(x

<=

cx

&&

y

>=

cy)

{

deg

=

Math.atan((cx

-

x)

/

(y

-

cy))

*

180

/

Math.PI;

if

(deg

<

ps.angle

/

2)

{

deg

=

ps.angle

/

2;

}

temp

=

(deg

-

ps.angle

/

2)

/

(360

-

ps.angle)

*

(ps.max

-

ps.min)

+

ps.min;

}

if

(temp

<=

ps.min)

{

temp

=

ps.min;

}

if

(temp

>=

ps.max)

{

temp

=

ps.max;

}

//因为提供步长,所欲需要做接近步长的数

temp

=

this.getTemps(temp);

this.setState({

temp,

});

ps.valueChange(this.state.temp);

}

getTemps(tmps)

{

const

k

=

parseInt((tmps

-

ps.min)

/

ps.step,

10);

const

k1

=

ps.min

+

ps.step

*

k;

const

k2

=

ps.min

+

ps.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:

ps.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

(ps.enTouch)

{

this.lastTemper

=

this.state.temp;

const

x

=

evt.nativeEvent.locationX;

const

y

=

evt.nativeEvent.locationY;

this.parseToDeg(x,

y);

}

},

onPanResponderMove:

(evt,

gestureState)

=>

{

if

(ps.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

(ps.enTouch)

plete(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

=

ps.width

/

2;

const

cy

=

ps.height

/

2;

let

deg;

let

temp;

if

(x

>=

cx

&&

y

<=

cy)

{

deg

=

Math.atan((cy

-

y)

/

(x

-

cx))

*

180

/

Math.PI;

temp

=

(270

-

deg

-

ps.angle

/

2)

/

(360

-

ps.angle)

*

(ps.max

-

ps.min)

+

ps.min;

}

else

if

(x

>=

cx

&&

y

>=

cy)

{

deg

=

Math.atan((cy

-

y)

/

(cx

-

x))

*

180

/

Math.PI;

temp

=

(270

+

deg

-

ps.angle

/

2)

/

(360

-

ps.angle)

*

(ps.max

-

ps.min)

+

ps.min;

}

else

if

(x

<=

cx

&&

y

<=

cy)

{

deg

=

Math.atan((x

-

cx)

/

(y

-

cy))

*

180

/

Math.PI;

temp

=

(180

-

ps.angle

/

2

-

deg)

/

(360

-

ps.angle)

*

(ps.max

-

ps.min)

+

ps.min;

}

else

if

(x

<=

cx

&&

y

>=

cy)

{

deg

=

Math.atan((cx

-

x)

/

(y

-

cy))

*

180

/

Math.PI;

if

(deg

<

ps.angle

/

2)

{

deg

=

ps.angle

/

2;

}

temp

=

(deg

-

ps.angle

/

2)

/

(360

-

ps.angle)

*

(ps.max

-

ps.min)

+

ps.min;

}

if

(temp

<=

ps.min)

{

temp

=

ps.min;

}

if

(temp

>=

ps.max)

{

temp

=

ps.max;

}

temp

=

this.getTemps(temp);

this.setState({

temp,

});

ps.valueChange(this.state.temp);

}

getTemps(tmps)

{

const

k

=

parseInt((tmps

-

ps.min)

/

ps.step,

10);

const

k1

=

ps.min

+

ps.step

*

k;

const

k2

=

ps.min

+

ps.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:

-ps.height

/

2

-

ps.r,

left:

ps.width

/

2

-

ps.r,

flex:

1,

}}>

{ps.renderCenterView(this.state.temp)}

</View>

</View>

);

}

_circlerate()

{

let

rate

=

parseInt(

(this.state.temp

-

ps.min)

*

100

/

(ps.max

-

ps.min),

10

);

if

(rate

<

0)

{

rate

=

0;

}

else

if

(rate

>

100)

{

rate

=

100;

}

return

rate;

}

_renderCircleSvg()

{

const

cx

=

ps.width

/

2;

const

cy

=

ps.height

/

2;

const

prad

=

ps.angle

/

2

*

(Math.PI

/

180);

const

startX

=

-(Math.sin(prad)

*

ps.r)

+

cx;

const

startY

=

cy

+

Math.cos(prad)

*

ps.r;

//

//

最外层的圆弧配置

const

endX

=

Math.sin(prad)

*

ps.r

+

cx;

const

endY

=

cy

+

Math.cos(prad)

*

ps.r;

//

计算进度点

const

progress

=

parseInt(

this._circlerate()

*

(360

-

ps.angle)

/

100,

10

);

//

根据象限做处理

苦苦苦

高中数学全忘了,参考辅助线

const

t

=

progress

+

ps.angle

/

2;

const

progressX

=

cx

-

Math.sin(t

*

(Math.PI

/

180))

*

ps.r;

const

progressY

=

cy

+

Math.cos(t

*

(Math.PI

/

180))

*

ps.r;

const

descriptions

=

[

'M',

startX,

s

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论