在本教程中,学习如何使用 React Native 组件(例如 Image、Pressable 和 Vector 图标)来构建屏幕。
在本章中,我们将创建 StickerSmash 应用的第一个屏幕。
¥In this chapter, we will create the first screen of the StickerSmash app.
上面的屏幕显示一个图片和两个按钮。应用用户可以使用两个按钮之一选择图片。第一个按钮允许用户从他们的设备中选择图片。第二个按钮允许用户继续使用应用提供的默认图片。
¥The screen above displays an image and two buttons. The app user can select an image using one of the two buttons. The first button allows the user to select an image from their device. The second button allows the user to continue with a default image provided by the app.
用户选择图片后,他们将能够选择并向图片添加贴纸。那么,让我们开始创建这个屏幕。
¥Once the user selects an image, they'll be able to select and add a sticker to the image. So, let's get started creating this screen.
1
¥Break down the screen
在通过编写代码构建此屏幕之前,让我们将其分解为一些基本元素。这些元素中的大多数直接对应于 React Native 的内置 核心组件。
¥Before we build this screen by writing code, let's break it down into some essential elements. Most of these elements directly correspond to the built-in Core Components from React Native.
有三个基本要素:
¥There are three essential elements:
屏幕有背景颜色
¥The screen has a background color
屏幕中央显示一个大图片
¥There is a large image displayed at the center of the screen
屏幕下半部分有两个按钮
¥There are two buttons in the bottom half of the screen
第一个按钮由多个组件组成。父元素提供黄色边框,并在行内包含图标和文本组件。
¥The first button is composed of multiple components. The parent element provides a yellow border and contains an icon and text components inside a row.
在 React Native 中,样式(例如黄色边框)是使用 JavaScript 完成的,而 Web 则使用 CSS。大多数 React Native 核心组件都接受 style
属性,该属性接受 JavaScript 对象作为其值。有关样式的详细信息,请参阅 React Native 中的样式。
¥In React Native, styling (such as the yellow border) is done using JavaScript as compared to the web, where CSS is used. Most of the React Native core components accept a style
prop that accepts a JavaScript object as its value. For detailed information on styling, see Styling in React Native.
现在我们已经将 UI 分解为更小的块,我们准备开始编码。
¥Now that we've broken down the UI into smaller chunks, we're ready to start coding.
2
¥Style the background
让我们改变背景颜色。该值在 App.js 文件的 styles
对象中定义。
¥Let's change the background color. This value is defined in the styles
object in the App.js file.
将 styles.container.backgroundColor
属性的默认值 #fff
替换为 #25292e
。它将改变屏幕的背景颜色。
¥Replace the default value of #fff
with #25292e
for the styles.container.backgroundColor
property. It will change the background color of the screen.
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#25292e',
alignItems: 'center',
justifyContent: 'center',
},
});
React Native 使用与 Web 相同的颜色格式。它支持十六进制三元组(这就是
#fff
)、rgba
、hsl
以及一组命名颜色,例如red
、green
、blue
、peru
和papayawhip
。欲了解更多信息,请参阅 React Native 中的颜色。¥React Native uses the same color format as the web. It supports hex triplets (this is what
#fff
is),rgba
,hsl
, and a set of named colors likered
,green
,blue
,peru
, andpapayawhip
. For more information, see Colors in React Native.
3
¥Change the text color
背景很暗,因此文本难以阅读。<Text>
组件使用 #000
(黑色)作为其默认颜色。让我们为 <Text>
组件添加一个样式,以将 App.js 中的文本颜色更改为 #fff
(白色)。
¥The background is dark, so the text is difficult to read. The <Text>
component uses #000
(black) as its default color. Let's add a style to the <Text>
component to change the text color to #fff
(white) in App.js.
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Text style={{ color: '#fff' }}>
Open up App.js to start working on your app!
</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#25292e',
alignItems: 'center',
justifyContent: 'center',
},
});
4
¥Display the image
我们可以使用 React Native 的 <Image>
组件在应用中显示图片。<Image>
组件需要图片源。该源可以是 静态资源 或 URL。例如,可以从应用的 ./assets/images 目录中获取源,或者源可以来自 uri
属性形式的 网络。
¥We can use React Native's <Image>
component to display the image in the app. The <Image>
component requires a source of an image. This source can be a static asset or a URL. For example, the source can be required from the app's ./assets/images directory, or the source can come from the Network in the form of a uri
property.
接下来,在 App.js 中导入并使用 React Native 中的 <Image>
组件和 background-image.png
。我们还可以添加样式来显示图片。
¥Next, import and use the <Image>
component from React Native and background-image.png
in the App.js. Let's also add styles to display the image.
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, View, Image } from 'react-native';
const PlaceholderImage = require('./assets/images/background-image.png');
export default function App() {
return (
<View style={styles.container}>
<View style={styles.imageContainer}>
<Image source={PlaceholderImage} style={styles.image} />
</View>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#25292e',
alignItems: 'center',
},
imageContainer: {
flex: 1,
paddingTop: 58,
},
image: {
width: 320,
height: 440,
borderRadius: 18,
},
});
PlaceholderImage
变量引用 ./assets/images/background-image.png 并用作 <Image>
组件上的 source
属性。
¥The PlaceholderImage
variable references the ./assets/images/background-image.png and is used as the source
prop on the <Image>
component.
5
¥Dividing components into files
当我们向该屏幕添加更多组件时,让我们将代码划分为多个文件:
¥As we add more components to this screen, let's divide the code into multiple files:
在项目的根目录下创建一个组件目录。这将包含本教程中创建的所有自定义组件。
¥Create a components directory at the root of the project. This will contain all the custom components created throughout this tutorial.
然后,在 Components 文件夹中创建一个名为 ImageViewer.js 的新文件。
¥Then, create a new file called ImageViewer.js, inside the components folder.
移动代码以显示此文件中的图片以及 image
样式。
¥Move the code to display the image in this file along with the image
styles.
import { StyleSheet, Image } from 'react-native';
export default function ImageViewer({ placeholderImageSource }) {
return (
<Image source={placeholderImageSource} style={styles.image} />
);
}
const styles = StyleSheet.create({
image: {
width: 320,
height: 440,
borderRadius: 18,
},
});
接下来,让我们导入该组件并在 App.js 中使用它:
¥Next, let's import this component and use it in the App.js:
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, View } from 'react-native';
import ImageViewer from './components/ImageViewer';
const PlaceholderImage = require('./assets/images/background-image.png');
export default function App() {
return (
<View style={styles.container}>
<View style={styles.imageContainer}>
<ImageViewer placeholderImageSource={PlaceholderImage} />
</View>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#25292e',
alignItems: 'center',
},
imageContainer: {
flex: 1,
paddingTop: 58,
},
});
6
Pressable
创建按钮¥Create buttons using Pressable
React Native 提供了各种组件来处理原生平台上的触摸事件。在本教程中,我们将使用 <Pressable>
组件。它是一个核心组件封装器,可以检测交互的各个阶段,从基本的单击事件到长按等高级事件。
¥React Native provides various components to handle touch events on native platforms. For this tutorial, we'll use the <Pressable>
component. It is a core component wrapper that can detect various stages of interactions, from basic single-tap events to advanced events such as a long press.
在设计中,我们需要实现两个按钮。每个都有不同的风格和标签。让我们首先创建一个可重用来创建两个按钮的组件。
¥In the design, there are two buttons we need to implement. Each has different styles and labels. Let's start by creating a component that can be reused to create the two buttons.
使用以下代码在组件目录中创建一个名为 Button.js 的新文件:
¥Create a new file called Button.js inside the components directory with the following code:
import { StyleSheet, View, Pressable, Text } from 'react-native';
export default function Button({ label }) {
return (
<View style={styles.buttonContainer}>
<Pressable style={styles.button} onPress={() => alert('You pressed a button.')}>
<Text style={styles.buttonLabel}>{label}</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
buttonContainer: {
width: 320,
height: 68,
marginHorizontal: 20,
alignItems: 'center',
justifyContent: 'center',
padding: 3,
},
button: {
borderRadius: 10,
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
},
buttonIcon: {
paddingRight: 8,
},
buttonLabel: {
color: '#fff',
fontSize: 16,
},
});
现在,在应用中,当用户点击屏幕上的任何按钮时,都会显示警报。发生这种情况是因为 <Pressable>
在其 onPress
属性中调用了 alert()
。
¥Now, in the app, an alert will be displayed when the user taps any of the buttons on the screen. It happens because the <Pressable>
calls an alert()
in its onPress
prop.
让我们将此组件导入到 App.js 文件中,并为封装这些按钮的 <View>
组件添加样式:
¥Let's import this component into App.js file and add styles for <View>
component that encapsulates these buttons:
import { StatusBar } from "expo-status-bar";
import { StyleSheet, View} from "react-native";
import Button from './components/Button';
import ImageViewer from './components/ImageViewer';
const PlaceholderImage = require("./assets/images/background-image.png");
export default function App() {
return (
<View style={styles.container}>
<View style={styles.imageContainer}>
<ImageViewer placeholderImageSource={PlaceholderImage} />
</View>
<View style={styles.footerContainer}>
<Button label="Choose a photo" />
<Button label="Use this photo" />
</View>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
%%placeholder-start%%// Styles that are unchanged from previous step are hidden for brevity. %%placeholder-end%%container: {
flex: 1,
backgroundColor: '#25292e',
alignItems: 'center',
},
imageContainer: {
flex: 1,
paddingTop: 58,
},
footerContainer: {
flex: 1 / 3,
alignItems: 'center',
},
});
让我们看看我们在 Android、iOS 和 Web 上的应用:
¥Let's take a look at our app on Android, iOS and the web:
带有标签 "使用这张照片" 的第二个按钮类似于设计中的实际按钮。但是,第一个按钮需要更多样式来匹配设计。
¥The second button with the label "Use this photo" resembles the actual button from the design. However, the first button needs more styling to match the design.
7
¥Enhance the reusable button component
"选择一张照片" 按钮需要与 "使用这张照片" 按钮不同的样式,因此我们将添加一个新的按钮主题属性,该属性将允许我们应用 primary
主题。该按钮在标签之前还有一个图标。我们将使用 @expo/vector-icons
库中的图标,其中包括流行图标集中的图标。
¥The "Choose a photo" button requires different styling than the "Use this photo" button, so we will add a new button theme prop that will allow us to apply a primary
theme.
This button also has an icon before the label. We will use an icon from the @expo/vector-icons
library that includes icons from popular icon sets.
在终端中按 Ctrl + c 停止开发服务器。然后,安装 @expo/vector-icons
库:
¥Stop the development server by pressing Ctrl + c in the terminal. Then, install the @expo/vector-icons
library:
-
npx expo install @expo/vector-icons
npx expo install
命令将安装该库并将其添加到 package.json 中的项目依赖中。
¥The npx expo install
command will install the library and add it to the project's dependencies in package.json.
安装库后,通过运行 npx expo start
命令重新启动开发服务器。
¥After installing the library, restart the development server by running the npx expo start
command.
要加载并在按钮上显示图标,让我们使用库中的 FontAwesome
。修改 Button.js 添加以下代码片段:
¥To load and display the icon on the button, let's use FontAwesome
from the library. Modify Button.js to add the following code snippet:
import { StyleSheet, View, Pressable, Text } from 'react-native';
import FontAwesome from "@expo/vector-icons/FontAwesome";
export default function Button({ label, theme }) {
if (theme === "primary") {
return (
<View style={[styles.buttonContainer, { borderWidth: 4, borderColor: "#ffd33d", borderRadius: 18 }]}>
<Pressable
style={[styles.button, { backgroundColor: "#fff" }]}
onPress={() => alert('You pressed a button.')}
>
<FontAwesome
name="picture-o"
size={18}
color="#25292e"
style={styles.buttonIcon}
/>
<Text style={[styles.buttonLabel, { color: "#25292e" }]}>{label}</Text>
</Pressable>
</View>
);
}
return (
<View style={styles.buttonContainer}>
<Pressable style={styles.button} onPress={() => alert('You pressed a button.')}>
<Text style={styles.buttonLabel}>{label}</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
// Styles from previous step remain unchanged.
});
我们来了解一下上面的代码做了什么:
¥Let's learn what the above code does:
主主题按钮使用内联样式,它使用直接在 style
属性中传递的对象覆盖 StyleSheet.create()
中定义的样式。内联样式使用 JavaScript。
¥The primary theme button uses inline styles which overrides the styles defined in the StyleSheet.create()
with an object directly passed in the style
prop. Inline styles use JavaScript.
主主题中的 <Pressable>
组件使用 #fff
的 backgroundColor
属性来设置按钮的背景颜色。如果我们将此属性添加到 styles.button
,则将为主要主题和无样式主题设置背景颜色值。
¥The <Pressable>
component in the primary theme uses a backgroundColor
property of #fff
to set the button's background color. If we add this property to the styles.button
, then the background color value will be set for both the primary theme and the unstyled one.
使用内联样式可以覆盖特定值的默认样式。
¥Using inline styles allows overriding the default styles for a specific value.
现在,修改 App.js 文件以在第一个按钮上使用 theme="primary"
属性。
¥Now, modify the App.js file to use the theme="primary"
prop on the first button.
export default function App() {
return (
<View style={styles.container}>
<View style={styles.imageContainer}>
<ImageViewer placeholderImageSource={PlaceholderImage} />
</View>
<View style={styles.footerContainer}>
<Button theme="primary" label="Choose a photo" />
<Button label="Use this photo" />
</View>
<StatusBar style="auto" />
</View>
);
}
让我们看看我们在 Android、iOS 和 Web 上的应用:
¥Let's take a look at our app on Android, iOS and the web:
¥Next step
我们实现了最初的设计。
¥We implemented the initial design.
在下一章中,我们将添加从设备的媒体库中选取图片的功能。