Skip to main content

ReactNative快速入门

处理文本输入

TextInput是一个允许用户输入文本的基础组件。它有一个onChangeText函数属性,此属性会在文本变化时被调用。还有一个onSubmitEditing属性,会在文本被提交后(用户按下软键盘上的提交键)调用。

假如我们要实现当用户输入时,实时将其以单词为单位翻译为另一种文字。一个单词翻译成一个 🍕。所以"Hello there ioser"将会被翻译为"🍕🍕🍕"。

TextInput示例
import React, { useState } from 'react';
import { SafeAreaView, Text, TextInput, View } from 'react-native';

const App = () => {
const [text, setText] = useState('');
return (
<SafeAreaView>
<View style={{ padding: 10 }}>
<TextInput
style={{ height: 40 }}
placeholder="Type here to translate!"
onChangeText={text => setText(text)}
onSubmitEditing={() => setText('submit')}
defaultValue={text}
/>
<Text style={{ padding: 10, fontSize: 42 }}>
{text.split(' ').map((word) => word && '🍕').join(' ')}
</Text>

<Image source={{
uri: 'https://reactnative.dev/img/tiny_logo.png',
width: 64,
height: 64
}}></Image>
</View>
</SafeAreaView>
);
}

export default App;

在上面的例子里,我们把text保存到 state 中,因为它会随着时间变化。上面的例子中顺便演示了下Image组件的用法。

使用滚动视图

滚动视图

ScrollView是一个通用的可滚动的容器,你可以在其中放入多个组件和视图。ScrollView 不仅可以垂直滚动,还能水平滚动(通过horizontal属性来设置)。

import React from 'react';
import { Image, SafeAreaView, ScrollView, Text } from 'react-native';

const logo = {
uri: 'https://reactnative.dev/img/tiny_logo.png',
width: 64,
height: 64
};

const App = () => (
<SafeAreaView>
<ScrollView>
<Text style={{ fontSize: 96 }}>Scroll me plz</Text>
<Image source={logo} />
<Image source={logo} />
<Text style={{ fontSize: 96 }}>If you like</Text>
<Image source={logo} />
<Image source={logo} />
<Image source={logo} />
<Text style={{ fontSize: 96 }}>Scrolling down</Text>
<Image source={logo} />
<Image source={logo} />
<Image source={logo} />
<Image source={logo} />
<Image source={logo} />
<Text style={{ fontSize: 96 }}>What's the best</Text>
<Image source={logo} />
<Image source={logo} />
<Text style={{ fontSize: 96 }}>Framework around?</Text>
<Image source={logo} />
<Image source={logo} />
<Image source={logo} />
<Image source={logo} />
<Image source={logo} />
<Text style={{ fontSize: 80 }}>React Native</Text>
</ScrollView>
</SafeAreaView>
);
export default App;

知识拓展

对上述示例进行扩展,将Text和Image都封装成一个组件。了解即可

了解组件封装
function MyImage() {
return <Image source={logo} />
}

const MyText: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<Text style={{ fontSize: 56 }}>
{children}
</Text>
);

function MyText2({ children }: {children: React.ReactNode} ) {
return <Text style={{ fontSize: 56 }}>{children}</Text>
}

左右滚动

  <ScrollView horizontal>

允许使用滑动手势对视图进行分页

  <ScrollView pagingEnabled>

允许用户对内容进行缩放(仅iOS支持,后面可用手势实现类似功能)

  <ScrollView maximumZoomScale={5} minimumZoomScale={1}>
warning

ScrollView适合用来显示数量不多的滚动元素。放置在ScrollView中的所有组件都会被渲染,哪怕有些组件因为内容太长被挤出了屏幕外。如果你需要显示较长的滚动列表,那么应该使用功能差不多但性能更好的FlatList组件。下面我们来看看如何使用长列表。

使用长列表

React Native 提供了几个适用于展示长列表数据的组件,一般而言我们会选用FlatList或是SectionList

FlatList示例

FlatList
  • FlatList组件用于显示垂直的滚动列表,其中元素之间结构近似,仅数据不同。
  • FlatList更适于长列表数据,且元素个数可以增删。
  • 和ScrollView不同的是,FlatList并不立即渲染所有元素,而是优先渲染屏幕上可见的元素。
  • FlatList组件必须的两个属性是data和renderItem。data是列表的数据源,而renderItem则从数据源中逐个解析数据,然后返回一个设定好格式的组件来渲染。

下面的例子创建了一个简单的FlatList,并预设了一些模拟数据。

import { FlatList, SafeAreaView, StyleSheet, Text, View } from 'react-native';
// 创建样式
const styles = StyleSheet.create({
item: {
padding: 10,
fontSize: 18,
height: 44,
},
});
const FlatListBasics = () => {
return (
<SafeAreaView>
<FlatList
data={[
{key: 'Devin'},
{key: 'Dan'},
{key: 'Dominic'},
{key: 'Jackson'},
{key: 'James'},
{key: 'Joel'},
{key: 'John'},
{key: 'Jillian'},
{key: 'Jimmy'},
{key: 'Julie'},
]}
renderItem={({item}) => <Text style={styles.item}>{item.key}</Text>}
/>
</SafeAreaView>
);
}

export default FlatListBasics;

SectionList示例

如果要渲染分组的数据,可以使用SectionList

