一、 首先配置環境 當然是node 下用npm
npm install -g react-native-cli
然後創建項目
react-native init react1
cd react1
react-native run-android
新開一個cmd 啓動項目
react-native start
在電腦上啓動的安卓虛擬機 不能搖一搖,所以還需要在 cmd 裏輸入
adb shell input keyevent 82
或者
adb -s emulator-5554 shell input keyevent 82
在筆記本下啓動的虛擬機會比較卡可以設置如下,會稍微好點
二、需要實現的界面和功能如下
新建一個AppNavigator.js 文件 用於首頁和詳情頁的跳轉
'use strict'
import React, { Component } from 'react';
import { StyleSheet, Navigator } from 'react-native';
import ViewContainer from '../views/indexView';
import DetailContainer from '../views/Detail';
class AppNavigator extends Component {
_renderScene(route, navigator) {
let globalNavigatorProps = { navigator };
switch(route.ident){
case 'indexView':
return(
<ViewContainer {...globalNavigatorProps} />
)
case 'detail':
return(
<DetailContainer {...globalNavigatorProps} />
)
default:
return(
<ViewContainer {...globalNavigatorProps} />
)
}
}
render() {
return (
<Navigator initialRoute={this.props.initialRoute}
ref="AppNavigator"
renderScene={this._renderScene}/>
);
}
}
module.exports = AppNavigator;
index.android.js 首先展示首頁
'use strict'
import React, { Component } from 'react';
import { AppRegistry, StatusBar } from 'react-native';
import AppNavigator from './app/common/AppNavigator';
class react1 extends Component {
render() {
this._setStatusBar();
return (
<AppNavigator
initialRoute={{ident: 'indexView'}}/>
);
}
//狀態欄的顏色
_setStatusBar() {
StatusBar.setBackgroundColor('#af3329', true);
}
}
AppRegistry.registerComponent('react1', () => react1);
reactjs 寫樣式和傳統的css 有一定的區別,駝峯和沒有簡寫如(margin: 0 auto) 是沒有的,同時安卓機下是不能顯示出陰影的
首頁中的 卡片佈局如下
'use strict'
import React, { Component } from 'react';
import { StyleSheet, Text, View, AsyncStorage, Image } from 'react-native';
import util from '../common/util';
class Card extends Component {
constructor(props) {
super(props);
}
render() {
let subject, posterImage, image; // 大圖
this.props.subject ? subject = this.props.subject : subject = this.props;
posterImage = subject.images.large;
if(posterImage != '' && posterImage != null) {
image = <Image resizeMode="stretch" style={styles.posterImage}
source={{uri: posterImage}}/>;
}else{
image = <Text>{this.props.subject.title}</Text>;
}
return (
<View style={[styles.cardBox, this.props.CardPosition ? {
position: 'absolute',
top: this.props.CardTop} : null
]}>
<View style={styles.posterWrap}>
{image}
{this.props.new ? <Text style={styles.newTop}>新上榜</Text> : null }
{this.props.rank ? <Text style={styles.topNumber}>Top {this.props.rank}</Text> : null}
</View>
<View style={styles.cinemaMsg}>
<View style={styles.cinemaMsgItem}>
<Text style={styles.title} numberOfLines={1} >{subject.title}
{ this.props.box ? <Text style={styles.cast}> {subject.casts[0].name}...</Text> : null}
</Text>
<Text style={styles.average}>評分:{subject.rating.average}</Text>
</View>
<View style={styles.cinemaMsgItem}>
<Text style={[styles.arrivedMsg, styles.flex2]} numberOfLines={1}>{subject.original_title} ({subject.year})</Text>
<Text style={styles.boxOffice} numberOfLines={1}>{ this.props.box ? '票房:' + this.props.box/1000 : subject.casts[0].name}</Text>
</View>
<View style={styles.cinemaMsgItem}>
<Text style={styles.arrivedMsg}>類型:{subject.genres.join('\/')}</Text>
<Text style={styles.directors}>導演:{subject.directors[0].name}</Text>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
flex2: {
overflow: 'hidden',
},
cardBox: {
borderRadius: 5,
borderWidth: 2,
marginTop: 2,
width: 310,
marginHorizontal: (util.size.width - 310) / 2 ,
borderColor: '#e1e2da',
backgroundColor: '#ffffff',
},
posterWrap: {
width: 310,
borderColor: '#e1e2da',
},
posterImage: {
height: 340,
width: 310,
},
newTop: {
position: 'absolute',
top: 0,
right: 0,
fontSize: 12,
color: '#ffffff',
backgroundColor: 'rgba(230,69,51,0.65)',
paddingVertical: 1,
paddingHorizontal: 3,
},
topNumber: {
position: 'absolute',
top: 0,
left: 0,
fontSize: 12,
color: '#ffffff',
paddingVertical: 1,
paddingHorizontal: 3,
backgroundColor: 'rgba(255,164,51,0.7)',
},
cinemaMsg: {
width: 300,
padding: 2,
flexDirection: 'column',
},
cinemaMsgItem: {
flex: 1,
justifyContent: 'space-between',
flexDirection: 'row',
},
title: {
flex: 2,
fontSize: 15,
color: '#1d1d1d',
textAlign: 'left',
},
cast: {
fontSize: 12,
},
average: {
flex: 1,
fontSize: 15,
color: '#e64533',
textAlign: 'right',
},
arrivedMsg: {
fontSize: 13,
textAlign: 'left',
},
boxOffice: {
flex:1,
fontSize: 12,
color: '#e64533',
textAlign: 'right',
},
directors: {
fontSize: 12,
textAlign: 'right',
color: '#1d1d1d',
},
});
module.exports = Card;
卡片滑動swipe 效果
npm install -g react-native-swipe-cards
import SwipeCards from 'react-native-swipe-cards';
render() {
let data = (this.props.dataCinema ? JSON.parse(this.props.dataCinema) : null);
return (
<View style={styles.box}>
{ data ?
<SwipeCards cards={data} style={styles.swipeCards}
loop={true}
renderCard={(cardData) => <Card {...cardData} />}
handleYup={this.handleYup} renderNope={this.renderNope} renderYup={this.renderYup}
handleNope={this.handleNope}
cardRemoved={this.cardRemoved}/>
: null
}
</View>
);
}
首頁抽屜效果
npm install -g react-native-drawer
render() {
return (
<Drawer
ref={(ref) => this._drawer = ref}
type="static"
content={
<LeftControlPanel closeDrawer={this.closeDrawer}/>
}
styles={{main: {shadowColor: '#000000', shadowOpacity: 0.3, shadowRadius: 15}}}
captureGestures={true}
acceptTap={true}
acceptPan={true}
negotiatePan={false}
useInteractionManager={false}
tweenDuration={100}
panThreshold={0.08}
panOpenMask={0.03}
panCloseMask={0}
disabled={this.state.drawerDisabled}
openDrawerOffset={(viewport) => {
return 80
}}
panOpenMaskY={50}
side="left"
tweenHandler={Drawer.tweenPresets.parallax}
>
<Drawer
type="static"
ref={(ref) => this._drawer2 = ref}
content={
<RightControlPanel closeDrawer={this.closeDrawer2} />
}
captureGestures={true}
acceptTap={true}
acceptPan={true}
negotiatePan={false}
useInteractionManager={false}
tweenDuration={100}
panThreshold={0.08}
panOpenMask={0.03}
panCloseMask={0}
openDrawerOffset={(viewport) => {
return 80
}}
side="right"
tweenHandler={Drawer.tweenPresets.parallax}
>
<Main topItem={this.state.topItem} navigator={this.props.navigator}/>
</Drawer>
</Drawer>
以上所用插件我都有改動 符合demo的需求····
通過這次的demo學習對react 有進一步的認識與體會,
組件的生命週期
componentWillReceiveProps(nextProps){} 接收新的數據
shouldComponentUpdate(nextProps, nextState){ return boo} 必須有返回值, 返回 false componentWillUpdate()不會被調用 render()也再不執行 ,這樣根據需要可以禁止頁面的更新。
react native事件捕獲
onStartShouldSetPanResponderCapture, onMoveShouldSetPanResponderCapture連個方法都有返回值, 返回true 時,事件就不再傳遞,被當前組件劫持並調用當前組件的onResponderStart或者onResponderRlase等
數據請求利用 facth 比傳統ajax 更簡潔 當然屬於es6 的
fetch(url).then((response) => response.text())
.then((responseText) => {
successCallback(JSON.parse(responseText));
}).catch(function(err){
failCallback(err);
});
state 更新 用setState 當然也可以用 如
this.state['cards'] = JSON.parse(nextProps.dataCinema);
this.forceUpdate();
forceUpdate就是重新render。有變量不在state上,缺又想更新state,刷新render;或者state裏的某個變量層次太深,更新的時候沒有自動觸發render。這些時候都可以手動調用forceUpdate自動觸發render。
跳轉到github