table of Contents
Previous describes how to integrate existing React Native iOS project. Expand under this one we put on a do a demo, click Add a movie to jump to the details page. React Native page jump using the recommended third-party navigation controls: REACT-Navigation
Integrated react-navigation
- According to official guidelines , the terminal cd to the project root directory, enter the following command to integrate:
npm install --save react-native-navigation
npm install --save react-native-gesture-handler
react-native link react-native-gesture-handler
- In iOS project, open Podfile file, add RCTLinkingIOS:
pod 'React', :path => '../node_modules/react-native', :subspecs => [
. . . // other subspecs
'RCTLinkingIOS',
. . .
]
Then execute the following command to install
pod install
At this point, react-navigation integrated product.
Use react-navigation
- Refer to the official use of the document , create Navigator.js file in the root directory, edit the content as follows:
import React from "react";
import { createStackNavigator, createAppContainer } from 'react-navigation'
import HotMovie from './src/page/HotMovie';
import MovieDetail from './src/page/MovieDetail'
const AppNavigator = createStackNavigator(
{
Home: HotMovie,
Details: MovieDetail
},
{
initialRouteName: "Home"
}
)
const AppContainer = createAppContainer(AppNavigator);
export default class Navigator extends React.Component {
render() {
return <AppContainer />;
}
}
HotMovie which is on a list of movies created, MovieDetail for the new movie details page, as specified in the next step
- Creating MovieDetail.js file, the path is ./src/page/MovieDetail.js, edit the following:
import React,{Component} from 'react';
import {StyleSheet,Image,Text,View} from 'react-native';
export default class MovieDetail extends Component<Props>{
constructor(props){
super(props)
const { navigation } = props
const itemId = navigation.getParam('itemId', 'NO-ID')
const cover = navigation.getParam('cover')
this.state = {
detail:null,
cover:cover,
itemId:itemId
}
this.fetchData = this.fetchData.bind(this)
}
componentDidMount(){
const requrest_url = "https://movie.douban.com/j/subject_abstract?subject_id="+this.state.itemId
this.fetchData(requrest_url)
}
fetchData(requrest_url){
fetch(requrest_url)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
detail:responseJson.subject
});
})
}
render(){
if (!this.state.detail) {
return this.renderLoadingView();
}
const data = this.state.detail
const state = this.state
return(
<View>
<Text style={{fontSize:32,fontWeight:"400",padding:10}}>{data.title}</Text>
<View style={styles.detailView}>
<Image style={styles.thumbnail} source={{url:state.cover}}></Image>
<View style={styles.rightDetai}>
<Text>导演: {data.directors.join('/')}</Text>
<Text>评分:{data.rate}</Text>
<Text>时长:{data.duration}</Text>
<Text>类型:{this.state.detail.types.join('/')}</Text>
<Text>主演:{this.getDetaiActor()}</Text>
</View>
</View>
</View>
)
}
renderLoadingView(){
return (
<View style={styles.container}>
<Text>
正在加载...
</Text>
</View>
)
}
getDetaiActor(){
return this.state.detail.actors.slice(0,5).join('/')+' 等'
}
}
const styles = StyleSheet.create({
container: {
flex:1,
flexDirection:'column',
alignItems:'center',
justifyContent: 'center',
alignItems: 'center',
height:300
},
detailView: {
flexDirection:'row',
justifyContent: 'flex-start',
height:200,
paddingLeft:20,
paddingTop:10,
paddingRight:10,
},
thumbnail:{
width:79.5,
height:121.5,
},
rightDetai:{
flexDirection:'column',
height:200,
marginLeft:10
}
});
- Index.js file amended as follows:
import React from 'react';
import { AppRegistry } from 'react-native';
import HotMovie from './src/page/HotMovie';
import MovieDetail from './src/page/MovieDetail'
import Navigator from './Navigator';
AppRegistry.registerComponent('Navigator', () => Navigator);
AppRegistry.registerComponent('HotMovie', () => HotMovie);
AppRegistry.registerComponent('MovieDetail', () => MovieDetail);
- In iOS project, jump ViewController.m file to read as follows:
#import "ViewController.h"
#import <React/RCTRootView.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 200, 50)];
button.center = self.view.center;
[button setTitle:@"跳转RN" forState:0];
[button setTitleColor:[UIColor greenColor] forState:0];
[button addTarget:self action:@selector(clickButton:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
- (void)clickButton:(UIButton*)button{
NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];
RCTRootView *rootView =
[[RCTRootView alloc] initWithBundleURL: jsCodeLocation
moduleName: @"Navigator"
initialProperties: nil
launchOptions: nil];
UIViewController *vc = [[UIViewController alloc] init];
vc.view = rootView;
[self presentViewController:vc animated:YES completion:nil];
}
@end
- Add the click event in HotMovie.js, HotMovie.js complete code is as follows:
import React, { Component } from 'react';
import {StyleSheet, Image, Text, View, FlatList,TouchableOpacity} from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation'
var REQUEST_URL = "https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0"
export default class HotMovie extends Component<Props> {
_onItemClick(item) {
this.props.navigation.navigate('Details',{itemId:item.id,cover:item.cover,title:item.title})
}
constructor(props){
super(props);
this.state = {
movies:null,
}
this.renderMovie = this.renderMovie.bind(this)
this.fetchData = this.fetchData.bind(this)
}
componentDidMount(){
this.fetchData()
}
fetchData(){
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
movies:responseJson.subjects
});
})
}
render() {
if (!this.state.movies) {
return this.renderLoadingView();
}
return (
<FlatList
data={this.state.movies}
renderItem={this.renderMovie}
style={styles.list}
keyExtractor={item => item.id}
/>
);
}
renderLoadingView(){
return (
<View style={styles.container}>
<Text>
正在加载...
</Text>
</View>
)
}
renderMovie({item}){
return(
<TouchableOpacity style={styles.item} onPress={() => this._onItemClick(item)}>
<Image source={{url:item.cover}} style={styles.thumbnail}/>
<View style={styles.itemRight}>
<Text>{item.title}</Text>
<Text>{item.rate}</Text>
</View>
</TouchableOpacity>
)
}
}
const styles = StyleSheet.create({
container: {
flex:1,
flexDirection:'row',
alignItems:'center',
justifyContent: 'center',
alignItems: 'center',
},
item:{
marginTop:1,
flexDirection:'row',
alignItems:'center',
justifyContent: 'flex-start',
height:100,
backgroundColor:'lightgray',
paddingLeft:10
},
thumbnail:{
width:53,
height:81,
backgroundColor:'lightgray'
},
itemRight:{
height:100,
justifyContent: 'center',
alignItems:'center',
paddingLeft:10
},
list: {
backgroundColor: "#F5FCFF"
}
});
Which this.props.navigation.navigate('Details')
is the navigation Skip react-navigation method, but this method can not jump the same page (will not effect), if you want to repeatedly push the same page, you need to read:
this.props.navigation.push('Details')
Navigate back then:
this.props.navigation.goBack()
- Settings Navigation title
Depending on the demand, we look at the official Example:
- If the title is fixed, the definition of a property called the static navigationOptions, return an object configuration, such as:
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
};
/* render function, etc */
}
- If the parameters need to obtain from the top, the code such as:
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('otherParam', 'A Nested Details Screen'),
};
};
/* render function, etc */
}
- If you want to change the title, the code such as:
<Button
title="Update the title"
onPress={() => this.props.navigation.setParams({otherParam: 'Updated!'})}
/>
- If you need to modify the style, such as the code ::
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
};
/* render function, etc */
}
- These are just set up a home page navigation bar style, we hope that the global settings, then straight back to the top of createStackNavigator Code, amendment:
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
/* The header config from HomeScreen is now here */
defaultNavigationOptions: {
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
},
}
);
- Sometimes, we want to change the title of custom controls, such as buttons or display pictures, we can:
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 />,
};
/* render function, etc */
}
Returning to our example of the demo, we want the background color values of the entire App navigation column is # f4511e, the text is white, so the unified configuration in Navigator.js, Navigator.js complete code is as follows:
import React from "react";
import { createStackNavigator, createAppContainer } from 'react-navigation'
import HotMovie from './src/page/HotMovie';
import MovieDetail from './src/page/MovieDetail'
const AppNavigator = createStackNavigator(
{
Home: HotMovie,
Details: MovieDetail
},
{
defaultNavigationOptions: {
headerTintColor: '#fff',
headerStyle: {
backgroundColor: '#f4511e',
},
headerTitleStyle: {
fontWeight: 'bold',
},
},
navigationOptions: {
tabBarLabel: 'Home!',
},
}
)
const AppContainer = createAppContainer(AppNavigator);
export default class Navigator extends React.Component {
render() {
return <AppContainer />;
}
}
Home (movie list) navigation bar for the specified title picture movie.png (corresponding to the path: Project root directory /src/images/movie.png), so as to modify HotMovie.js:
import React, { Component } from 'react';
import {StyleSheet, Image, Text, View, FlatList,TouchableOpacity} from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation'
var REQUEST_URL = "https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0"
class LogoTitle extends React.Component {
render() {
return (
<Image
source={require('../image/movie.png')}
style={{ width: 30, height: 30 }}
/>
);
}
}
export default class HotMovie extends Component<Props> {
static navigationOptions = {
headerTitle: <LogoTitle />,
};
//....省略代码
}
const styles = StyleSheet.create({
//...省略代码
});
In the movie details page, we set the title according to the previous screen name parameter passed to the movie, the film details the default value:
import React,{Component} from 'react';
import {StyleSheet,Image,Text,View} from 'react-native';
export default class MovieDetail extends Component<Props>{
static navigationOptions = ({ navigation }) => {
return {
title:navigation.getParam('title','电影详情')
}
}
//...省略代码
}
const styles = StyleSheet.create({
//...省略代码
});
The complete source code: https://github.com/dolacmeng/RNProject/tree/master
operating results: