Icon buttons
Using icons for buttons is a very common UI pattern for mobile apps. Icons make the app feel nicer as it allwes us to have less text on your sceen, making it easier on the eyes.
We'll be using Expo Icons which is built on top of react-native-vector-icons and has a convenient website for searching for available icons.
Install @expo/vector-icons
npx expo install @expo/vector-icons
When installing new packages on an Expo app, it's recommended to use npx expo install
instead of the default yarn install
/ npm install
etc. The npx expo install
command will still call your preferred package manager to install the library under the hood (the preferred package manager is determined based on the lockfile in your codebase btw), the difference is that the npx expo install
command ensures we install an SDK-compatible version of the library (for libraries where these versions are tracked).
Replace the delete button with an icon
Let's replace the delete button with a cross icon.
For small icon buttons, use hitSlop
to ensure the pressable areas is large enough to comfortably tap.
Add a red (#ee6055
) color to the theme file:
Update: theme.ts
@@ -4,4 +4,5 @@ export const theme = {
colorBlack: "#000",
colorGrey: "grey",
colorLightGrey: "#eee",
+ colorRed: "#ee6055",
};
Use it as a background for the delete button:
Update: components/ShoppingListItem.tsx
@@ -1,4 +1,5 @@
import { TouchableOpacity, View, Alert, StyleSheet, Text } from "react-native";
+import AntDesign from "@expo/vector-icons/AntDesign";
import { theme } from "../theme";
type Props = {
@@ -37,15 +38,12 @@ export function ShoppingListItem({ name, isCompleted }: Props) {
>
{name}
</Text>
- <TouchableOpacity
- onPress={handleDelete}
- style={[
- styles.button,
- isCompleted ? styles.completedButton : undefined,
- ]}
- activeOpacity={0.8}
- >
- <Text style={styles.buttonText}>Delete</Text>
+ <TouchableOpacity hitSlop={20} onPress={handleDelete}>
+ <AntDesign
+ name="closecircle"
+ size={24}
+ color={isCompleted ? theme.colorGrey : theme.colorRed}
+ />
</TouchableOpacity>
</View>
);
@@ -54,7 +52,7 @@ export function ShoppingListItem({ name, isCompleted }: Props) {
const styles = StyleSheet.create({
itemContainer: {
paddingVertical: 16,
- paddingHorizontal: 8,
+ paddingHorizontal: 18,
borderBottomColor: theme.colorCerulean,
borderBottomWidth: 1,
flexDirection: "row",
@@ -65,17 +63,6 @@ const styles = StyleSheet.create({
fontSize: 18,
fontWeight: "200",
},
- button: {
- backgroundColor: theme.colorBlack,
- padding: 8,
- borderRadius: 6,
- },
- buttonText: {
- color: "#fff",
- fontWeight: "bold",
- textTransform: "uppercase",
- letterSpacing: 1,
- },
completedContainer: {
backgroundColor: theme.colorLightGrey,
borderBottomColor: theme.colorLightGrey,
@@ -85,7 +72,4 @@ const styles = StyleSheet.create({
textDecorationLine: "line-through",
textDecorationColor: theme.colorGrey,
},
- completedButton: {
- backgroundColor: theme.colorGrey,
- },
});
Use a circle / check icon on the left
Now let's also add check / circle icon buttons for the other side, based on whether the shopping list item is completed or not.
Update: components/ShoppingListItem.tsx
@@ -1,5 +1,6 @@
import { TouchableOpacity, View, Alert, StyleSheet, Text } from "react-native";
import AntDesign from "@expo/vector-icons/AntDesign";
+import Entypo from "@expo/vector-icons/Entypo";
import { theme } from "../theme";
type Props = {
@@ -30,14 +31,21 @@ export function ShoppingListItem({ name, isCompleted }: Props) {
isCompleted ? styles.completedContainer : undefined,
]}
>
- <Text
- style={[
- styles.itemText,
- isCompleted ? styles.completedText : undefined,
- ]}
- >
- {name}
- </Text>
+ <View style={styles.row}>
+ <Entypo
+ name={isCompleted ? "check" : "circle"}
+ size={24}
+ color={isCompleted ? theme.colorGrey : theme.colorCerulean}
+ />
+ <Text
+ style={[
+ styles.itemText,
+ isCompleted ? styles.completedText : undefined,
+ ]}
+ >
+ {name}
+ </Text>
+ </View>
<TouchableOpacity hitSlop={20} onPress={handleDelete}>
<AntDesign
name="closecircle"
@@ -62,6 +70,8 @@ const styles = StyleSheet.create({
itemText: {
fontSize: 18,
fontWeight: "200",
+ marginLeft: 8,
+ flex: 1,
},
completedContainer: {
backgroundColor: theme.colorLightGrey,
@@ -72,4 +82,9 @@ const styles = StyleSheet.create({
textDecorationLine: "line-through",
textDecorationColor: theme.colorGrey,
},
+ row: {
+ flexDirection: "row",
+ flex: 1,
+ alignItems: "center",
+ },
});
Checkpoint
Android | iOS |
---|---|