有配套视频
,能够酌情观看。
本篇资源:连接: https://pan.baidu.com/s/1qXH2qx2 密码: b5sjphp
源码托管到 github 上,须要源码的 点我下载,喜欢的话记得 Star,谢谢!react
本章许多内容原本是要放到后面讲的,考虑到有朋友可能不须要了解
redux
相关内容,因此把能想到的一些常见的东西先讲下。android
在服务器返回给咱们的 json
数据中,提供了 hasnexthour
字段,当这个字段返回为 1
的时候,表示后面还有内容,按钮能够点击,不然不能点击,按照这个思路,咱们就来完成这个功能。git
在 state
中新增 isNextTouch
状态github
isNextTouch:false // 下一小时按钮状态
在每次请求成功后都更新下状态:json
let isNextTouch = true; if (responseData.hasnexthour == 1) { // hasnexthour不为0时 下一小时 按钮可点击 isNextTouch = false; } // 从新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(responseData.data), loaded:true, prompt:responseData.displaydate + responseData.rankhour + '点档' + '(' + responseData.rankduring + ')', isNextTouch:isNextTouch, // 更新按钮状态 });
接着咱们就能够根据状态进行相应更改:redux
{/* 下一小时按钮 */} <TouchableOpacity onPress={() => this.nextHour()} disabled={this.state.isNextTouch} > <Text style={{marginLeft:10, fontSize:17, color:this.state.isNextTouch == false ? 'green' : 'gray'}}>{"下1小时" + " >"}</Text> </TouchableOpacity>
使用 ref
能够获取到相应的组件,更加灵活地在须要的地方使用,配合 setNativeProps
能够作到不直接调用 render
直接渲染组件,在某些频繁更新的组件上使用,能够 大大提升性能
,不过 千万
不要为了使用 setNativeProps
而使用,某些状况下可能会拔苗助长。react-native
使用方法以下:api
test() { this.refs.testText.setNativeProps({ style: { backgroundColor:'green' } }) } <Text ref="testText">快,说我帅</Text>
原版 APP
中当咱们点击 首页和海淘
2个 Item
时,会立刻获取最新数据个数而后进行更新,这边来实现一下这个功能。服务器
经过通知的方式监听Item点击作相应的操做,因此咱们在须要接收通知的页面注册一下通知,在须要的地方发送通知便可:
home
界面注册通知// 组件加载完成 componentDidMount() { // 注册通知 this.subscription = DeviceEventEmitter.addListener('clickHomeItem', () => this.clickTabBarItem()); }
componentWillUnmount() { // 注销通知 this.subscription.remove(); }
clickTabBarItem
方法逻辑:// 点击了Item clickTabBarItem() { // 加载最新数据 this.loadData(); }
回到 Main
页面,咱们修改下点击 Item
响应的事件:
Item
点击事件:onPress={() => this.clickItem(selectedTab, subscription)}>
clickItem
方法逻辑:// 点击了Item clickItem(selectedTab, subscription) { if (subscription !== "" && this.state.selectedTab == selectedTab) { // 发送通知 DeviceEventEmitter.emit(subscription); } // 渲染页面 this.setState({ selectedTab: selectedTab }) }
因此传值也须要新增 subscription
参数,不须要订阅的按钮就能够传 ""
便可。
海淘也是相似操做,这边就不赘述,本身试着实现一下。
实现思路很简单,咱们使用逆传的方式,每次获取到最新数据的时候,同时须要调用一下 在 main
中 获取最新数据个数
的请求方法便可。
首先咱们在 home
定义一个属性供外界使用:
static defaultProps = { loadDataNumber:{}, // 回调 };
接着,当咱们请求到最新数据的同时,咱们调用一下这个属性,就能够了:
// 获取最新数据个数 this.loadDataNumber(); // loadDataNumber 中的逻辑 loadDataNumber() { // 调用 this.props.loadDataNumber 中保存的代码块 this.props.loadDataNumber(); }
为了方便调用,咱们将 获取最新数据个数
的逻辑抽出来放到单独的方法内,这边顺便再介绍 AsyncStorage
怎么同时获取多个 key
值的方法:
// 获取最新数据个数网络请求 loadDataNumber() { // 取出id AsyncStorage.multiGet(['cnfirstID', 'usfirstID'], (error, stores) => { // 拼接参数 let params = { "cnmaxid" : stores[0][1], "usmaxid" : stores[1][1], }; // 请求数据 HTTPBase.get('http://guangdiu.com/api/getnewitemcount.php', params) .then((responseData) => { this.setState({ cnbadgeText:responseData.cn, usbadgeText:responseData.us }) }) .catch((error) => { }) }); }
很好,接着咱们转到 main 中,修改下 renderTabBarItem
方法中的内容,实现一下 `` 属性的方法:
renderScene={(route, navigator) => { let Component = route.component; return <Component {...route.params} navigator={navigator} loadDataNumber={() => this.loadDataNumber()} /> }}
到这里就完成了,海淘页面也是相似操做,本身试着实现一下。
一键置顶功能也是市面上 APP
上能够说必备功能了,这边 原版APP
也有这个功能,因此咱们跟着来实现一下。
这个功能实现更加简单,只要咱们调用 ScrollView
的 scrollTo
方法,将 y
设置为 0 便可;由于 ListView
是在 ScrollView
上进行的二次开发,因此它可使用 ScrollView
的全部方法:
// 点击了Item clickTabBarItem() { let PullList = this.refs.pullList; // 一键置顶 PullList.scrollTo({y:0}); }
这样咱们的一键置顶功能就完成了,在须要的页面进行一样操做就能够实现相同功能。
那么为了更好的用户体验,咱们这边还须要来处理一下点击 TabBarItem
的一下细节,那就是当用户点击 Item
时,可能只是单纯的想进行页面的 切换或者置顶操做
,而不想进行 刷新
,那么咱们就须要来判断一下何时须要刷新,何时须要置顶。
那么咱们能够经过判断 ListView
中的 Scroll
的偏移量来判断是否须要进行置顶操做,当偏移量大于 1 的时候咱们就进行置顶操做,不然的话咱们就进行刷新操做。
那么问题又来了,当咱们执行刷新操做的时候,应该模拟用户下拉显示 滚动小菊花
来告诉用户咱们在进行刷新操做,但是 pullList
并无提供咱们这个方法怎么办?那咱们就须要分析 第三方框架的内容
来找方法解决这个问题(具体方法,能够观看我为各位录制的视频),这边就很少讲了,直接上最终代码:
// 点击了Item clickTabBarItem() { let PullList = this.refs.pullList; if (PullList.scroll.scrollProperties.offset > 0) { // 不在顶部 // 一键置顶 PullList.scrollTo({y:0}); }else { // 在顶部 // 执行下拉刷新动画 PullList.state.pullPan = new Animated.ValueXY({x: 0, y: this.topIndicatorHeight * -1}); // 加载最新数据 this.loadData(); // 关闭动画 setTimeout(() => { PullList.resetDefaultXYHandler(); },1000); } }
那这边咱们的筛选菜单还有个问题,就是能够响应咱们的手势进行滚动,这样确定是不对的,那么咱们须要关闭这个手势的监听,使这个菜单不能滚动,具体操做以下:
{/* 菜单内容 */} <ListView scrollEnabled={false} // 关闭滑动功能 dataSource={this.state.dataSource} // 设置数据源 renderRow={this.renderRow.bind(this)} // 根据数据初始化 Cell contentContainerStyle={styles.contentViewStyle} // 样式 initialListSize={16} // 一次性渲染几行数据 />
到如今确定有不少朋友发现 Navigator
跳转动画并非那么流畅,会出现掉帧卡顿的现象,并不像 NavigatorIOS
那么丝丝顺滑;形成这个的缘由是由于 NavigatorIOS
是在 UI线程 执行的 动画操做,而 Navigator
是在 JS线程执行的动画,那这样就会 阻塞住 JS线程,那么怎么去解决这个问题?这边提供 2 种方案:
第一种:使用 navigation 框架,这个是目前替代 navigator 最好的方案之一,很强大,很流畅,可是须要再去学习一下使用。
第二种:若是你懒得学习上面的框架,那么这边再给各位提供另外一种方法 —— 使用官方提供的 API:InteractionManager(能够将一些耗时较长的工做安排到全部互动或动画完成以后再进行。这样能够保证JavaScript动画的流畅运行),这边咱们就使用这种方案来进行一下优化:
InteractionManager.runAfterInteractions(() => { this.props.navigator.push({ component: Search, }); });
是的,就这一步操做便可,在其余须要用到 跳转功能的地方 使用一下这个API便可。
用于提高大列表的滚动性能。须要给行容器添加样式overflow:'hidden'。(Android已默认添加此样式)此属性默认开启
这个属性是由于在早期 ListView
在数据到达必定程度的时候就会愈来愈卡,最终致使 APP 崩溃退出,使用这个属性后 APP 崩溃确实在必定程度上获得缓解,可是卡顿问题仍是依旧存在。那等到后面咱们会介绍 FlatList
,它将是将来 ListView
替代品,主要解决它性能差的,占用内容持续增长的问题,目前还没发布稳定版本,可是通过一段时间测试,我以为已经能够向你们推荐了,因此在后面的章节中会为各位介绍的。
废了这么多话,这边咱们就先来使用一下 removeClippedSubviews
,很简单,使用它只须要在咱们封装的 cell 中的 container
样式中添加 overflow:'hidden'
便可。
container: { flexDirection:'row', alignItems:'center', justifyContent:'space-between', backgroundColor:'white', height:120, width:width, borderBottomWidth:0.5, borderBottomColor:'gray', marginLeft:15, overflow:'hidden', },
这边咱们试了下安卓,发现当咱们显示 modal 而后又关闭 modal 的时候,就会出现 ListView 列表消失的问题,那么实际上是由于咱们 modal 放置的顺序问题,modal 应当放置到全部主视图以后建立,避免它影响其余视图显示,这边就以 home
页面为例,其余视图本身实现哈:
render() { return ( <View style={styles.container}> {/* 导航栏样式 */} <CommunalNavBar leftItem = {() => this.renderLeftItem()} titleItem = {() => this.renderTitleItem()} rightItem = {() => this.renderRightItem()} /> {/* 根据网络状态决定是否渲染 listview */} {this.renderListView()} {/* 初始化近半小时热门 */} <Modal pointerEvents={'box-none'} animationType='slide' transparent={false} visible={this.state.isHalfHourHotModal} onRequestClose={() => this.onRequestClose()} > {/* 包装导航功能 */} <Navigator initialRoute={{ name:'halfHourHot', component:HalfHourHot }} renderScene={(route, navigator) => { let Component = route.component; return <Component removeModal={(data) => this.closeModal(data)} {...route.params} navigator={navigator} /> }} /> </Modal> {/* 初始化筛选菜单 */} <Modal pointerEvents={'box-none'} animationType='none' transparent={true} visible={this.state.isSiftModal} onRequestClose={() => this.onRequestClose()} > <CommunalSiftMenu removeModal={(data) => this.closeModal(data)} data={HomeSiftData} loadSiftData={(mall, cate) => this.loadSiftData(mall, cate)} /> </Modal> </View> ); }
缘由咱们以后会带你们来本身 开发一个相似 modal 的组件,到时候再跟你们详解。
细心的朋友应该发现了一个问题,一样一张 git 图片,在 iOS 上能够正常加载,在 Android 上图片居然不能动,可能会想算了吧,能显示图片就好了?转头发现,产品经理正 “清闲” 磨刀呢。。。那其实解决这个问题很简单,咱们只须要使用一下 facebokk 的一个强大的图片加载库就能解决这个问题了。
首先,咱们打开 build.gradle
,在 dependencies
中添加下面一行代码
compile "com.facebook.fresco:animated-gif:0.13.0"
从新 run 一下,编译器会自动帮咱们添加这个库并配置完毕,那么 Android 上也能够愉快地显示 gif图片 了。
什么?找不到这个文件?那可不行,看一下给各位录制的视频吧。
咱们导航栏的返回按钮很挫对吧,这边统一简单先改一下:
// 返回左边按钮 renderLeftItem() { return( <TouchableOpacity onPress={() => {this.pop()}} > <View style={{flexDirection:'row', alignItems:'center'}}> <Image source={{uri:'back'}} style={styles.navbarLeftItemStyle} /> <Text>返回</Text> </View> </TouchableOpacity> ); }
那么 Android 中的 TextInput
的下划线是否是丑爆了?这边咱们也来处理下它,直接使用 underlineColorAndroid
这个属性,让他为透明便可。
underlineColorAndroid={'transparent'}
这边先来介绍一下 navigationBa
的使用,使用它可让咱们只在一个地方管理 navigator
导航栏的样式,就不用像如今这样在每一个页面都手动添加导航栏。
这边先举个例子让你们知道怎么用,考虑到传值不方便的缘由,到讲完 redux
以后,再一块儿讲这部份内容,因此你们只须要了解一下怎么使用就能够了。
首先,咱们来看下 navigationBar
文件内的内容:
let NavigationBarRouteMapper = { LeftButton(route, navigator, index, navState) { if (index > 0) { return ( <TouchableOpacity onPress={() => navigator.pop()} > <Text>返回</Text> </TouchableOpacity> ) } }, RightButton(route, navigator, index, navState) { }, Title(route, navigator, index, navState) { return( <Text>{route.name}</Text> ) }, }; export default ( <Navigator.NavigationBar style={{backgroundColor:'green'}} routeMapper={NavigationBarRouteMapper} /> )
接着,咱们到 main文件中
使用一下这个 navigationBar
:
navigationBar={NavigationBar}
拨打电话(真机测试,模拟器没有打电话功能):
import { Linking } from ‘react-native’; function callPhone() { return Linking.openURL('tel:10086'); }
获取视图组件的 x,y,宽,高,偏移量的值,可使用 measure 方法:
this.refs.mainView.measure((x, y, width, height, px,py)) => { console.log(width); }
开发中建议先从 iOS 端作起,安卓端适配;固然若是公司不是只有你一我的负责 react-native 项目,大可没必要理会这条。
开发中有些功能在 模拟器 上是没法测试的,这时候须要配合真机进行调试,下面整理出一些常见的问题:
肯定电脑与咱们手机链接同一个 WiFi 网络环境下。
咱们须要打开 开发中菜单(摇下手机) —— —— —— 输入电脑IP地址(IP地址怎么找?本身搜索吧)—— 退出菜单 ——
到这里第一个版本就完结了,接下来就要开始咱们的第二版本的开发了,那么第二个版本以前大概会用一篇的内容来主要讲下 react
怎么结合 redux
进行开发,并作个小 Demo,让你们先熟悉一下 redux
使用,而后就是咱们当前的项目 转为 redux
开发了。
这边想知道你们更想知道或者对于 redux
哪里比较不理解的,好跟着改进一下,尽可能使文章和视频更易懂。