React Native实践React-Native 开发阵营React Native开发

初探React-Native(二)代码篇

2018-01-25  本文已影响70人  叫我马小帅

撸了几天代码,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’)

4CB009D5DC235BB97D8FE345EB7F68AD.png

因为...有个库不用了,详情自己百度吧,这不重要,俺们来干的,上解决办法

进入到他的代码位置


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之路还在慢慢探索中,有什么问题欢迎打扰,一起探讨

生命不息,代码不止!码农一枚,请多点赞

上一篇下一篇

猜你喜欢

热点阅读