To find the referenced sketch file visit UIDesignDaily and download it. This will contain many different components you can build. We will focus on a component that displays caloric information as well as other information related to a recipe.
First we’ll need to install react-native-svg
for so we can render our SVG icons. To install run expo install react-native-svg
to get the correct version according to the expo version you have installed
To convert our SVG code visit Transform Tools which will take an SVG and convert it to React Native SVG code so we don’t have to do it manually.
It will produce a rough output, and we’ll massage it. Create an icons.js
file and we’ll hold all of our icons in it for our display bar.
import React from "react"; import Svg, { G, Path, Circle, Rect } from "react-native-svg"; export const Clock = (props) => { return ( <Svg width="26px" height="28px" viewBox="0 0 26 28" {...props}> <G transform="translate(-247 -922) translate(202 878) translate(40 40)" stroke="none" strokeWidth={1} fill="none" fillRule="evenodd" > <Path d="M0 0L36 0 36 36 0 36z" /> <Circle stroke="#111127" strokeWidth={2.25} strokeLinecap="round" strokeLinejoin="round" cx={18} cy={19.5} r={10.5} /> <Path stroke="#111127" strokeWidth={2.25} strokeLinecap="round" strokeLinejoin="round" d="M18 15L18 19.5 21 19.5" /> <Path d="M10.5 6L6.375 9M25.5 6l4.125 3" stroke="#111127" strokeWidth={2.25} strokeLinecap="round" strokeLinejoin="round" /> </G> </Svg> ); }; export const Serving = (props) => { return ( <Svg width="25px" height="25px" viewBox="0 0 25 25" {...props}> <G transform="translate(-377 -924) translate(202 878) translate(173 43)" stroke="none" strokeWidth={1} fill="none" fillRule="evenodd" > <Path d="M0 0L30 0 30 30 0 30z" /> <Path d="M12.5 4A11.25 11.25 0 1026 17.5c0-.69-.56-1.25-1.25-1.25h-8.5a2.5 2.5 0 01-2.5-2.5V5a1.125 1.125 0 00-1.25-1" stroke="#111127" strokeWidth={1.875} strokeLinecap="round" strokeLinejoin="round" /> <Path d="M18.75 4.375a11.25 11.25 0 016.875 6.875H20c-.69 0-1.25-.56-1.25-1.25V4.375" stroke="#111127" strokeWidth={1.875} strokeLinecap="round" strokeLinejoin="round" /> </G> </Svg> ); }; export const Calories = (props) => { return ( <Svg width="26px" height="24px" viewBox="0 0 26 24" {...props}> <G transform="translate(-531 -924) translate(202 878) translate(326 42)" stroke="none" strokeWidth={1} fill="none" fillRule="evenodd" > <Path d="M0 0L32 0 32 32 0 32z" /> <Rect stroke="#111127" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" x={4} y={16} width={8} height={10.6666667} rx={1.33333333} /> <Rect stroke="#111127" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" x={12} y={10.6666667} width={8} height={16} rx={1.33333333} /> <Rect stroke="#111127" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" x={20} y={5.33333333} width={8} height={21.3333333} rx={1.33333333} /> <Path d="M5.333 26.667H24" stroke="#202842" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" /> </G> </Svg> ); };
Now we’ll render our white bar container. The container
will take up the whole screen and also center our general content. The spacer
are each flex: 1
and will center the content without affecting the caloric display content.
export default function App() { return ( <View style={styles.container}> <View style={styles.spacer} /> <View style={styles.whiteWrap}></View> <View style={styles.spacer} /> </View> ); }
Our styling for our container, and spacers.
const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#F1E8E6", paddingHorizontal: 10, alignItems: "center", }, spacer: { flex: 1, }, });
Now lets pull apart our styling for our whiteWrap
. We set our background color to white, and swap our content to display as flexDirection: ‘row’
. Then we’ll set all of our content to be aligned in the center, and use the space-between
setting to spread out our inner component pieces. One added benefit would be to potentially add flexWrap: ‘wrap'
if you’re going to render more than 3 items.
Finally our shadow is made up of 4 pieces. shadowColor
sets the color, the shadowOpacity
sets the opacity. Finally our shadowRadius
describes the spread of our shadow. The shadowOffset
will move that shadow over on the X and Y even though it is labeled width and height. Here we have a 2
offset on y axis.
const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#F1E8E6", paddingHorizontal: 10, alignItems: "center", }, spacer: { flex: 1, }, whiteWrap: { backgroundColor: "#FFFFFF", shadowColor: "#F55951", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 10, borderRadius: 15, paddingHorizontal: 20, paddingVertical: 25, flexDirection: "row", alignItems: "center", justifyContent: "space-between", }, });
Now we have our piece component. It will render each piece of data and will take an icon
that is a React component, as well as children
which will be some text. We want our icon and our text to be side by side. So we wrap it in a View
and give it a flexDirection: ‘row’
and align in the center. The marginRight
will make it so it can live next to others and have some spacing between other piece components.
Because we’re receiving a React component for our icon
we can just drop it right in. Finally our Text
will be bold, and apply a marginLeft
so it is separated from the icon.
const Piece = ({ icon, children }) => { return ( <View style={{ flexDirection: "row", alignItems: "center", justifyContent: "center", marginRight: 10, }} > {icon} <Text style={{ marginLeft: 10, fontWeight: "bold", fontSize: 12, }} > {children} </Text> </View> ); };
Now that we have a small piece component we can render our icons in the icon
prop and pass our text in as children.
import React from "react"; import { StyleSheet, Text, View } from "react-native"; import { Calories, Serving, Clock } from "./icons"; export default function App() { return ( <View style={styles.container}> <View style={styles.spacer} /> <View style={styles.whiteWrap}> <Piece icon={<Clock />}>30 min</Piece> <Piece icon={<Serving />}>6 servings</Piece> <Piece icon={<Calories />}>210 calories</Piece> </View> <View style={styles.spacer} /> </View> ); }