一. 环境搭建(当前为mac)
需要安装的依赖有:Node(v10版本以上),WatchMan,React Native以及Xcode。
Node,Watchman
官方推荐的是用HomeBrew来安装WatchMan
brew install watchman
Node建议更改npm镜像
npm config set registry https://registry.npm.taobao.org --global
npm config set disturl https://npm.taobao.org/dist --global
Yarn、React Native 的命令行工具(react-native-cli)
React Native 的命令行工具用于执行创建、初始化、更新项目、运行打包服务(packager)等任务
npm install -g yarn react-native-cli
安装完 yarn 后同理也要更改镜像源:
yarn config set registry https://registry.npm.taobao.org --global
yarn config set disturl https://npm.taobao.org/dist --global
Xcode
mac的话可以去app store一键进行安装
初始化一个Demo
使用 React Native 命令行工具来创建一个名为"AwesomeProject"的新项目,init 命令默认会创建最新的版本。
react-native init AwesomeProject
在这个阶段可能会在CocoaPods安装相关依赖时卡住,因为其仓库不在国内,可以尝试更换成国内镜像,更换之后直接切换当前目录,启动项目。
cd AwesomeProject
react-native run-ios
如若遇到以下错误,可以尝试切换设备型号
react-native run-ios --simulator="iPhone 11"
如下所示,我们的环境就已经搭建好了。
二. react-native布局
react-native使用的布局模式是FlexBox,不过值得注意的是它跟我们之前所接触的css3的FlexBox还是有所不同的。
- flexDirection : react-native默认为 'column',而在css3中默认为 'row'。
- alignItems : react-native中默认为 'stretch',而在css3中默认为 'flex-start'。
- react-native中flex不接受多参数,不像css3中类似这种:flex: 2 2 20%。
- 不支持的属性: align-content,flex-basis,order,flex-flow,flex-shrink。
其他的就给一张图参考下吧
三. navigation 导航器
1. 相关依赖安装
进入当前初始化好的react-native项目,我们首先得安装react-navigation,以及navigation所依赖的第三方库,并将其关联至react-native。这边我是通过yarn包管理器进行安装的:
yarn add react-navigation
yarn add react-native-gesture-handler
react-native link react-native-gesture-handler
// 我这里ReactNative版本是0.6x的,所以最后一步link操作略不同,如下所示:
cd ios
pod install
cd..
2. 路由创建及切换
在ReactNative中使用createStackNavigator()来配置路由,这个方法接收一个路由对象参数。假设我们对Home唯一的路由配置是页面组件,我们不需要使用{screen:HomeScreen}配置格式,可以直接使用页面组件。通过initialRouteName我们可以设置默认路由。而createAppContainer()这个函数返回的是一个React组件,并将createStackNavigator创建的 React 组件 作为参数,可以直接从App.js 导出,用作我们应用程序的根组件。
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
const AppNavigator = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
},
);
export default createAppContainer(AppNavigator);
路由间的切换使用this.props.navigation.navigate('XXX'),如下所示:
<Button
title="跳转详情页"
onPress={() => this.props.navigation.navigate('Details')}
/>
- this.props.navigation:navigation通过prop 传递给每个在 stack navigator 中定义的屏幕组件。
- navigate('Details'):navigator()里面所传参数就是用户定义的路由名,支持第二个参数作为跳转路由携带的参数。
- this.props.navigation.getParam(): 通过这个方法可以读取参数。
点击跳转至与当前所处路由相同,参数不同的业务场景:
因为当前机制识别跳转路由与当前路由相同时,不会做任何操作,我们需要使用push来进行实现。
this.props.navigation.push('Details', {
itemId: Math.floor(Math.random() * 100),
})
3. 导航头
导航头Bar配置
通过navigationOptions这个静态属性对其进行配置,可以返回一个静态对象,也可以通过返回方法动态实现。
- 静态方式
static navigationOptions = {
title: 'Home',
};
- 动态方式
static navigationOptions = ({navigation}) => {
return {
title: navigation.getParam('otherParam', 'zwzwzw'),
};
};
render() {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Home Screen</Text>
<Button
title="点击修改title"
onPress={() => {
this.props.navigation.setParams({otherParam: '帅爆了!'});
}}
/>
</View>
);
}
头部样式:
- 全部路由共享的默认样式
const AppNavigator = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
defaultNavigationOptions: {
headerStyle: {
backgroundColor: '#f4511e', // header外层view的样式,这里设置的为bar的背景色
},
headerTintColor: '#fff', // 返回按钮和标题都使用这个属性作为它们的颜色
headerTitleStyle: {
fontWeight: 'bold', // 如果我们想为标题定制fontFamily,fontWeight和其他Text样式属性,我们可以用它来完成。
},
},
},
);
- 覆盖默认样式
static navigationOptions = ({navigation, navigationOptions}) => {
const {params} = navigation.state;
return {
title: params ? params.otherParam : 'detail页面',
headerStyle: {
backgroundColor: navigationOptions.headerTintColor,
},
headerTintColor: navigationOptions.headerStyle.backgroundColor,
};
};
- 使用自定义样式(参考官方文档案例,引用图片组件)
class LogoTitle extends React.Component {
render() {
return (
<Image
source={require('./spiro.png')}
style={{ width: 30, height: 30 }}
/>
);
}
}
class HomeScreen extends React.Component {
static navigationOptions = {
// headerTitle instead of title
headerTitle: () => <LogoTitle />,
};
}
- 标题按钮
IOS 上的后退按钮使用的标题字符串, 或 null 禁用标签。 默认为上一个场景的 headerTitle
从下图可以发现返回按钮为上一个页面的title,所以我们得对其覆盖。
StackNavigator({
A: {
screen: AScreen,
navigationOptions: () => ({
title: `zwzwzw`,
headerBackTitle: null, //对其重写或自定义
}),
},
B: {
screen: BScreen,
navigationOptions: () => ({
title: `anything you want here`,
}),
},
});
至于头与页面之间的交互可以参考官方文档计数器案例。
modal堆栈
我理解的modal堆栈就是重新使用createStackNavigator()方法创建一个新的stackNavigator,然后将之前的页面stackNavigator嵌套进去,如下所示:
const RootStack = createStackNavigator(
{
Main: {
screen: MainStack,
},
MyModal: {
screen: ModalScreen,
},
},
{
mode: 'modal', // modal的进入样式,ios默认为modal,由下而上,card则为左右切换样式。
headerMode: 'none', // 头部样式,这样写的话是全屏模式。
}
);
modal的样式很像苹果手机的激活提示,由下而上弹出请激活。
列表组件
1.FlatList
这是一个简单的高性能列表组件,直接上个简单的例子,熟悉一些基础的组件属性:
const CITY_NAME = ['益阳', '株洲', '长沙', '湘潭', '宁乡'];
class DetailsScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: CITY_NAME,
};
}
static navigationOptions = ({navigation, navigationOptions}) => {
const {params} = navigation.state;
return {
title: params ? params.otherParam : 'detail页面',
headerStyle: {
backgroundColor: navigationOptions.headerTintColor,
},
headerTintColor: navigationOptions.headerStyle.backgroundColor,
};
};
_renderItem(data) {
return (
<View style={styles.item}>
<Text style={styles.text}>{data.item}</Text>
</View>
);
}
loadData(flag) {
if (flag) {
this.setState({
loading: true,
});
}
setTimeout(() => {
let arr = [];
if (flag) {
for (let i = this.state.data.length - 1; i >= 0; i--) {
arr.push(this.state.data[i]);
}
} else {
arr = this.state.data.concat(CITY_NAME);
}
this.setState({
data: arr,
loading: false,
});
}, 2000);
}
genIndicator() {
return (
<View style={styles.indicatorContainer}>
<ActivityIndicator
style={styles.indicator}
size={'large'}
color={'red'}
animating={true}
/>
<Text>正在加载更多...</Text>
</View>
);
}
render() {
const {navigation} = this.props;
return (
<View style={{flex: 1}}>
<FlatList
data={this.state.data}
renderItem={data => this._renderItem(data)}
refreshControl={ //下拉刷新
<RefreshControl
title={'加载中...'}
tintColor={'orange'} // 苹果专属
refreshing={this.state.loading}
onRefresh={() => { //刷新状态控制
this.loadData(true);
}}
/>
}
ListFooterComponent={() => this.genIndicator()} //底部加载更多样式实现
onEndReached={() => this.loadData()} //触底后进行的操作
/>
</View>
);
}
}
基本样式
2. SectionList
sectionList的使用方式跟FlatList差不多,区别在于接受的数据源的属性以及数据源的类型不同。
- sectionList的数据源实例
const CITY_NAME = [
{data: ['益阳', '株洲', '长沙', '湘潭', '宁乡'], title: '湖南'},
{data: ['虎门', '广州', '河源'], title: '广东'},
];
- 接收数据源的属性
sections={this.state.data}
- title渲染属性
renderSectionHeader={data => this._renderHeader(data)} // 组标题渲染
// 以下为方法
_renderHeader({section}) {
return (
<View style={styles.sectionHeader}>
<Text style={styles.sectionText}>{section.title}</Text>
</View>
);
}
- 分割线属性
ItemSeparatorComponent={() => <View style={styles.separator} />} // 分割线样式
// 样式设置
separator: {
height: 1,
backgroundColor: 'gray',
flex: 1,
},
下面是粗糙成品(有点丑哈哈哈)
本来研究下了swipeableList的,不过0.61的react-native库源码中没有相关引入,只能空闲时候研究下原因然后下次笔记补上~