React Native APP結構探索


APP結構探索

我在Github上找到了一個有登陸界面,能從網上獲取新聞信息的開源APP,想來研究一下APP的結構。

附上原網址:我的第一個React Native App

具體來講,就是研究一個復雜功能的APP在編寫時是如何一步一步展開的,包括APP內部邏輯、與UI交互、與服務器交互等。

index.android.js

首先,我找到了index.android.js文件。文件很短,內容如下:

/**
 * News
 * author : lufeng
 */

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

var Route = require("./web_modules/route");

AppRegistry.registerComponent('News', () => Route);

可以看到,關鍵代碼只有從"./web_modules/route"調用的Route,這也是整個程序的入口。

route.js

順藤摸瓜找到了route.js,代碼比之前長了一點,如下:

/*
 * 頁面路由
 */
import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  BackAndroid,
  Navigator,
  Image,
  Text,
  View,
  StatusBar
} from 'react-native';

var Tab = require("./tab");
var _navigator;

var Routes = React.createClass({

	configureScence: function(){
		return Navigator.SceneConfigs.FloatFromRight;
	},
	renderScene: function(route, navigator){
		_navigator = navigator;
		let Component = route.component;
		return <Component route={route} navigator={navigator}/>
	},
	render: function(){
		var renderScene = this.renderSceneAndroid;
		var configureScence = this.configureScenceAndroid;
		return (
			<Navigator
				initialRoute={{ name: '主頁', component:Tab }}
				configureScene={ this.configureScence }
				renderScene={ this.renderScene}
			/>
		);
	}
});

//監聽硬件的back鍵操作
BackAndroid.addEventListener('hardwareBackPress', function() {
	if(_navigator == null){
		return false;
	}
	if(_navigator.getCurrentRoutes().length === 1){
		return false;
	}
	_navigator.pop();
	return true;
});

module.exports = Routes;

route.js文件里的結構仍然很清晰,主要有三部分:

  • 注冊了名為Routes的組件。
  • 監聽back鍵操作並進行相應處理。
  • 導出Routes

React 允許將代碼封裝成組件(component),然后像插入普通 HTML 標簽一樣,在網頁中插入這個組件。React.createClass 方法就用於生成一個組件類。

這里涉及到Navigator的一些知識:

Navigator即導航器,通過導航器我們可以實現應用在不同的頁面之間進行跳轉。 
導航器會建立一個路由棧,用來彈出,推入或者替換路由狀態。該路由棧相當於Android原生中使用的任務棧

renderScene

renderScene方法就相當於我們使用的startActivity方法了,我們可以在該方法中設置需要渲染的場景(跳轉的頁面),該方法接收兩個參數(必要參數),routenavigator,其中route就是路由的頁面,navigator是一個Navigator對象,因為Navigator對象擁有poppushjump等方法,我們需要導航器對象來實現頁面的跳轉。而路由route需要我們提前進行配置。

configureScene

該方法用來設置指定路由對象的配置信息,從而改變場景的動畫或者手勢。如:

configureScene={(route) => {
      //跳轉的動畫
      return Navigator.SceneConfigs.VerticalDownSwipeJump;
}}

initialRoute

用來設置默認頁面,也就是啟動APP看到的第一個頁面,需要兩個參數,namecomponent

可以看到,這里設置的默認頁面來自Tab。而Tab來自"./tab",我們打開tab.js重頭戲好像來了!!因為我看到了很多寫頁面的代碼。。。

tab.js

先貼代碼:

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Image,
  Text,
  View,
  StatusBar
} from 'react-native';

import TabNavigator from 'react-native-tab-navigator'; //引入tabbar支持包  
  
const TabNavigatorItem =TabNavigator.Item;  
const TAB_ITEM = [{
	code : 'Home',
	name : '首頁',
	icon_n : require('./images/tab/tab_messagecenter_n.png'),
	icon_p : require('./images/tab/tab_messagecenter_p.png'),
	contentView : require('./tab_home')
},{
	code : 'Suggest',
	name : '推薦',
	icon_n : require('./images/tab/tab_contact_n.png'),
	icon_p : require('./images/tab/tab_contact_p.png'),
	contentView : require('./tab_suggest')
},{
	code : 'Find',
	name : '發現',
	icon_n : require('./images/tab/tab_discovery_n.png'),
	icon_p : require('./images/tab/tab_discovery_p.png'),
	contentView :  require('./tab_find')
},{
	code : 'Mine',
	name : '我的',
	icon_n : require('./images/tab/tab_myself_n.png'),
	icon_p : require('./images/tab/tab_myself_p.png'),
	contentView :  require('./tab_mine')
}];

class Tab extends Component {  
  
	constructor(props){  
		super(props);  
		this.state = {  
			items : TAB_ITEM,
			selectedTab : TAB_ITEM[0].code
		}  
	}  
  
	/*
	 * tab點擊方法 
	 */  
	onPress(tabCode){  
		if(tabCode){  
			this.setState({  
				selectedTab : tabCode
			});  
		}  
	}  
	
