React Native 进度条(react-native-svg)

SVG定义

摘自维基百科可缩放矢量图形(英语:Scalable Vector GraphicsSVG)是一种基于可扩展标记语言(XML),用于描述二维矢量图形的图形格式。SVG由W3C制定,是一个开放标准

这些概念性的东西就不多讲了,感兴趣的自行去网络查找,或者参考文章末尾给出的链接。

SVG path 命令

  • M = moveto
  • L = lineto
  • H = horizontal lineto
  • V = vertical lineto
  • C = curveto
  • S = smooth curveto
  • Q = quadratic Bézier curve
  • T = smooth quadratic Bézier curveto
  • A = elliptical Arc
  • Z = closepath

比如:M5 8 L100 0的意思是:
移动到 point(5, 8) → 连线到point(100,0)

我们使用react-native-svgreact-native中实现如下的效果:

进度条效果图

进度条效果图
进度条效果图

直线进度条

<Svg height="24" width="225">
    <G fill="none" stroke="#3d5875">
        <Path strokeLinecap="round" strokeWidth="8" d="M5 8 l215 0" />
    </G>
    <G fill="none" stroke="#00e0ff">
        <Path strokeLinecap="round" strokeWidth="8" d="M5 8 l100 0"/>
    </G>
</Svg>
参数 解释
stroke="#3d5875" 线条的颜色
strokeWidth="8" 线条的宽度
strokeLinecap="round" 线条的两边用圆角
d="M5 8 l215 0" 背景线条充满,总长度225 - 圆角长度5 * 2 = 215
d="M5 8 l100 0" 前景线条的长度
直线进度条效果图

直线进度条 + 动画

// 1,假设进度是0~100
// 2,线条的长度是 215(215 = 225 - 5 * 2)

let AnimatedPath = Animated.createAnimatedComponent(Path);
export default class AwesomeProject extends Component {
    constructor(props)
    {
        super(props);
        this.state = {
            lineFillAnimation: new Animated.Value(0),
        };
        // 这里是动画的映射关系
        this.lineAnimation = this.state.lineFillAnimation.interpolate({
            inputRange: [
               0,
               100
            ],
            outputRange: [
               `M5 8 l0 0`,
               `M5 8 l215 0`,
            ]
         });
    }
    componentDidMount()
    {
        this.startAnimation();
    }
    startAnimation()
    {
        this.state.lineFillAnimation.setValue(0);

        Animated.spring(
            this.state.lineFillAnimation,
            {
                toValue: 50,  // 设置进度值,范围:0~100
                friction: 5,   // 动画摩擦力
                tension: 35 // 动画张力
            }
        ).start();
    }
    render() {
        return (
            <View style={styles.container}>
                <Svg height="16" width="225">
                    <G fill="none" stroke="#3d5875">
                        <Path strokeLinecap="round" strokeWidth="8" d="M5 8 l215 0" />
                    </G>
                    <G fill="none" stroke="#00e0ff">
                        <AnimatedPath strokeLinecap="round" strokeWidth="8" d={this.lineAnimation}/>
                    </G>
                </Svg>
            </View>
        );
    }
}
直线进度条+动画效果
直线进度条+动画效果

圆形进度条

this.dasharray = [Math.PI * 2 * 42];

<Svg
    height="100"
    width="100">
    <Circle
        cx="50"
        cy="50"
        r="42"
        stroke="#3d5875"
        strokeWidth="8"
        fill="transparent"
    />
    <Circle
        cx="50"
        cy="50"
        r="42"
        origin="50,50"
        rotate="-90"
        stroke="#00e0ff"
        strokeWidth="8"
        strokeLinecap="round"
        fill="transparent"
        strokeDasharray={this.dasharray} strokeDashoffset={50}
    />
</Svg>
参数 解释
<Svg height="100" width="100" 整个圆形画布的长、宽为100x100
<Circle cx="50" cy="50"
strokeWidth="8"
r="42"
stroke="#3d5875"
fill="transparent" />
画底色圆形
圆形的中心点是point(50,50)
线条宽是8
半径是42 = (100 - 8 * 2) / 2
线条颜色是#3d5875
圆形的填充色是透明
rotate="-90" 逆时针旋转90度
strokeLinecap="round" 线条的结点是圆形的
strokeDasharray 固定的计算形式:圆周长 = [Math.PI * 2 * 半径]
strokeDashoffset={50} 前景色的周长度,就是图中黑色的弧形的长度(范围:0~圆周长)
圆形进度条

圆形进度条 + 动画

let AnimatedCircle = Animated.createAnimatedComponent(Circle)

export default class AwesomeProject extends Component {
    constructor(props)
    {
        super(props);
        this.state = {
            circleFillAnimation: new Animated.Value(0)
        };
        this.dasharray = [Math.PI * 2 * 42];
        // 这里是动画的映射关系
        this.circleAnimation = this.state.circleFillAnimation.interpolate({
            inputRange: [
               0,
               100,
            ],
            outputRange: [
                this.dasharray[0],
                0
            ]
         });
    }
    componentDidMount()
    {
        this.startAnimation();
    }
    startAnimation()
    {
        this.state.circleFillAnimation.setValue(0);
        Animated.spring(
            this.state.circleFillAnimation,
            {
                toValue: 80,  // 设置进度值,范围:0~100
                friction: 5,     // 动画摩擦力
                tension: 35   // 动画张力
            }
        ).start();
    }
    render() {
        return (
            <View style={styles.container}>
                <Svg
                    height="100"
                    width="100">
                    <Circle
                        cx="50"
                        cy="50"
                        r="42"
                        stroke="#3d5875"
                        strokeWidth="8"
                        fill="transparent"
                    />
                    <AnimatedCircle
                        cx="50"
                        cy="50"
                        r="42"
                        origin="50,50"
                        rotate="-90"
                        stroke="#00e0ff"
                        strokeWidth="8"
                        strokeLinecap="round"
                        fill="transparent"
                        strokeDasharray={this.dasharray} strokeDashoffset={this.circleAnimation}
                    />
                </Svg>
            </View>
        );
    }
}
圆形进度条+动画
圆形进度条+动画

项目代码地址

react-native-svg-example

参考资料

svg教程
svg元素
react-native-svg
react-art
SVG Circle Progress
Radial Progress Meters (CSS/SVG)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容