2018/5/30
2019/05/05 (重新整理)
https://snack.expo.io/ 是個不錯的起點,先下載expo到你的手機上,接下來在https://snack.expo.io/寫的程式碼,就可以直接在你的手機上看成果了 (詳參: Snack — A Playground for React Native)。
打開https://snack.expo.io/就會有一個範例程式檔 App.js:
import React, { Component } from 'react';import { Text, View, StyleSheet } from 'react-native';import { Constants } from 'expo';// You can import from local filesimport AssetExample from './components/AssetExample';// or any pure javascript modules available in npmimport { Card } from 'react-native-elements'; // Version can be specified in package.jsonexport default class App extends Component { render() { return ( <View style={styles.container}> <Text style={styles.paragraph}> Change code in the editor and watch it change on your phone! Save to get a shareable url. </Text> <Card title="Local Modules"> <AssetExample /> </Card> </View> ); }}const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', paddingTop: Constants.statusBarHeight, backgroundColor: '#ecf0f1', }, paragraph: { margin: 24, fontSize: 18, fontWeight: 'bold', textAlign: 'center', color: '#34495e', },});在https://snack.expo.io/中,並不需要
AppRegistry.registerComponent('testapp', () => ShowView);首先,先安裝react native tools
要安裝node.js,安裝後,根據React Native Getting Started,如果已經安裝了Android Studio或XCode,可以利用React Native CLI:
npm install -g react-native-cli但是,如果是還沒有安裝Android Studio或XCode:
npm install -g expo-cli以下範例是以expo為例。
就像使用create-react-app或create-react-native-app一樣,也可以利用expo init產生一個空白的專案:
expo init test-rnexpo init會產生一些設定檔,以及一個App.js,
import React from 'react';import { StyleSheet, Text, View } from 'react-native';export default class App extends React.Component { render() { return ( <View style={styles.container}> <Text>Open up App.js to start working on your app!</Text> </View> ); }}const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', },});要執行這個專案的話
cd test-rnnpm start就可以啟動expo的DevTools,DevTools會啟動瀏覽器http://localhost:19002/,讓我們可以利用安裝好的模擬器或利用expo提供的app測試我們寫好的app。
我們先參考 ReactNative開發入門教學(1)-HelloWorld 來做一些改變:
import React, { Component } from 'react';import { Text, View, StyleSheet } from 'react-native';export default class App extends Component { render() { return ( <View style={styles.container}> <Text style={styles.welcome}>Hello World!</Text> </View> ); }}const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, }});就會在手機上看到Hello World。
比起寫一個Android App或iOS App來說,這樣的程式其實是相當簡潔。
參考 ReactNative開發入門教學(2)-觸發事件 再來做一些改變,首先,將App.js改為:
import React, { Component } from 'react';import App from './src/app';export default class Main extends Component { render() { return ( <App /> ); }}因為在snack.expo.io中,不使用AppRegistry,而是直接使用App.js。
接下來產生一個src目錄,並且新增一個app.js,就如同範例的內容一樣。(src/app.js)
import React, { Component } from 'react';import { Text, View, TouchableHighlight, Button} from 'react-native';class App extends Component { constructor(props) { super(props); this.state = {}; } _click() { alert('Clicked!'); } render() { return( <View> <Button title="Try it!" onPress={this._click.bind(this)}/> <TouchableHighlight onPress={this._click.bind(this)}> <Text>HelloWorld!</Text> </TouchableHighlight> </View> ); }}export default App;把前一個範例中的StyleSheet加進來,會看起來好看一點:
import React, { Component } from 'react';import { Text, View, TouchableHighlight, Button, StyleSheet} from 'react-native';class App extends Component { constructor(props) { super(props); this.state = {}; } _click() { alert('Clicked!'); } render() { return( <View style={styles.container}> <Button title="Try it!" onPress={this._click.bind(this)}/> <TouchableHighlight onPress={this._click.bind(this)}> <Text>HelloWorld!</Text> </TouchableHighlight> </View> ); }}const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }});export default App;程式改完之後,會自動reload。
這個範例用到兩個元件:
最好要把程式碼做一些基本的切割,例如,將HomeScreen 及 DetailsScreen切成兩個檔案放在src路徑下,App.js會改成:
// 2019/05/04 revised for react navigation 3.x // https://reactnavigation.org/docs/en/tab-based-navigation.htmlimport React from 'react';import { createBottomTabNavigator, createAppContainer } from 'react-navigation';import HomeScreen from './src/home';import DetailsScreen from './src/details';const TabNavigator = createBottomTabNavigator({ Home: HomeScreen, Details: DetailsScreen,});export default createAppContainer(TabNavigator);src/home.js
import React from 'react';import { View, Text, Button } from 'react-native';class HomeScreen extends React.Component { render() { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button title="Go to Details" onPress={() => this.props.navigation.navigate('Details')} /> </View> ); }}export default HomeScreen;src/details.js
import React from 'react';import { View, Text, Button } from 'react-native';class DetailsScreen extends React.Component { render() { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Button title="Go back" onPress={() => this.props.navigation.goBack()} /> </View> ); }}export default DetailsScreen;**注意** 在exop.io會自動去下載用到的package,如果是使用vs code,就要手動安裝,先利用ctrl-C把npm停下來,執行
npm install react-navigationnpm startimport React from 'react';import { StyleSheet, View, Text, FlatList } from 'react-native';export default class FlatListScreen extends React.Component { render() { return ( <View style={styles.container}> <FlatList data={[ {key: 'Devin'}, {key: 'Jackson'}, {key: 'James'}, {key: 'Joel'}, {key: 'John'}, {key: 'Jillian'}, {key: 'Jimmy'}, {key: 'Julie'}, ]} renderItem={({item}) => <Text style={styles.item}>{item.key}</Text>} /> </View>); }}const styles = StyleSheet.create({ container: { flex: 1, paddingTop: 22 }, item: { padding: 10, fontSize: 18, height: 44, }, })App.js加入FlatListScreen:
// revised for react navigation 3.x// https://reactnavigation.org/docs/en/tab-based-navigation.htmlimport React from 'react';//import { TabNavigator } from 'react-navigation';import { createBottomTabNavigator, createAppContainer } from 'react-navigation';import HomeScreen from './src/home';import DetailsScreen from './src/details';import FlatListScreen from "./src/FlatListScreen";const TabNavigator = createBottomTabNavigator({ Home: HomeScreen, Details: DetailsScreen, "Flat List": FlatListScreen});export default createAppContainer(TabNavigator);react native elements提供的ListItem比FlatList、SectionList還好用,提供了不少的功能,如:avatar、icon、onPress,也可以跟FlatList合併使用。
src/listitemdemo.js
import React from 'react';import { View, Alert } from 'react-native';import { ListItem } from 'react-native-elements';//https://github.com/react-native-training/react-native-elements/issues/349const list = [ { title: 'Appointments', info: 'more info about Appointments', icon: 'av-timer', }, { title: 'Trips', info: 'more info about Trips', icon: 'flight-takeoff', },];export default class ListItemDemo extends React.Component { _onPressButton(item) { Alert.alert(item.info); } render() { return ( <View> {list.map((item, i) => ( <ListItem key={i} title={item.title} leftIcon={{ name: item.icon }} onPress={() => this._onPressButton(item)} /> ))} </View> ); }}src/listitemdemo2.js
import React from 'react';import { View} from 'react-native';import { ListItem } from 'react-native-elements';//https://react-native-training.github.io/react-native-elements/docs/listitem.htmlconst list = [ { name: 'Amy Farha', avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/ladylexy/128.jpg', subtitle: 'Vice President', }, { name: 'Chris Jackson', avatar_url: 'https://s3.amazonaws.com/uifaces/faces/twitter/adhamdannaway/128.jpg', subtitle: 'Vice Chairman', },];export default class ListItemDemo2 extends React.Component { render() { return ( <View> {list.map((l, i) => ( <ListItem key={i} roundAvatar //this is the correct way: leftAvatar={{ source: { uri: l.avatar_url } }} //avatar={{ uri: l.avatar_url }} title={l.name} subtitle={l.subtitle} /> ))} </View> ); }}app.js
// revised for react navigation 3.x// https://reactnavigation.org/docs/en/tab-based-navigation.htmlimport React from 'react';//import { TabNavigator } from 'react-navigation';import { createBottomTabNavigator, createAppContainer } from 'react-navigation';import HomeScreen from './src/home';import DetailsScreen from './src/details';import FlatListScreen from "./src/FlatListScreen";import ListItemDemo from "./src/listitemdemo";import ListItemDemo2 from "./src/listitemdemo2";const TabNavigator = createBottomTabNavigator({ Home: HomeScreen, Details: DetailsScreen, "Flat List": FlatListScreen, "ListItem Demo": ListItemDemo, "ListItem Demo 2": ListItemDemo2});export default createAppContainer(TabNavigator);import React from 'react';import { FlatList, ActivityIndicator, Text, View } from 'react-native';export default class MovieScreen extends React.Component { constructor(props){ super(props); this.state ={ isLoading: true} } componentDidMount(){ return fetch('https://facebook.github.io/react-native/movies.json') .then((response) => response.json()) .then((responseJson) => { this.setState({ isLoading: false, dataSource: responseJson.movies, }, function(){ }); }) .catch((error) =>{ console.error(error); }); } render(){ //如果還沒完成,出現轉圈圈的AcitivityIndicator if(this.state.isLoading){ return( <View style={{flex: 1, padding: 20}}> <ActivityIndicator/> </View> ) } return( <View style={{flex: 1, paddingTop:20}}> <FlatList data={this.state.dataSource} renderItem={({item}) => <Text>{item.title}, {item.releaseYear}</Text>} keyExtractor={({id}, index) => id} /> </View> ); }}跟前面的範例整合起來:
// revised for react navigation 3.x// https://reactnavigation.org/docs/en/tab-based-navigation.htmlimport React from 'react';//import { TabNavigator } from 'react-navigation';import { createBottomTabNavigator, createAppContainer } from 'react-navigation';//import HomeScreen from './src/home';//import DetailsScreen from './src/details';import FlatListScreen from "./src/FlatListScreen";import ListItemDemo from "./src/listitemdemo";import ListItemDemo2 from "./src/listitemdemo2";import MovieScreen from "./src/movie";const TabNavigator = createBottomTabNavigator({ "Flat List": FlatListScreen, "ListItem Demo": ListItemDemo, "ListItem Demo 2": ListItemDemo2, Movie:MovieScreen});export default createAppContainer(TabNavigator);