Neem contact op

SVG's gebruiken in React Native

Een eenvoudige opzet voor flexibel gebruik van SVG's

July 5, 2020
Cover image

Op het moment dat je gaat werken met iconen of vector illustraties in een applicatie, ga je willen werken met het Scalable Vector Graphics (SVG) formaat.

Verschillende devices hebben naast een andere grootte scherm, resolutie, ook een andere pixeldichtheid. En in tegenstelling tot .jpeg en .png formaten blijft een SVG altijd scherp, hoe je je iPhone of tablet ook wend of keert.

React Native configureren

Helaas kun je in React (Native) niet standaard een SVG tonen. Terwijl hiervoor in web browsers al even support voor is, moet je voor React Native een pakket downloaden om dit toch voor elkaar te krijgen. Een veel gebruikt pakket hiervoor is react-native-svg.

Voeg react-native-svg toe aan je project:

1npm install react-native-svg

Link de native code voor iOs:

1cd ios && pod install && cd ..

SVG als bestand importeren

Als je met iconen werkt scheelt het tijd als je deze plug-and-play in je project kan gebruiken. Hiervoor gebruiken we een tweede pakket die dit verzorgt, namelijk: react-native-svg-transformer.

Voeg het pakket toe aan je project:

1yarn add --dev react-native-svg-transformer

Vervang of vul je huidige metro.config.js aan in de root van je project met onderstaande configuratie:

// config.metro.js
const { getDefaultConfig } = require("metro-config");
 
module.exports = () => {
 return {
   transformer: {
     babelTransformerPath: require.resolve("react-native-svg-transformer")
   },
   resolver: {
     assetExts: assetExts.filter(ext => ext !== "svg"),
     sourceExts: [...sourceExts, "svg"]
   }
 };
14};

Vervolgens kun je het icoon direct in je code importeren, net als ieder ander React Component:

// app.js
import React from 'react';
import { View, StyleSheet } from 'react-native';
 
import AwardIcon from './src/assets/icons/award.svg';
 
const App = () => (
 <View style={styles.container}>
   <AwardIcon />
 </View>
);
 
const styles = StyleSheet.create({
 container: {
   alignItems: 'center',
   justifyContent: 'center',
   flex: 1,
 }
});
 
21export default App;

En als resultaat:

Je kan ook direct properties meegeven. Vergeet niet eventuele properties te verwijderen uit de SVG, inline properties krijgen namelijk voorrang op de properties die worden meegestuurd.

// award.svg
<svg version="1.1" x="0px" y="0px" viewBox="0 0 512 512"></svg>
3<svg></svg>

Het voordeel hiervan is dat je met één bestand een icoon met verschillende formaten en kleuren kan inzetten.

// app.js
const App = () => (
 <View style={styles.container}>
   <AwardIcon width="100%" height="100%" viewBox="0 0 512 512" fill="tomato"/>
 </View>
6 );

SVGs direct in je code gebruiken

Wanneer je te maken hebt met complexere toepassingen kan het handig zijn om een SVG op te bouwen met behulp van een functie. Hiermee kun je een section divider met variaties creëren door met booleans delen van de SVG niet te laten zien. Met dit in gedachte gaan we de tool Get Waves gebruiken om een section divider te maken en deze te implementeren op onderstaande wijze. Let daarbij op:

  • De viewBox geven we de afmetingen van de SVG mee om te zorgen dat de inhoud meeschaalt met container.
  • Met de preserveAspectRatio propertie passen we aan hoe de SVG zich verhoudt tot de viewbox. Op MDN is meer te lezen over de toepassing.
// page-divider.js
import React from 'react'
import { View, StyleSheet } from 'react-native'
import Svg, { G, Path } from 'react-native-svg'
 
export const PageDivider = ({ hasExtraLayer = true, fill = "#4279DD" }) => (
 <>
   <Svg width="100%" height="320" preserveAspectRatio="xMinYMax" viewBox="0 0 1440 320">
     <G {...{ fill }}>
       {hasExtraLayer &&
         <Path d="M0,128 L288,224 L576,192 L864,160 L1152,320 L1440,288 L1440,320 L1152,320 L864,320 L576,320 L288,320 L0,320Z" />
       }
       <Path fillOpacity="0.6" d="M0,128 L80,138.7C160,149,320,171,480,197.3C640,224,800,256,960,266.7 C1120,277, 1280,267, 1360,261.3 L1440,256 L1440,320 L1360,320 C1280,320,1120,320,960,320 C800,320, 640,320, 480,320 C320,320, 160,320, 80,320 L0,320 Z" />
     </G>
   </Svg >
   <View style={styles.container} />
 </>
)
 
const styles = StyleSheet.create({
 container: {
   flex: 1,
   backgroundColor: "#4279DD",
 }
25})

En dan krijgen we:

Transformaties toepassen

SVGs kunnen ook ingezet worden voor illustraties waar interactie een vereiste is. Hiervoor gebruiken we de 'PanResponder' functie van React Native. Deze functie herkent single- en multi-touch gebaren waarmee we kunnen bijhouden waar je het scherm aanraakt.

Dit gaan we gebruiken om een SVG path realtime aan te passen:

import React, { useState} from 'react'
import { View, PanResponder } from 'react-native'
import Svg, { Path } from 'react-native-svg'
 
export const App = () => {
 const [lipHeight, setLipHeight] = useState(0)
 
 const responder = PanResponder.create({
   onStartShouldSetPanResponder: () => true,
   onPanResponderMove: (e, gestureState) => {
     setLipsHeight(gestureState.moveY)
   },
 })
 
 return (
   <View {...responder.panHandlers}>
     <Svg width="100%" height="100%" >
      <Path stroke="#000" strokeWidth="20" strokeLinecap="round" d={`M110,480 Q200,${lipHeight} 300,480`}/>
     </Svg >
   </View>
 )
22}

met als resultaat:

An animation showing a line segment being bent through touch interaction

Aan de slag

Tot slot is het een goed idee om deze implementaties zelf ook te draaien om te zien of je alles goed begrijpt. Succes!


Ruben Werdmuller

Developer @Humanoids