    /*
     *渲染每項 
     */  
	renderTabView(options){  
		var tabNomal = options.icon_n;  
		var tabPress = options.icon_p;  
 
		return(  
			<TabNavigatorItem  
				key={options.code} 
				title={options.name}  
				renderIcon={()=><Image style={styles.tabIcon} source={tabNomal}/>}  
				renderSelectedIcon={()=><Image style={styles.tabIcon} source={tabPress}/>}  
				selected={this.state.selectedTab === options.code}  
				selectedTitleStyle={{color:'#333333'}}  
				onPress={()=>this.onPress(options.code)}  
				renderBadge= {()=>options.badgeNum?<View style={styles.badgeView}>
											<Text style={styles.badgeText}>options.badgeNum</Text>
										  </View>:null}>  
				<options.contentView route={this.props.route} navigator={this.props.navigator}/>
			</TabNavigatorItem>  
		);  
	}  
    
	render() {  
	
		var items = [];
        for (var i=0; i< this.state.items.length; i++) {
            items.push(this.renderTabView(this.state.items[i]));
        }
		return (  
			<View style={styles.container}>  
				<TabNavigator tabBarStyle={styles.tab}>  
					{items}
				</TabNavigator>  
			</View>  
		);  
	}  
}  
  
const styles = StyleSheet.create({  
  container: {  
    flex: 1,  
    backgroundColor: '#F5FCFF',  
  },    
  tab:{  
    height: 55,  
    alignItems:'center',  
    backgroundColor:'#f4f5f6',  
  },  
  tabIcon:{  
    width:25,  
    height:25,  
  },  
  badgeView:{  
    width:22,  
    height:14 ,  
    backgroundColor:'#f85959',  
    borderWidth:1,  
    marginLeft:10,  
    marginTop:3,  
    borderColor:'#FFF',  
    alignItems:'center',  
    justifyContent:'center',  
    borderRadius:8,  
  },  
  badgeText:{  
    color:'#fff',  
    fontSize:8,  
  }  
});  

module.exports = Tab;

這里看的比較費力。。先是創建了一個名為tab的類,然后將界面底部的所有項的信息作為TAB_ITEM傳到tabconstructor中。接着是onPress()方法作為tab的點擊方法,后面的renderTabView方法的注釋中標明了是渲染每項,其中又調用了TabNavigatorItem組件,這個組件來自Github。最后的render()里就是加載了整個布局。

TabNavigator

Tab組件(底部導航):react-native-tab-navigator

https://github.com/exponentjs/react-native-tab-navigator

TAB_ITEM

這里以tab_home.js為例,其他的類似。核心代碼如下:

class Tab_Home extends Component { 
	
	constructor(props){  
		super(props);  
	}  
	
	showActionSheet(){
		this.ActionSheet.show();
	}
	
	render() {
		return (
			<View style={{flex:1,justifyContent:'flex-start',alignItems:'center', bottom : 5}}>  
				<View style={styles.header}>  
					<View style={styles.header_btn}></View>
					<View style={styles.header_center}>
						<Text style={styles.header_title}>新聞網</Text>
					</View>
					<TouchableOpacity  onPress={this.showActionSheet.bind(this)}>
						<Image source={require('./images/header/more.png')} style={styles.header_icon,styles.header_btn}/>  
					</TouchableOpacity>
				</View>
				<Swiper style={styles.wrapper} showsButtons={false} autoplay={false} height={200} showsPagination={true}>
					<Image style={styles.slide} source={ require('./images/demo/slideshow1.jpg') }></Image>
					<Image style={styles.slide} source={ require('./images/demo/slideshow2.jpg') }></Image>
					<Image style={styles.slide} source={ require('./images/demo/slideshow3.jpg') }></Image>
					<Image style={styles.slide} source={ require('./images/demo/slideshow4.jpg') }></Image>
					<Image style={styles.slide} source={ require('./images/demo/slideshow5.jpg') }></Image>
				</Swiper>
				<List dataNums="6" route={this.props.route} navigator={this.props.navigator}/>
				<ActionSheet 
                    ref={(o) => this.ActionSheet = o}
                    title="進入新聞推薦分類!"
                    options={buttons}
                    cancelButtonIndex={0}
                    destructiveButtonIndex={1}
                />
			</View>   
		);
	}
}

這個類主要是首頁的布局,涉及到多種組件。其中比較值得一提的是TouchableOpacitySwiperActionSheet

TouchableOpacity

本組件用於封裝視圖,使其可以正確響應觸摸操作。當按下的時候,封裝的視圖的不透明度會降低。這個過程並不會真正改變視圖層級,大部分情況下很容易添加到應用中而不會帶來一些奇怪的副作用。(譯注:此組件與TouchableHighlight的區別在於並沒有額外的顏色變化,更適於一般場景)

這里此組件的onPress()事件的處理是彈出ActionSheet菜單。

Swiper

用於組件(常見的是圖片)的輪播。

官方文檔:https://github.com/leecade/react-native-swiper

ActionSheet

從頁面底部彈出菜單,擁有標題等屬性,常用於應用的退出。本例是選擇欄目用。(雖然沒有實現具體的功能)

官方文檔:https://github.com/beefe/react-native-actionsheet

今天就先到這啦。明天繼續看~~

感謝以下幾篇博客:

我的第一個React Native App

Navigator

ReactNative頁面跳轉Navigator

React入門實例教程

TouchableOpacity


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM