初探React-Native(二)代码篇
撸了几天代码,iOS项目中集成RN页面还算简单,主要是互相之间的通讯,现在开始撸代码啦,
直接上干货!
1.iOS项目于RN之间互相的通讯
iOS向RN页面发送数据,只能发送字典奥!!!
iOS向RN页面发送数据在RN界面接收后就可以直接使用啦!
接收并使用
RN向iOS发送数据
iOS项目中先创建一个类,并继承协议
.m文件
.h文件
在RN文件中,声明NativeModules
NativeModules声明
其中CalendarManager要和iOS项目的类名一模一样!
发送字符串
之所以发送加载结束是因为我在iOS项目中添加了HUD蒙版,等RN页面的数据加载完成之后,发送加载结束给iOS项目,然后清除蒙版,但是这里有个小坑,下文说
发送字典数据这样就可以RN传值给iOS了,大家可以试一试,好了,现在要说一下坑了,由于本人懒癌发作,脑抽的没有新建类,而是直接在ViewController中直接继承了协议,机智的我发现一样可以NSLog()打印出数据,然后我就直接操作 [HUD removeFromSuperview]; 发现取消不了HUD,打印HUD发现为null!
可以接收数据,但是并改不了样式,哪怕加主线程谷歌到的原因
解决方式还是老老实实的新创建类,然后用通知的方式进行更改吧 image.png
要放在主线程中奥!
2.RN中的列表ListView,包括下拉刷新上拉加载和网络请求
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
View,
Image,
ListView,
Text,
TouchableOpacity,
AlertIOS,
NativeModules,
RefreshControl,
ActivityIndicator,
Dimensions
} from 'react-native';
// 与iOS端通讯
var CalendarManager = NativeModules.CalendarManager;
// 声明空数组
var demoList = [];
// 获取全屏宽和高
var {width, height} = Dimensions.get('window');
class ZhongShiMedia extends Component {
constructor(props) {
super(props);
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(demoList),
bigImg:'',
page:0,
isLoadingTail: false, //是否显示下拉加载的动画,没有数据了返回ture择不显示下拉动画
isRefreshing: false, // 是否隐藏上拉
first:false, //因为第一次进入时_endReached也会走,为false让他第一次不执行网络请求方法
};
this.fetchData(false);
}
render() {
return (
<View style={styles.container}>
<ListView
dataSource={this.state.dataSource}
contentContainerStyle={styles.grid}
renderHeader={this._renderHeader.bind(this)} // 添加头视图
renderRow={this._renderRow.bind(this)}
renderFooter={() => this._renderFooter()} //尾视图用来显示加载图标
onEndReachedThreshold={1} //显示尾视图就执行加载
onEndReached={() => this._endReached()}
refreshControl={
<RefreshControl
refreshing={this.state.isRefreshing} // 是否显示下拉舒心的动画
onRefresh={() => this._onRefresh()}/>
}
/>
</View>
)
}
fetchData(isLoadMore) {
if (isLoadMore) {
// 加载
this.state.page = this.state.page + 1;
}else{
//刷新
this.state.page = 1;
}
let page = this.state.page ;
console.log('++++++' + page);
//网络请求方法
let url = 'http://pulandian.crhclub.com/attractionWebService.ashx?action=getAttractionInfoListRenqi&pageSize=10&page=' + page ;
fetch(url, {
method: 'GET',
headers: {},
})
.then((response) => response.json())
.then((responseData) => {
// 如果有数据
if (responseData.zhihuijinshi.length != 0) {
if (isLoadMore) {
// 加载
demoList = demoList.concat(responseData.zhihuijinshi);
}else{
//刷新
demoList = [];
demoList = demoList.concat(responseData.zhihuijinshi);
}
}else{
// 没有数据后,就不在执行下拉刷新的动画
this.setState({
isLoadingTail: true
});
}
//修改数据和UI
this.setState({
dataSource: this.state.dataSource.cloneWithRows(demoList),
bigImg:responseData.advert[0].imgUrl,
isRefreshing: false,
});
//发送iOS端,取消HUD的动画
CalendarManager.addEventOne('加载结束')
})
.catch((error) => {
callback(error);
});
}
// 上拉刷新的方法
_onRefresh = () => {
this.setState({
isRefreshing: true,
});
this.fetchData(false);
}
//下拉刷新的方法
_endReached = () => {
// 防止第一次执行
if(!this.state.first) {
this.setState({
first: true,
});
return
}
// 获取数据
this.fetchData( true);
}
_renderFooter = () => {
//没数据了则不显示动画
if(this.state.isLoadingTail == true) {
return <View style={{marginVertical:0}}/>
}
// 加载动画
return (<ActivityIndicator style={{ marginVertical:20 }}/>);
}
// 头视图
_renderHeader(){
return ( <Image source={{uri:this.state.bigImg}} style={styles.hadImg} /> );
}
// cell 的布局
_renderRow(rowData, sectionid, rowid) {
return (
<TouchableOpacity activeOpacity={0.5} onPress={()=>{CalendarManager.addEventTwo({Id:rowData.id,title:rowData.title})}}>
<View style={styles.itemLayout}>
<Image defaultSource={{uri:'icon'}} source={{uri:rowData.imgurl}} style={styles.imageeee} />
<View style={styles.rightSty}>
<Text style={styles.titleSty}>{rowData.title}</Text>
<Text style={styles.addressSty}>{rowData.address}</Text>
</View>
</View>
<View style={styles.xian}></View>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
container: { //根View样式
marginTop:64,
flex: 1,
backgroundColor: '#F6F6F6'
},
imageeee:{
height:100,
marginLeft:15,
marginTop:10,
flex:0.4,
backgroundColor: '#63BAE0'
},
rightSty:{
flex:0.6,
backgroundColor: '#F6F6F6'
},
hadImg:{
flex:1,
height:150,
resizeMode:'stretch',
},
titleSty:{
marginTop:10,
marginLeft:15,
width:width * 0.5,
height:20,
fontSize: 17,
},
addressSty:{
marginTop:10,
marginLeft:15,
width:width * 0.5,
},
xian:{
width:width,
height:1,
backgroundColor:'#272822',
marginTop:10,
},
itemLayout:{
flex:1,
flexDirection:'row',
flexWrap:'wrap',
backgroundColor:'#F6F6F6',
},
});
// 项目名要有所对应
AppRegistry.registerComponent('ZhongShiMedia', () => ZhongShiMedia);
(xianView那个就是创建一条线,可以用 borderStyle:'solid',
borderBottomWidth:1,
borderBottomColor:'gray', 这个属性替代,不要像我一样low,这些代码可复制粘贴直接使用,备注写的也还可以,喜欢给点个赞,如果有问题,可以联系我)
以下是个人理解的RN布局
RN布局主要是操作父类,在一个<View></View>中View是父类,通过样式代码控制其子类是横向布局还是纵向布局
flexDirection:column 纵向 row 横向
然后可以再里面在通过另一个<View></View>来重新控制其横向还是纵向,但是必须是View,ScrollView行不行没有试,不过<Text>和<Image/>是不行的
不过其子类可以用alignSelf这个属性
RN中没有css的浮动属性,不过有绝对定位和相对定位
3.RN中加载webView
<WebView bounces={false}
scalesPageToFit={true}
scrollEnabled={false}
onLoadEnd={this.onLoadEnd}
source={{uri:'https://www.baidu.com',method: 'GET'}}
style={styles.webSty}>
</WebView>
搞完了iOS中集成RN布局,又玩了会纯RN项目,这个RN项目也是好多坑呀!!!我捞干的长话短说吧
1.tabBar项目框架的搭建
首先RN要集成一些第三方框架,而RN的关于tabBar的框架有TabNavigator和react-navigation
安装第三方框架的方法
安装:npm install react-navigation --save
查看:npm view react-navigation
删除:npm rm react-navigation --save
安装TabNavigator
npm install react-native-tab-navigator --save
安装react-navigation
npm install react-navigation --save
为什么要安装第三方框架呢,因为第三方框架安卓和iOS可以通用!
以上两个框架我都试了,我推荐使用react-navigation,因为到二级页面后他可以隐藏tabBar,
而TabNavigator没有隐藏的方法,只能动态改变TabBar的高度,也可能是我的方法有问题,才导致以下的Bug
如果有解决方法告诉我一下
react-navigation框架的集成....懒癌又犯了!主要是集成的代码太多,涉及多个页面,Demo还没写好,想要的留言吧,或者加我QQ1002547276,可以发个小项目给你
这是集成的部分代码2.RN中创建轮播图
RN中主流的轮播图框架也有两个react-native-swiper 和 react-native-viewpager
这两个框架我同样都集成了,先说react-native-viewpager
安装react-native-viewpager
npm install react-native-viewpager --save
项目中导入import ViewPager from 'react-native-viewpager';
image.png
但是这时候运行你会发现可恶的红色出现了
unddefined is not an object(evaluating ‘React.propTypes.func’)
因为...有个库不用了,详情自己百度吧,这不重要,俺们来干的,上解决办法
进入到他的代码位置
image.png ViewPager.js文件修改 DefaultViewPageIndicator.js文件修改 DefaultViewPageIndicator.js文件修改
这样就解决啦,可以畅快的用react-native-viewpager了
集成代码
import React, { Component ,PropTypes} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Dimensions,
Image
} from 'react-native';
import ViewPager from 'react-native-viewpager';
var deviceWidth = Dimensions.get('window').width;
var BANNER_IMGS = [
'https://images.unsplash.com/photo-1441742917377-57f78ee0e582?h=1024',
'https://images.unsplash.com/photo-1441716844725-09cedc13a4e7?h=1024',
'https://images.unsplash.com/photo-1441448770220-76743f9e6af6?h=1024',
'https://images.unsplash.com/photo-1441260038675-7329ab4cc264?h=1024',
'https://images.unsplash.com/photo-1441126270775-739547c8680c?h=1024',
'https://images.unsplash.com/photo-1440964829947-ca3277bd37f8?h=1024',
'https://images.unsplash.com/photo-1440847899694-90043f91c7f9?h=1024'
];
export default class HomePage extends Component {
constructor(props) {
super(props);
// 用于构建DataSource对象
var dataSource = new ViewPager.DataSource({
pageHasChanged: (p1, p2) => p1 !== p2,
});
// 实际的DataSources存放在state中
this.state = {
dataSource: dataSource.cloneWithPages(BANNER_IMGS)
}
}
_renderPage(data, pageID) {
return (
<Image
source={{uri:data}}
style={styles.page}/>
);
}
render() {
return (
<View style={styles.container}>
<ViewPager
style={{height:130}}
dataSource={this.state.dataSource}
renderPage={this._renderPage}
isLoop={true}
autoPlay={true}
/>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
alignItems: 'flex-start',
backgroundColor:'#999999',
},
page: {
width: deviceWidth,//设备宽(只是一种实现,此处多余)
height: 130,
resizeMode: 'stretch'
},
});
你以为这就结束了? 不!!!
小点点有问题
这个控件的page点有问题,看到这一通集成的我已经崩溃了,不过可以在样式中添加renderPageIndicator={false} 来隐藏点点,不过我已经放弃这个控件了,如果有解决方法请留言或者私聊我!
下面就来看看react-native-swiper,首先先来说我为什么没有第一个选择这个框架,因为百度查到的react-native-swiper的资料都是
image.png image.png
可以看出来,他们都是固定写死个数的<Image/>,实际开发中,要根据后台返回的数据来创建不同个数<Image/>,所有就要根据后台传的数组,动态创建<Image/>
动态创建控件有了这个,剩下的就简单啦
安装 react-native-swiper
npm i react-native-swiper --save
import React, { Component ,PropTypes} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Dimensions,
Image
} from 'react-native';
import Swiper from 'react-native-swiper';
var deviceWidth = Dimensions.get('window').width;
var BANNER_IMGS = [
'https://images.unsplash.com/photo-1441742917377-57f78ee0e582?h=1024',
'https://images.unsplash.com/photo-1441716844725-09cedc13a4e7?h=1024',
'https://images.unsplash.com/photo-1441448770220-76743f9e6af6?h=1024',
'https://images.unsplash.com/photo-1441260038675-7329ab4cc264?h=1024',
'https://images.unsplash.com/photo-1441126270775-739547c8680c?h=1024',
'https://images.unsplash.com/photo-1440964829947-ca3277bd37f8?h=1024',
'https://images.unsplash.com/photo-1440847899694-90043f91c7f9?h=1024'
];
export default class HomePage extends Component {
constructor(props) {
super(props);
// 实际的DataSources存放在state中
this.state = {
}
}
render() {
var images = [];
for (var i = 0; i < BANNER_IMGS.length; i++) {
let view = (
<View style={styles.slide}>
<Image
source={{uri:BANNER_IMGS[i]}}
style={styles.page}/>
</View>
)
images.push(view);
}
return (
<View style={styles.lalal}>
<Swiper style={styles.wrapper} height={200} horizontal={true} autoplay autoplayTimeout={1}
// 修改点点的位置
// paginationStyle={{
// bottom: 23, left: null, right: 10
// }}
>
{images}
</Swiper>
</View>
);
}
}
var styles = StyleSheet.create({
lalal:{
height:200,
width:deviceWidth,
backgroundColor:'#FEFEFE',
},
slide: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#9DD6EB'
},
page: {
color: '#fff',
width:deviceWidth,
height:150,
}
});
这两天撸的代码都在这里啦,RN之路还在慢慢探索中,有什么问题欢迎打扰,一起探讨