SVG - наиболее распространенный язык разметки для векторной графики, в основном благодаря его обширной поддержке веб-разработки. Взаимодействие с веб-браузерами, а также простота отладки с помощью ваших любимых инструментов разработки сделали его непревзойденным, когда дело доходит до создания красивой графики.
Вполне естественно, что веб-разработчики, обращаясь к React Native, будут искать тот же набор инструментов при попытке реализовать безумные идеи своих дизайнеров, которые наверняка придут в форме SVG.
React Native поставляется со встроенной SVG-подобной библиотекой под названием ART. Что он делает, так это в основном сопоставляет компоненты React с собственными классами в iOS и Android, которые рисуют на экране с помощью компонентов платформы (Core Graphics в iOS и android.graphics в Android). Однако я хотел бы порекомендовать использовать отличный пакет под названием react-native-svg, который доступен как в Expo, так и в react-native-community. Преимущества использования response-native-svg:
- Написание SVG точно так же, как для Интернета (тот же синтаксис)
- Поддержка сенсорных событий для каждого элемента SVG (Компонент)
Итак, без дальнейших подробностей, давайте погрузимся в то, как реализовать красивую круговую диаграмму, и в конечном итоге мы также будем анимировать ее с помощью библиотеки React Native Animated. Вот как будет выглядеть конечный результат:
App.js
import SVG, {G} from 'react-native-svg'; ... import Slice from "./Slice"; const AnimatedSlice = Animated.createAnimatedComponent(Slice); const demoData = [ { number: 60, color: '#0d2f51' }, { number: 20, color: '#28BD8B' }, { number: 20, color: '#F66A6A' } ]; export default class App extends Component<Props> { constructor(props) { super(props); this.state = { animValue: new Animated.Value(0.1), }; } resetPie = ()=>{ this.state.animValue.setValue(0.1); }; animate = ()=>{ Animated.timing( this.state.animValue, { toValue: 2, duration: 500, easing: Easing.inOut(Easing.quad) } ).start(()=>{ setTimeout(this.resetPie, 2000); }); }; render() { let endAngle = Animated.multiply(this.state.animValue, Math.PI); return ( <View style={styles.container}> <Svg width={200} style={styles.pieSVG} height={200} viewBox={`-100 -100 200 200`} > <G> { demoData.map( (item, index) =>{ return ( <AnimatedSlice index={index} endAngle={endAngle} color={item.color} data={demoData} key={'pie_shape_' + index} /> ) }) } </G> </Svg> <View style={{marginTop: 20}}> <Button onPress={this.animate}/> </View> </View> ); } }
В App.js мы берем образцы данных (demoData) и рисуем их на круговой диаграмме. Для этого мы используем несколько компонентов react-native-svg (SVG, G и Path). Круговая диаграмма будет построена из элементов контура (элемент контура для каждого среза круговой диаграммы). Мы оборачиваем компонент ‹Path› в настраиваемый элемент под названием Slice и создаем из него анимированный компонент с помощью createAnimatedComponent.
Вот код:
Slice.js
import React, {Component} from 'react'; import {Path} from 'react-native-svg'; import * as shape from 'd3-shape'; const d3 = {shape}; export default class Slice extends Component { constructor(props) { super(props); this.state = {}; this.arcGenerator = d3.shape.arc() .outerRadius(100) .padAngle(0) .innerRadius(0); } createPieArc = (index, endAngle, data) => { const arcs = d3.shape.pie() .value((item)=>item.number) .startAngle(0) .endAngle(endAngle) (data); let arcData = arcs[index]; return this.arcGenerator(arcData); }; render() { const { endAngle, color, index, data } = this.props; let val = data[index].number; return ( <Path onPress={()=>alert('value is: '+val)} d={this.createPieArc(index, endAngle, data)} fill={color} /> ) } }
Вы можете видеть, что для вычисления среза пирога мы используем библиотеку d3, которая с версии V4 стала использоваться для React Native и других небраузерных сред (например, новый модуль d3-shape).
Анимация пирога будет сделана простым рисованием его от угла 0 до угла 360 красивым анимированным способом. Теперь мы хотели бы как можно больше использовать библиотеку Animated React Native, поскольку это официальный и задокументированный способ создания анимации в RN.
В идеале мы бы просто использовали элемент ‹Path› и снабдили его свойством d, указывающим на Animated.Value. Однако это не сработает, поскольку способ реализации Path.js в react-native-svg делает невозможным анализ значений из Animated.Value в примитив.
Вот почему мы обернули компонент ‹Path› нашим компонентом ‹Slice›, и, создав из него анимированный компонент, теперь мы можем передавать анимированное значение.
Используя эту технику, можно легко оживить любую форму, воплощая в жизнь самые безумные идеи дизайнеров!