react-native 의 ART 그래 픽 방법 상세 설명

배경
모 바 일 애플 리 케 이 션 개발 과정 에서 기본 적 인 2 차원 도형 이나 애니메이션 을 그 리 는 것 이 필수 적 이다.그러나 안 드 로 이 드 와 iOS 는 각자 의 API 방안 을 가지 고 있 음 을 감안 하여 더욱 보편적으로 받 아들 이 는 기술 방안 을 채택 하여 코드 의 더 블 플랫폼 호 환 에 유리 하 다.
art 는 다 중 브 라 우 저 호 환 을 위 한 Node style CommonJS 모듈 입 니 다.이 를 바탕 으로 페 이 스 북 은 React-art,패키지 아 트 를 개발 하여 react.js 에 의 해 사용 할 수 있 도록 하 였 으 며,즉 전단 의 svg 라 이브 러 리 를 실현 하 였 다.그러나 react.js 의 JSX 문법 을 고려 하여 등 svg 라벨 을 dom 에 직접 삽입 하 는 것 을 지원 합 니 다(물론 이때 사용 하 는 것 은 react-art 라 이브 러 리 가 아 닙 니 다).또한 HTML canvas 의 존재 도 있 기 때문에 전단 에 react-art 는 대체 할 수 없 는 것 이 아 닙 니 다.
그러나 모 바 일 에서 크로스 플랫폼 의 수 요 를 고려 한 데다 가 웹 엔 드 의 기술 축적 으로 인해 react-art 는 기 존의 도형 그리 기 솔 루 션 이 되 었 다.react-native 는 각각 0.10.0 과 0.18.0 에 ios 와 android 플랫폼 에서 react-art 에 대한 지원 을 추가 했다.
예제 코드
React.js 와 React-Native 의 차 이 는 다음 과 같은 ART 획득 에 있 습 니 다.그리고 이 예 는 웹 엔 드 와 모 바 일 엔 드 에 동시에 적용 할 수 있 습 니 다.react-art 자체 의 공식 예:Vector-Widget
Vector-widget 은 회전 과 마우스 클릭 이벤트 의 회전 가속 응답 을 추가 로 실현 합 니 다.웹 사 이 드 에 서 는 클릭 가속 을 볼 수 있 지만 모 바 일 에서 유효 하지 않 습 니 다.React Native 가 Group 의 onMouse Down 과 onMouse Up 속성 을 처리 하지 않 았 기 때 문 입 니 다.본 고 는 정적 svg 의 실현 에 중심 을 두 고 애니메이션 부분의 효 과 를 잠시 무시 하면 된다.
ART
react native 에서 ART 는 매우 중요 한 라 이브 러 리 로 매우 멋 진 그림 과 애니메이션 을 가능 하 게 합 니 다.주의해 야 할 것 은 React Native 가 ART 를 도입 하 는 과정 에서 Android 는 기본적으로 ART 라 이브 러 리 를 포함 하고 IOS 는 의존 라 이브 러 리 를 따로 추가 해 야 한 다 는 점 이다.
ios 의존 라 이브 러 리 추가
1.xcode 에서 React-native 의 iOS 항목 을 열 고'Libraries'디 렉 터 리 를 선택 하 십시오.>오른쪽 단 추 를 누 르 면'Add Files to 프로젝트 이름'―>'nodemodules/react-native/Library/ART/ART.xcodeproj'추가;
这里写图片描述
2.항목 루트 디 렉 터 리 를 선택 하 십시오.>'Build Phases'를 클릭 하 십시오.>'Link Binary With Libraries'를 클릭 하 십시오.>왼쪽 아래'+'를 클릭 하 십시오.>'libART.a'를 선택 하 십시오.
这里写图片描述
기본 구성 요소
ART 가 노출 된 구성 요 소 는 모두 7 개 로 본 고 는 자주 사용 하 는 네 가지 구성 요 소 를 소개 한다.Surface,Group,Shape,Text.
  • Surface-사각형 으로 렌 더 링 할 수 있 는 영역 으로 다른 요소 의 용기
  • Group-여러 모양,텍스트 및 기타 그룹 을 수용 할 수 있 습 니 다
  • Shape-형상 정의,채 울 수 있 음
  • Text-텍스트 모양 정의
  • 속성
    Surface
  • width:렌 더 링 구역 의 너비
  • height:렌 더 링 구역 의 높이 를 정의 합 니 다
  • Shape
  • d:그리 기 경로 정의
  • stroke:테두리 색상
  • strokeWidth:묘사 폭
  • strokeDash:점선 정의
  • fill:색상 채 우기
  • Text
  • funt:글꼴 스타일,글꼴,크기,굵기 여부 정의:bold 35px Heiti SC
  • Path
  • moveto(x,y):좌표(x,y)로 이동
  • lineTo(x,y):연결(x,y)
  • arc():포물선 그리 기
  • close():폐쇄 공간
  • 코드 예제
    직선 그리 기
    这里写图片描述
    
    import React from 'react'
    import {
      View,
      ART
    } from 'react-native'
    
    export default class Line extends React.Component{
    
      render(){
    
        const path = ART.Path();
        path.moveTo(1,1); //       (1,1)   (0,0)
        path.lineTo(300,1); //      (300,1)
    
        return(
          <View style={this.props.style}>
            <ART.Surface width={300} height={2}>
              <ART.Shape d={path} stroke="#000000" strokeWidth={1} />
            </ART.Surface>
          </View>
        )
      }
    }
    
    
    점선 그리 기
    strokeDash 의 인 자 를 알 고 있 습 니 다.
    [10,5]:10 픽 셀 실선 을 그 려 5 픽 셀 공백 을 그 리 는 것 을 의미 합 니 다.이렇게 순환 합 니 다.
    [10,5,20,5]:10 픽 셀 실선 을 그립 니 다.5 픽 셀 공백 을 그립 니 다.20 픽 셀 실선 과 5 픽 셀 공백 을 그립 니 다.
    这里写图片描述
    
    import React from 'react'
    import {
      View,
      ART
    } from 'react-native'
    
    const {Surface, Shape, Path} = ART;
    
    export default class DashLine extends React.Component{
    
      render(){
    
        const path = Path()
          .moveTo(1,1)
          .lineTo(300,1);
    
        return(
          <View style={this.props.style}>
            <Surface width={300} height={2}>
              <Shape d={path} stroke="#000000" strokeWidth={2} strokeDash={[10,5]}/>
            </Surface>
          </View>
        )
      }
    }
    
    
    직사각형 그리 기
    먼저 lineTo 를 통 해 세 개의 변 을 그립 니 다.close 링크 네 번 째 변 을 사용 합 니 다.채 우기 색상 채 우기.
    这里写图片描述
    
    import React from 'react'
    import {
      View,
      ART
    } from 'react-native'
    
    const {Surface, Shape, Path} = ART;
    
    export default class Rect extends React.Component{
    
      render(){
    
        const path = new Path()
          .moveTo(1,1)
          .lineTo(1,99)
          .lineTo(99,99)
          .lineTo(99,1)
          .close();
    
        return(
          <View style={this.props.style}>
            <Surface width={100} height={100}>
              <Shape d={path} stroke="#000000" fill="#892265" strokeWidth={1} />
            </Surface>
          </View>
        )
      }
    }
    
    
    원 을 그리다
    arc(x,y,radius)의 사용,종점 좌표 거리 기점 좌표 의 상대 거 리 를 이해 합 니 다.
    这里写图片描述
    
    import React from 'react'
    import {
      View,
      ART
    } from 'react-native'
    
    const {Surface, Shape, Path} = ART;
    
    export default class Circle extends React.Component{
    
      render(){
    
        const path = new Path()
          .moveTo(50,1)
          .arc(0,99,25)
          .arc(0,-99,25)
          .close();
    
    
        return(
          <View style={this.props.style}>
            <Surface width={100} height={100}>
              <Shape d={path} stroke="#000000" strokeWidth={1}/>
            </Surface>
          </View>
        )
      }
    }
    
    
    텍스트 그리 기
    funt 속성 을 알 아 보 는 사용,규칙 은"굵기 글꼴"입 니 다.
    메모:글꼴 은 path 속성 을 지원 해 야 합 니 다.bug 가 적용 되 지 않 았 을 것 입 니 다.안 드 로 이 드 는 소스 코드 수정 을 통 해 해결 할 수 있 으 며 IOS 는 소스 코드 를 보지 않 았 다.
    这里写图片描述
    
    import React, {Component} from 'react';
    import {
      AppRegistry,
      StyleSheet,
      ART,
      View
    } from 'react-native';
    
    const {Surface, Text, Path} = ART;
    
    export default class ArtTextView extends Component {
    
      render() {
    
        return (
          <View style={styles.container}>
            <Surface width={100} height={100}>
              <Text strokeWidth={1} stroke="#000" font="bold 35px Heiti SC" path={new Path().moveTo(40,40).lineTo(99,10)} >React</Text>
            </Surface>
    
          </View>
    
        );
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
      },
    
    });
    
    
    부채꼴 그리 기
    这里写图片描述
    여기에서 arc 를 사용 하여 경 로 를 그 려 야 합 니 다.
    Wedge.js
    
    import React, { Component, PropTypes } from 'react';
    import { ART } from 'react-native';
    const { Shape, Path } = ART;
    
    /**
     * Wedge is a React component for drawing circles, wedges and arcs. Like other
     * ReactART components, it must be used in a <Surface>.
     */
    export default class Wedge extends Component<void, any, any> {
    
      static propTypes = {
        outerRadius: PropTypes.number.isRequired,
        startAngle: PropTypes.number.isRequired,
        endAngle: PropTypes.number.isRequired,
        originX: PropTypes.number.isRequired,
        originY: PropTypes.number.isRequired,
        innerRadius: PropTypes.number,
      };
    
    
      constructor(props : any) {
        super(props);
        (this:any).circleRadians = Math.PI * 2;
        (this:any).radiansPerDegree = Math.PI / 180;
        (this:any)._degreesToRadians = this._degreesToRadians.bind(this);
      }
    
      /**
       * _degreesToRadians(degrees)
       *
       * Helper function to convert degrees to radians
       *
       * @param {number} degrees
       * @return {number}
       */
      _degreesToRadians(degrees : number) : number {
        if (degrees !== 0 && degrees % 360 === 0) { // 360, 720, etc.
          return (this:any).circleRadians;
        }
        return degrees * (this:any).radiansPerDegree % (this:any).circleRadians;
      }
    
      /**
       * _createCirclePath(or, ir)
       *
       * Creates the ReactART Path for a complete circle.
       *
       * @param {number} or The outer radius of the circle
       * @param {number} ir The inner radius, greater than zero for a ring
       * @return {object}
       */
      _createCirclePath(or : number, ir : number) : Path {
        const path = new Path();
    
        path.move(0, or)
          .arc(or * 2, 0, or)
          .arc(-or * 2, 0, or);
    
        if (ir) {
          path.move(or - ir, 0)
            .counterArc(ir * 2, 0, ir)
            .counterArc(-ir * 2, 0, ir);
        }
    
        path.close();
    
        return path;
      }
    
      /**
       * _createArcPath(sa, ea, ca, or, ir)
       *
       * Creates the ReactART Path for an arc or wedge.
       *
       * @param {number} startAngle The starting degrees relative to 12 o'clock
       * @param {number} endAngle The ending degrees relative to 12 o'clock
       * @param {number} or The outer radius in pixels
       * @param {number} ir The inner radius in pixels, greater than zero for an arc
       * @return {object}
       */
      _createArcPath(originX : number, originY : number, startAngle : number, endAngle : number, or : number, ir : number) : Path {
        const path = new Path();
    
        // angles in radians
        const sa = this._degreesToRadians(startAngle);
        const ea = this._degreesToRadians(endAngle);
    
        // central arc angle in radians
        const ca = sa > ea ? (this:any).circleRadians - sa + ea : ea - sa;
    
        // cached sine and cosine values
        const ss = Math.sin(sa);
        const es = Math.sin(ea);
        const sc = Math.cos(sa);
        const ec = Math.cos(ea);
    
        // cached differences
        const ds = es - ss;
        const dc = ec - sc;
        const dr = ir - or;
    
        // if the angle is over pi radians (180 degrees)
        // we will need to let the drawing method know.
        const large = ca > Math.PI;
    
        // TODO (sema) Please improve theses comments to make the math
        // more understandable.
        //
        // Formula for a point on a circle at a specific angle with a center
        // at (0, 0):
        // x = radius * Math.sin(radians)
        // y = radius * Math.cos(radians)
        //
        // For our starting point, we offset the formula using the outer
        // radius because our origin is at (top, left).
        // In typical web layout fashion, we are drawing in quadrant IV
        // (a.k.a. Southeast) where x is positive and y is negative.
        //
        // The arguments for path.arc and path.counterArc used below are:
        // (endX, endY, radiusX, radiusY, largeAngle)
    
        path.move(or + or * ss, or - or * sc) // move to starting point
          .arc(or * ds, or * -dc, or, or, large) // outer arc
          .line(dr * es, dr * -ec);  // width of arc or wedge
    
        if (ir) {
          path.counterArc(ir * -ds, ir * dc, ir, ir, large); // inner arc
        }
    
        return path;
      }
    
      render() : any {
        // angles are provided in degrees
        const startAngle = this.props.startAngle;
        const endAngle = this.props.endAngle;
        // if (startAngle - endAngle === 0) {
        // return null;
        // }
    
        // radii are provided in pixels
        const innerRadius = this.props.innerRadius || 0;
        const outerRadius = this.props.outerRadius;
    
        const { originX, originY } = this.props;
    
        // sorted radii
        const ir = Math.min(innerRadius, outerRadius);
        const or = Math.max(innerRadius, outerRadius);
    
        let path;
        if (endAngle >= startAngle + 360) {
          path = this._createCirclePath(or, ir);
        } else {
          path = this._createArcPath(originX, originY, startAngle, endAngle, or, ir);
        }
    
        return <Shape {...this.props} d={path} />;
      }
    }
    
    
    예제 코드:
    
    import React from 'react'
    import {
      View,
      ART
    } from 'react-native'
    
    const {Surface} = ART;
    import Wedge from './Wedge'
    
    export default class Fan extends React.Component{
    
      render(){
    
        return(
          <View style={this.props.style}>
            <Surface width={100} height={100}>
              <Wedge
               outerRadius={50}
               startAngle={0}
               endAngle={60}
               originX={50}
               originY={50}
               fill="blue"/>
    
            </Surface>
          </View>
        )
      }
    }
    
    
    종합 예시
    这里写图片描述
    관련 코드:
    
    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, {
      Component
    }from 'react';
    import {
      ART as Art,
      StyleSheet,
      View,
      Dimensions,
      TouchableWithoutFeedback,
      Animated
    } from 'react-native';
    
    var HEART_SVG = "M130.4-0.8c25.4 0 46 20.6 46 46.1 0 13.1-5.5 24.9-14.2 33.3L88 153.6 12.5 77.3c-7.9-8.3-12.8-19.6-12.8-31.9 0-25.5 20.6-46.1 46-46.2 19.1 0 35.5 11.7 42.4 28.4C94.9 11 111.3-0.8 130.4-0.8"
    var HEART_COLOR = 'rgb(226,38,77,1)';
    var GRAY_HEART_COLOR = "rgb(204,204,204,1)";
    
    var FILL_COLORS = [
      'rgba(221,70,136,1)',
      'rgba(212,106,191,1)',
      'rgba(204,142,245,1)',
      'rgba(204,142,245,1)',
      'rgba(204,142,245,1)',
      'rgba(0,0,0,0)'
    ];
    
    var PARTICLE_COLORS = [
      'rgb(158, 202, 250)',
      'rgb(161, 235, 206)',
      'rgb(208, 148, 246)',
      'rgb(244, 141, 166)',
      'rgb(234, 171, 104)',
      'rgb(170, 163, 186)'
    ]
    
    getXYParticle = (total, i, radius) => {
      var angle = ( (2 * Math.PI) / total ) * i;
    
      var x = Math.round((radius * 2) * Math.cos(angle - (Math.PI / 2)));
      var y = Math.round((radius * 2) * Math.sin(angle - (Math.PI / 2)));
      return {
        x: x,
        y: y,
      }
    }
    
    getRandomInt = (min, max) => {
      return Math.floor(Math.random() * (max - min)) + min;
    }
    
    shuffleArray = (array) => {
      for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
      }
      return array;
    }
    
    
    var {
      Surface,
      Group,
      Shape,
      Path
    } = Art;
    
    //  Animated.createAnimatedComponent         
    //           
    var AnimatedShape = Animated.createAnimatedComponent(Shape);
    
    var {
      width: deviceWidth,
      height: deviceHeight
    } = Dimensions.get('window');
    
    export default class ArtAnimView extends Component {
      constructor(props) {
        super(props);
    
        this.state = {
          animation: new Animated.Value(0)
        };
      }
    
      explode = () => {
        Animated.timing(this.state.animation, {
          duration: 1500,
          toValue: 28
        }).start(() => {
          this.state.animation.setValue(0);
          this.forceUpdate();
        });
      }
    
      getSmallExplosions = (radius, offset) => {
        return [0, 1, 2, 3, 4, 5, 6].map((v, i, t) => {
    
          var scaleOut = this.state.animation.interpolate({
            inputRange: [0, 5.99, 6, 13.99, 14, 21],
            outputRange: [0, 0, 1, 1, 1, 0],
            extrapolate: 'clamp'
          });
    
          var moveUp = this.state.animation.interpolate({
            inputRange: [0, 5.99, 14],
            outputRange: [0, 0, -15],
            extrapolate: 'clamp'
          });
    
          var moveDown = this.state.animation.interpolate({
            inputRange: [0, 5.99, 14],
            outputRange: [0, 0, 15],
            extrapolate: 'clamp'
          });
    
          var color_top_particle = this.state.animation.interpolate({
            inputRange: [6, 8, 10, 12, 17, 21],
            outputRange: shuffleArray(PARTICLE_COLORS)
          })
    
          var color_bottom_particle = this.state.animation.interpolate({
            inputRange: [6, 8, 10, 12, 17, 21],
            outputRange: shuffleArray(PARTICLE_COLORS)
          })
    
          var position = getXYParticle(7, i, radius)
    
          return (
            <Group
              x={position.x + offset.x }
              y={position.y + offset.y}
              rotation={getRandomInt(0, 40) * i}
            >
              <AnimatedCircle
                x={moveUp}
                y={moveUp}
                radius={15}
                scale={scaleOut}
                fill={color_top_particle}
              />
              <AnimatedCircle
                x={moveDown}
                y={moveDown}
                radius={8}
                scale={scaleOut}
                fill={color_bottom_particle}
              />
            </Group>
          )
        }, this)
      }
    
      render() {
        var heart_scale = this.state.animation.interpolate({
          inputRange: [0, .01, 6, 10, 12, 18, 28],
          outputRange: [1, 0, .1, 1, 1.2, 1, 1],
          extrapolate: 'clamp'
        });
    
        var heart_fill = this.state.animation.interpolate({
          inputRange: [0, 2],
          outputRange: [GRAY_HEART_COLOR, HEART_COLOR],
          extrapolate: 'clamp'
        })
    
        var heart_x = heart_scale.interpolate({
          inputRange: [0, 1],
          outputRange: [90, 0],
        })
    
        var heart_y = heart_scale.interpolate({
          inputRange: [0, 1],
          outputRange: [75, 0],
        })
    
        var circle_scale = this.state.animation.interpolate({
          inputRange: [0, 1, 4],
          outputRange: [0, .3, 1],
          extrapolate: 'clamp'
        });
    
        var circle_stroke_width = this.state.animation.interpolate({
          inputRange: [0, 5.99, 6, 7, 10],
          outputRange: [0, 0, 15, 8, 0],
          extrapolate: 'clamp'
        });
    
        var circle_fill_colors = this.state.animation.interpolate({
          inputRange: [1, 2, 3, 4, 4.99, 5],
          outputRange: FILL_COLORS,
          extrapolate: 'clamp'
        })
    
        var circle_opacity = this.state.animation.interpolate({
          inputRange: [1, 9.99, 10],
          outputRange: [1, 1, 0],
          extrapolate: 'clamp'
        })
    
    
        return (
          <View style={styles.container}>
            <TouchableWithoutFeedback onPress={this.explode} style={styles.container}>
              <View style={{transform: [{scale: .8}]}}>
                <Surface width={deviceWidth} height={deviceHeight}>
                  <Group x={75} y={200}>
                    <AnimatedShape
                      d={HEART_SVG}
                      x={heart_x}
                      y={heart_y}
                      scale={heart_scale}
                      fill={heart_fill}
                    />
                    <AnimatedCircle
                      x={89}
                      y={75}
                      radius={150}
                      scale={circle_scale}
                      strokeWidth={circle_stroke_width}
                      stroke={FILL_COLORS[2]}
                      fill={circle_fill_colors}
                      opacity={circle_opacity}
                    />
    
                    {this.getSmallExplosions(75, {x: 89, y: 75})}
                  </Group>
                </Surface>
              </View>
            </TouchableWithoutFeedback>
          </View>
        );
      }
    };
    
    class AnimatedCircle extends Component {
      render() {
        var radius = this.props.radius;
        var path = Path().moveTo(0, -radius)
          .arc(0, radius * 2, radius)
          .arc(0, radius * -2, radius)
          .close();
        return React.createElement(AnimatedShape);
      }
    }
    
    var styles = StyleSheet.create({
      container: {
        flex: 1,
      }
    });
    
    
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기