Insta4, React Native Icons
For developing mobile application like Instagram with react native and typescript, this writing explains how to use React Native Icons. This article is continued one from previous article.
1. Install and set up for icons
- Refer to official document for icons: https://github.com/oblador/react-native-vector-icons/tree/10.x?tab=readme-ov-file
- Install following packages and link it to CocoaPod.
$ cd InstaTest $ npm i react-native-vector-icons $ npm i -D @types/react-native-vector-icons $ cd ios $ npx pod-install $ cd ..
- If your Metro server is running, you need to escape from it first by ctrl + c. When Metro is running, packages are locked so other package cannot be added.
- Set up for iOS : Edit the ios/projectName/Info.plist
- Below <key>UIAppFonts</key> should be added.
ios/InstaTest/Info.plist
... <key>UIViewControllerBasedStatusBarAppearance</key> <false/> <key>UIAppFonts</key> <array> <string>AntDesign.ttf</string> <string>Entypo.ttf</string> <string>EvilIcons.ttf</string> <string>Feather.ttf</string> <string>FontAwesome.ttf</string> <string>FontAwesome5_Brands.ttf</string> <string>FontAwesome5_Regular.ttf</string> <string>FontAwesome5_Solid.ttf</string> <string>FontAwesome6_Brands.ttf</string> <string>FontAwesome6_Regular.ttf</string> <string>FontAwesome6_Solid.ttf</string> <string>Foundation.ttf</string> <string>Ionicons.ttf</string> <string>MaterialIcons.ttf</string> <string>MaterialCommunityIcons.ttf</string> <string>SimpleLineIcons.ttf</string> <string>Octicons.ttf</string> <string>Zocial.ttf</string> <string>Fontisto.ttf</string> </array> </dict> </plist>
- Set up for Android : Edit the android/app/build.gradle
- Add apply from: file("../../node_modules/react-native-vector-icons/fonts.gradle") at the end
android/app/build.gradle
android { ... } dependencies { ... } // Below should be added apply from: file("../../node_modules/react-native-vector-icons/fonts.gradle")
- After above setup, iOS and Android project should be built again.
$ npx react-native run-ios $ npx react-native run-android
- Icons can be used like below example.
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; export default function App() { return ( <Icon name={'home'} size={50} color={MD3Colors.primary50} onPress={onIconPressed} /> ) }
- You can put various Icon by entering some name. (ex. name={'home'})
- Above example use Material Community Icons and the icon name can be found here: https://pictogrammers.com/library/mdi/
2. Making IconText component
- Make following files in components directory.
$ cd src $ cd components $ touch IconText.tsx index.ts $ cd ../..
- Import TouchableView and use it in IconText component. Make IconText.tsx as below.
src/components/IconText.tsx
import React from 'react'; import type {FC, ComponentProps} from 'react'; import {Text} from 'react-native'; import type {TextStyle, StyleProp} from 'react-native'; import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; import {TouchableView} from './TouchableView'; import type {TouchableViewProps} from './TouchableView'; export type IconTextProps = TouchableViewProps & ComponentProps<typeof Icon> & { text: number | string textStyle: StyleProp<TextStyle> } export const IconText: FC<IconTextProps> = ({ name, size, color, textStyle, text, ...touchableViewProps }) => { return ( <TouchableView {...touchableViewProps}> <Icon name={name} size={size} color={color} /> <Text style={textStyle}>{text}</Text> </TouchableView> ) }
- IconTextProps takes TouchableViewProps and custom props such as Icon and text, textStyle. text can be number or string.
- To make it easy to use it in Person.tsx, make index.ts as below.
src/components/index.ts
export * from './TouchableView'; export * from './Avatar'; export * from './IconText';
3. Styling Person.tsx
- Edit the structure with flexDirection and styling again the Person.tsx as below.
src/copy/Person.tsx
import React from 'react'; import type {FC} from 'react'; import {View, Text, Image, Alert} from 'react-native'; import {MD3Colors} from 'react-native-paper'; import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; import {styles} from './Person.style'; import * as D from '../data'; import moment from 'moment'; import {Avatar, IconText} from '../components'; export type PersonProps = { person: D.IPerson } const avatarPressed = () => Alert.alert('avatar pressed.') const deletePressed = () => Alert.alert('delete pressed.') const countIconPressed = (name: string) => () => Alert.alert(`${name} pressed`) const Person: FC<PersonProps> = ({person}) => { return ( <View style={[styles.view]}> <View style={[styles.leftView]}> <Avatar imageStyle={[styles.avatar]} uri={person.avatar} size={50} onPress={avatarPressed} /> </View> <View style={[styles.rightView]}> <Text style={[styles.name]}>{person.name}</Text> <Text style={[styles.email]}>{person.email}</Text> <View style={[styles.dateView]}> <Text style={[styles.text]}> {moment(person.createdDate).startOf('day').fromNow()} </Text> <Icon name='trash-can' size={26} color={MD3Colors.secondary50} onPress={deletePressed} /> </View> <Text numberOfLines={3} ellipsizeMode="tail" style={[styles.text, styles.comments]}>{person.comments}</Text> <Image style={[styles.image]} source={{uri: person.image}} /> <View style={[styles.countsView]}> <IconText ViewStyle={[styles.touchableIcon]} onPress={countIconPressed('comment')} name="comment" size={24} color={MD3Colors.secondary20} textStyle={[styles.iconText]} text={person.counts.comment} /> <IconText ViewStyle={[styles.touchableIcon]} onPress={countIconPressed('retweet')} name="repeat-variant" size={24} color={MD3Colors.secondary20} textStyle={[styles.iconText]} text={person.counts.retweet} /> <IconText ViewStyle={[styles.touchableIcon]} onPress={countIconPressed('heart')} name="heart" size={24} color={MD3Colors.secondary20} textStyle={[styles.iconText]} text={person.counts.heart} /> </View> </View> </View> ) } export default Person
- To limit the text, use the numberOfLines attribute. In this case numberOfLines={3} is used.
- With ellipsizeMode="tail" attribute, it shows "..." at the end of text when there is more text behind 3rd line.
- Icon name such as trash-can, comment etc is found in here: https://pictogrammers.com/library/mdi/
src/copy/Person.style.ts
import {StyleSheet} from 'react-native'; import {MD3Colors} from 'react-native-paper'; export const styles = StyleSheet.create({ view: { flexDirection: 'row', backgroundColor: MD3Colors.primary80, padding: 5, }, leftView: {padding: 5}, avatar: {borderColor: MD3Colors.primary100, borderWidth: 2}, rightView: {flex: 1, padding: 5, marginRight: 10}, name: {marginRight: 5, fontSize: 22, fontWeight: '500'}, email: { textDecorationLine: 'underline', color: MD3Colors.secondary100, textDecorationColor: MD3Colors.secondary80, }, dateView: { flexDirection: 'row', justifyContent: 'space-between', padding: 3, marginTop: 5, }, text: {fontSize: 16}, comments: {marginTop: 10, fontSize: 16}, image: {height: 150, marginTop: 15}, countsView: { flexDirection: 'row', padding: 3, justifyContent: 'space-around', }, touchableIcon: {flexDirection: 'column', padding: 5, alignItems: 'center'}, iconText: {color: MD3Colors.primary200, marginLeft: 3}, });
- Align the view with leftView and rightView. In the leftView there is only avatar icon, and in the rightView there are other contents just like Insta.
- At the bottom of the rightView, there are comment, retweet, heart in a row. flexDirection row and space-around so it looks more familiar.
Comments
Post a Comment