import React from 'react';
import { SectionList, SafeAreaView, Text, StyleSheet } from 'react-native';

const styles = StyleSheet.create({
item: {
padding: 10,
fontSize: 18,
height: 44,
},
});

const SectionListBasics = () => {
return (
<SafeAreaView>
{/* data是固定的字段,renderItem中的item就是遍历的data数组 */}
<SectionList sections={[
{title1: 'D', data: ['Devin', 'Dan', 'Dominic']},
{title1: 'J', data: ['Jackson', 'James', 'Jillian', 'Jimmy', 'Joel', 'John', 'Julie']},
]}
renderSectionHeader={({section}) => <Text>{section.title1}</Text>}
renderItem={({item})=><Text style={styles.item}>{item}</Text>}
keyExtractor={(item, index) => index.toString()}
></SectionList>
</SafeAreaView>
)
}

export default SectionListBasics;

特定平台代码

在编写跨平台的应用时,我们肯定希望尽可能多地复用代码。但是总有些时候我们会碰到针对不同平台编写不同代码的需求。

React Native 提供了两种方法来区分平台:

  • 使用Platform模块.
  • 使用特定平台后缀.

Platform 模块

Platform 模块是一个检测当前运行平台的模块。如果组件只有一小部分代码需要依据平台定制,那么就可以用这个模块。

import {Platform, StyleSheet} from 'react-native';

const styles = StyleSheet.create({
height: Platform.OS === 'ios' ? 200 : 100,
});

Platform.OS在 iOS 上会返回ios,而在 Android 设备或模拟器上则会返回android

还有个实用的方法是 Platform.select(),它可以以 Platform.OS 为 key,从传入的对象中返回对应平台的值,见下面的示例:

import {Platform, StyleSheet} from 'react-native';

const styles = StyleSheet.create({
container: {
flex: 1,
...Platform.select({
ios: {
backgroundColor: 'red',
},
android: {
backgroundColor: 'blue',
},
}),
},
});

这一方法可以接受任何合法类型的参数,因此你也可以直接用它针对不同平台返回不同的组件,像下面这样:

const Component = Platform.select({
ios: () => require('ComponentIOS'),
android: () => require('ComponentAndroid'),
})();

<Component />;
danger

上面的写法是官方网站写法,但实际运行时会报错。能意会用法即可,下面是可以运行的示例

首先在根目录下创建"components"文件夹,然后分别创建两个文件:ComponentIOS.tsx和ComponentAndroid.tsx。

ComponentIOS.tsx
import React from 'react';
import { SafeAreaView, Text, View } from 'react-native';

const ComponentIOS = () => {
return (
<SafeAreaView>
<View style={{ padding: 10 }}>
<Text style={{color: 'green'}}>this is ios component</Text>
</View>
</SafeAreaView>
);
}

export default ComponentIOS;
ComponentAndroid.tsx
import React from 'react';
import { SafeAreaView, Text, View } from 'react-native';

const ComponentAndroid = () => {
return (
<SafeAreaView>
<View style={{ padding: 10 }}>
<Text style={{color: 'red'}}>this is Android component</Text>
</View>
</SafeAreaView>
);
}

export default ComponentAndroid;

根据不同平台展示不同组件

import React from 'react';
import { SafeAreaView, Text, Platform } from 'react-native';

const ComponentPlatform = () => {
const ComponentToRender = Platform.select({
ios: require('./components/ComponentIOS').default,
android: require('./components/ComponentAndroid').default,
});

return (
<SafeAreaView>
<ComponentToRender />
</SafeAreaView>
);
};

export default ComponentPlatform;

检测 Android 版本

在 Android 上,Version属性是一个数字,表示 Android 的 api level:

import {Platform} from 'react-native';

if (Platform.Version === 25) {
console.log('Running on Nougat!');
}

检测 iOS 版本

iOS 上,Version属性是-[UIDevice systemVersion]的返回值,具体形式为一个表示当前系统版本的 字符串。比如可能是"10.3"。

import {Platform} from 'react-native';

const majorVersionIOS = parseInt(Platform.Version, 10);
if (majorVersionIOS <= 9) {
console.log('Work around a change in behavior');
}

安卓和iOS版本号验证

console.log(Platform.OS + "---" + typeof Platform.Version);

特定平台后缀

当不同平台的代码逻辑较为复杂时,最好是放到不同的文件里,这时候我们可以使用特定平台后缀。React Native 会检测某个文件是否具有.ios.或是.android.的后缀,然后根据当前运行的平台自动加载正确对应的文件。

比如你可以在项目中创建下面这样的组件:

BigButton.ios.tsx
BigButton.android.tsx

然后去掉平台后缀直接引用:

import BigButton from './BigButton';

React Native 会根据运行平台的不同自动引入正确对应的组件。

示例:

BigButton.android.tsx
import React from 'react';
import { Button, SafeAreaView, View } from 'react-native';

const BigButton = () => {
return (
<SafeAreaView>
<View style={{ padding: 10 }}>
<Button title='this is android Button'/>
</View>
</SafeAreaView>
);
}

export default BigButton;

使用组件

import React from 'react';
import { SafeAreaView, Platform } from 'react-native';
import BigButton from './components/BigButton';

const ComponentPlatform = () => {
return (
<SafeAreaView>
<BigButton />
</SafeAreaView>
);
};

export default ComponentPlatform;