React-Native 之 项目实战(四)
2017-04-08 08:58
375 查看
前言
本文有配套视频,可以酌情观看。文中内容因各人理解不同,可能会有所偏差,欢迎朋友们联系我。
文中所有内容仅供学习交流之用,不可用于商业用途,如因此引起的相关法律法规责任,与我无关。
如文中内容对您造成不便,烦请联系 277511806@qq.com 处理,谢谢。
转载麻烦注明出处,谢谢。
本篇资源:链接: https://pan.baidu.com/s/1pKActHh 密码: n6ee
源码托管到 github 上,需要源码的 点我下载,喜欢的话记得点下星星,谢谢!
数据持久化
数据持久化是移动端的一个重要部分,刚发现 Realm原来已经支持
React-Native了,那么这边另起一篇专门介绍两种常用的存储方式
———— React-Native 之 数据持久化
这边没有发现
官方有将
商品数据做本地缓存的功能,为了让大家知道怎么做,我们就简单地来实验一下,具体逻辑在每个产品中都或多或少有些差异,这个朋友们就根据所学的灵活变通一下就可以了!
首先,在为了方便使用,也为了减少第三方框架对工程的 “污染”,我们需要对框架进行一次
基础的封装。
var RealmBase = {}; import Realm from 'realm'; const HomeSchame = { name:'HomeData', properties:{ id:'int', title:'string', image:'string', mall:'string', pubtime:'string', fromsite:'string', } }; const HTSchame = { name:'HTData', properties:{ id:'int', title:'string', image:'string', mall:'string', pubtime:'string', fromsite:'string', } }; // 初始化realm let realm = new Realm({schema:[HomeSchame, HTSchame]}); // 增加 RealmBase.create = function (schame, data) { realm.write(() => { for (let i = 0; i<data.length; i++) { let temp = data[i]; realm.create(schame, {id:temp.id, title:temp.title, image:temp.image, mall:temp.mall, pubtime:temp.pubtime, fromsite:temp.fromsite}); } }) } // 查询全部数据 RealmBase.loadAll = function (schame) { return realm.objects(schame); } // 条件查询 RealmBase.filtered = function (schame, filtered) { // 获取对象 let objects = realm.objects(schame); // 筛选 let object = objects.filtered(filtered); if (object) { // 有对象 return object; }else { return '未找到数据'; } } // 删除所有数据 RealmBase.removeAllData = function (schame) { realm.write(() => { // 获取对象 let objects = realm.objects(schame); // 删除表 realm.delete(objects); }) } global.RealmBase = RealmBase;
经过简单封装后,我们还需要引用一下框架,引用框架,我们就放到
main文件内,这样我们就可以确保
全局变量是在我们使用它之前就被调用过,避免找不到对象的错误(我们也同时将
HTTPBase修改为全局,方便使用)。
import RealmStorage from '../storage/realmStorage';
现在我们就来做下
本地持久化实验,这边我们的逻辑就是,当网络出现问题的时候,每次都会进到
catch 中返回错误 code 告诉我们,出现了什么问题(既然进到这里了,是不是数据无论如何都不会加载成功?),那么我们就可以在这里
取出本地数据,然后展示出来,那么数据的应该在哪里保存呢?这个我们只需要在每次
刷新完成并且渲染完成后,保存一下数据就可以了。
// 加载最新数据网络请求 loadData(resolve) { let params = {"count" : 10 }; HTTPBase.get('https://guangdiu.com/api/getlist.php', params) .then((responseData) => { // 清空数组 this.data = []; // 拼接数据 this.data = this.data.concat(responseData.data); // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); // 关闭刷新动画 if (resolve !== undefined){ setTimeout(() => { resolve(); }, 1000); } // 存储数组中最后一个元素的id let cnlastID = responseData.data[responseData.data.length - 1].id; AsyncStorage.setItem('cnlastID', cnlastID.toString()); // 存储数组中第一个元素的id let cnfirstID = responseData.data[0].id; AsyncStorage.setItem('cnfirstID', cnfirstID.toString()); // 清楚本地存储的数据 RealmBase.removeAllData('HomeData'); // 存储数据到本地 RealmBase.create('HomeData', responseData.data); }) .catch((error) => { // 拿到本地存储的数据,展示出来,如果没有存储,那就显示无数据页面 this.data = RealmBase.loadAll('HomeData'); // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); }) }
到这里,我们就完成了
数据本地持久化并且成功将数据取出,这边数据持久化的实验就完成了。
数据持久化.gif
译注:
有关
realm的配置,可转到 React-Native
之 数据持久化 查看,这边不多赘述。
当我们完全配置完
realm后,会发现整个工程
多出将近500M+,不用担心,这些只不过是
realm的依赖库,等我们后面
打包后就不会有这么多东西了。
我们已经使用了
git进行对代码进行托管,那么,如果从仓库拉取最新数据时,是不是还是要重新配置
node_modules文件夹,这个就很麻烦了,我们可以备份一下
node_modules文件夹,将它
拷贝进工程就可以使用了。
.gitignore 语法
gitignore文件内包含了需要忽略或保留的文件的一些配置,灵活使用可以减少我们的工作量,但是里面的内容是什么意思呢?这边也给大家说下:
/:表示目录
*:为通配多个字符
?:通配单个字符
[]:包含单个字符的匹配列表
!:表示不忽略匹配到的文件和目录
// 示例
// 忽略ios文件夹下的所有内容
知道语法后,我们是不是就能看懂 工程中
gitignore文件的内容了,举个栗子:
# Xcode // 注释,说明这是 Xcode 配置 # build/ // 忽略 build 文件夹下所有内容 *.pbxuser // 忽略以 .pbxuser 为后缀的文件 !default.pbxuser // 除 default.pbxuser 文件外 *.mode1v3 // 忽略以 .mode1v3 为后缀的文件 !default.mode1v3 // 除 default.mode1v3 文件外 # node.js // 注释,说明这是 node 配置 # node_modules/ // 忽略 node_modules 文件夹内所有内容 npm-debug.log // 忽略 npm-debug.log yarn-error.log // 忽略 yarn-error.log
好了,就介绍到这里,希望可以帮到有需要的朋友,需要学习更多关于
git的内容,可以到 git介绍与使用 查看学习。
自定义详情cell
到这边可能有人会想,前面不是已经自定义了 cell了,为什么不直接在前面自定义的
cell里面再添加一些操作,使所有的
cell共用同一套组件?其实考虑到下面几点原因:
可以看到
半小时热门的cell和
三大模块的cell区别在于少了
优惠平台和数据提供平台这一栏的2个控件,其他地方是一样的,如果我们做到一起那也是可以的,但是这样会造成一个组件里面担负过多业务逻辑,在
数据量少是没关系,但是
数据量一多那么需要渲染的成本就会增加,也就会严重影响到性能。
如果我们分开使用,那么只是增加了组件,而且组件内部处理的业务逻辑变少了,这样也减少了我们后期的维护成本。
从结构上来说,这样也更为的清晰,减少开发人员之间的沟通成本。
首先,还是一样,我们先来创建
GDCommunalCell文件,并且我们将前面
自定义cell里面的内容
copy一下,放到这个文件中,并进行相应修改:
export default class GDCommunalCell extends Component { static propTypes = { image:PropTypes.string, title:PropTypes.string, mall:PropTypes.string, pubTime:PropTypes.string, fromSite:PropTypes.string, }; renderDate(pubTime, fromSite) { // 时间差的计算 let minute = 1000 * 60; // 1分钟 let hour = minute * 60; // 1小时 let day = hour * 24; // 1天 let week = day * 7; // 1周 let month = day * 30; // 1个月 // 计算时间差 let now = new Date().getTime(); // 获取当前时间 let diffValue = now - Date.parse(pubTime.replace(/-/gi, "/")); if (diffValue < 0) return; let monthC = diffValue/month; // 相差了几个月 let weekC = diffValue/week; // 相差几周 let dayC = diffValue/day; // 相差几天 let hourC = diffValue/hour // 相差几小时 let minuteC = diffValue/minute; // 相差几分钟 let result; if (monthC >= 1) { result = parseInt(monthC) + "月前"; }else if (weekC >= 1) { result = parseInt(weekC) + "周前"; }else if (dayC >= 1) { result = parseInt(dayC) + "天前"; }else if (hourC >= 1) { result = parseInt(hourC) + "小时前"; }else if (minuteC >= 1) { result = parseInt(minuteC) + "分钟前"; }else result = "刚刚"; return result + ' · ' + fromSite; } render() { return ( <View style={styles.container}> {/* 左边图片 */} <Image source={{uri:this.props.image === '' ? 'defaullt_thumb_83x83' : this.props.image}} style={styles.imageStyle} /> {/* 中间 */} <View style={styles.centerViewStyle}> {/* 标题 */} <View> <Text numberOfLines={3} style={styles.titleStyle}>{this.props.title}</Text> </View> {/* 详情 */} <View style={styles.detailViewStyle}> {/* 平台 */} <Text style={styles.detailMallStyle}>{this.props.mall}</Text> {/* 时间 + 来源 */} <Text style={styles.timeStyle}>{this.renderDate(this.props.pubTime, this.props.fromSite)}</Text> </View> </View> {/* 右边的箭头 */} <Image source={{uri:'icon_cell_rightArrow'}} style={styles.arrowStyle} /> </View> ); } } const styles = StyleSheet.create({ container: { flexDirection:'row', alignItems:'center', justifyContent:'space-between', backgroundColor:'white', height:100, width:width, borderBottomWidth:0.5, borderBottomColor:'gray', marginLeft:15 }, imageStyle: { width:70, height:70, }, centerViewStyle: { height:70, justifyContent:'space-around', }, titleStyle: { width:width * 0.65, }, detailViewStyle: { flexDirection:'row', justifyContent:'space-between', alignItems:'center' }, detailMallStyle: { fontSize:12, color:'green', }, timeStyle: { fontSize:12, color:'gray', }, arrowStyle: { width:10, height:10, marginRight:30, } });
OK,这边完成了,我们到首页中试一下是不是好使的。
详情页.gif
译注:
这边需要注意的是时间的转化,方式有很多,这边就以最直接的方式来计算。
还有需要注意的是在
JAVA中,获取到的月份是和我们现在的月份少
1个月的,这是因为
JAVA的月份是从
0开始,
Javascript也是一样的。
小时风云榜
这个模块和首页、海淘请求数据方面是类似的,不同在于这里需要我们根据不同的时间段来进行相对应的请求,这边参考视频吧,直接上完整代码。还是
copy首页或者海淘的代码,修改请求这部分代码:
export default class GDHourList extends Component { // 构造 constructor(props) { super(props); // 初始状态 this.state = { dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}), loaded:false, prompt:'', }; this.nexthourhour = ''; this.nexthourdate = ''; this.lasthourhour = ''; this.lasthourdate = ''; this.loadData = this.loadData.bind(this); } // 加载最新数据网络请求 loadData(resolve, date, hour) { let params = {}; if (date) { params = { "date" : date, "hour" : hour } } HTTPBase.get('http://guangdiu.com/api/getranklist.php', params) .then((responseData) => { // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(responseData.data), loaded:true, prompt:responseData.displaydate + responseData.rankhour + '点档' + '(' + responseData.rankduring + ')' }); // 关闭刷新动画 if (resolve !== undefined){ setTimeout(() => { resolve(); }, 1000); } // 暂时保留一些数据 this.nexthourhour = responseData.nexthourhour; this.nexthourdate = responseData.nexthourdate; this.lasthourhour = responseData.lasthourhour; this.lasthourdate = responseData.lasthourdate; }) .catch((error) => { }) } // 跳转到设置 pushToSettings() { this.props.navigator.push({ component:Settings, }) } // 返回中间标题 renderTitleItem() { return( <Image source={{uri:'navtitle_rank_106x20'}} style={styles.navbarTitleItemStyle} /> ); } // 返回右边按钮 renderRightItem() { return( <TouchableOpacity onPress={()=>{this.pushToSettings()}} > <Text style={styles.navbarRightItemStyle}>设置</Text> </TouchableOpacity> ); } // 根据网络状态决定是否渲染 listview renderListView() { if (this.state.loaded === false) { return( <NoDataView /> ); }else { return( <PullList onPullRelease={(resolve) => this.loadData(resolve)} dataSource={this.state.dataSource} renderRow={this.renderRow.bind(this)} showsHorizontalScrollIndicator={false} style={styles.listViewStyle} initialListSize={5} /> ); } } // 跳转到详情页 pushToDetail(value) { this.props.navigator.push({ component:CommunalDetail, params: { url: 'https://guangdiu.com/api/showdetail.php' + '?' + 'id=' + value } }) } // 返回每一行cell的样式 renderRow(rowData) { return( <TouchableOpacity onPress={() => this.pushToDetail(rowData.id)} > <CommunalCell image={rowData.image} title={rowData.title} mall={rowData.mall} pubTime={rowData.pubtime} fromSite={rowData.fromsite} /> </TouchableOpacity> ); } componentDidMount() { this.loadData(); } lastHour() { this.loadData(undefined, this.lasthourdate, this.lasthourhour); } nextHour() { this.loadData(undefined, this.nexthourdate, this.nexthourhour); } render() { return ( <View style={styles.container}> {/* 导航栏样式 */} <CommunalNavBar titleItem = {() => this.renderTitleItem()} rightItem = {() => this.renderRightItem()} /> {/* 提醒栏 */} <View style={styles.promptViewStyle}> <Text>{this.state.prompt}</Text> </View> {/* 根据网络状态决定是否渲染 listview */} {this.renderListView()} {/* 操作栏 */} <View style={styles.operationViewStyle}> <TouchableOpacity onPress={() => this.lastHour()} > <Text style={{marginRight:10, fontSize:17, color:'green'}}>{"< " + "上1小时"}</Text> </TouchableOpacity> <TouchableOpacity onPress={() => this.nextHour()} > <Text style={{marginLeft:10, fontSize:17, color:'green'}}>{"下1小时" + " >"}</Text> </TouchableOpacity> </View> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', backgroundColor: 'white', }, navbarTitleItemStyle: { width:106, height:20, marginLeft:50 }, navbarRightItemStyle: { fontSize:17, color:'rgba(123,178,114,1.0)', marginRight:15, }, promptViewStyle: { width:width, height:44, alignItems:'center', justifyContent:'center', backgroundColor:'rgba(251,251,251,1.0)', }, operationViewStyle: { width:width, height:44, flexDirection:'row', justifyContent:'center', alignItems:'center', }, });
小时风云榜.gif
首页筛选功能
从图中,我们可以看出筛选的下拉菜单类似 九宫格,这个我们在 React-Native
之 ListView使用 中有这样的案例,不清楚的可以再回去看一下,所以这边我们也使用
ListView实现。
在做之前,我们需要先配置一下,将压缩包内的
HomeSiftData文件和
HTSiftData文件放到工程内。
接着我们就要来完成这个筛选组件,代码如下:
export default class GDCommunalSiftMenu extends Component { static defaultProps = { removeModal:{}, loadSiftData:{} }; static propTypes = { data:PropTypes.array, }; // 构造 constructor(props) { super(props); // 初始状态 this.state = { dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}) }; } // 退出 popToHome(data) { this.props.removeModal(data); } // 点击事件 siftData(mall, cate) { this.props.loadSiftData(mall, cate); this.popToHome(false); } // 处理数据 loadData() { let data = []; for (let i = 0; i<this.props.data.length; i++) { data.push(this.props.data[i]); } // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(data), }) } renderRow(rowData) { return( <View style={styles.itemViewStyle}> <TouchableOpacity onPress={() => this.siftData(rowData.mall, rowData.cate)} > <View style={styles.itemViewStyle}> <Image source={{uri:rowData.image}} style={styles.itemImageStyle} /> <Text>{rowData.title}</Text> </View> </TouchableOpacity> </View> ) } componentDidMount() { this.loadData(); } render() { return( <TouchableOpacity onPress={() => this.popToHome(false)} activeOpacity={1} > <View style={styles.container}> {/* 菜单内容 */} <ListView dataSource={this.state.dataSource} renderRow={this.renderRow.bind(this)} contentContainerStyle={styles.contentViewStyle} initialListSize={16} /> </View> </TouchableOpacity> ) } } const styles = StyleSheet.create({ container: { width:width, height:height }, contentViewStyle: { flexDirection:'row', flexWrap:'wrap', width: width, top:Platform.OS === 'ios' ? 64 : 44, }, itemViewStyle: { width:width * 0.25, height:70, backgroundColor:'rgba(249,249,249,1.0)', justifyContent:'center', alignItems:'center' }, itemImageStyle: { width:40, height:40 } });
我们点击某个平台,就要进行相应的请求,然后重新渲染 首页的ListView ,方式如下:
// 加载最新数据网络请求 loadSiftData(mall, cate) { let params = {}; if (mall === "" && cate === "") { // 全部 this.loadData(undefined); return; } if (mall === "") { // cate 有值 params = { "cate" : cate }; }else { params = { "mall" : mall }; } HTTPBase.get('https://guangdiu.com/api/getlist.php', params) .then((responseData) => { // 清空数组 this.data = []; // 拼接数据 this.data = this.data.concat(responseData.data); // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); // 存储数组中最后一个元素的id let cnlastID = responseData.data[responseData.data.length - 1].id; AsyncStorage.setItem('cnlastID', cnlastID.toString()); }) .catch((error) => { }) }
至此,首页的筛选功能也完成了,在
海淘模块内也使用一下就可以了。
筛选功能.gif
搜索模块
点击 首页或者海淘 右侧按钮,我们跳转到搜索模块,解析图奉上:根据解析图我们添加相应子组件。
export default class GDHome extends Component { // 构造 constructor(props) { super(props); // 初始状态 this.state = { dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}), loaded:false, isModal:false }; this.data = []; this.changeText = ''; this.loadData = this.loadData.bind(this); this.loadMore = this.loadMore.bind(this); } // 加载最新数据网络请求 loadData(resolve) { if (!this.changeText) return; let params = { "q" : this.changeText }; HTTPBase.get('http://guangdiu.com/api/getresult.php', params) .then((responseData) => { // 清空数组 this.data = []; // 拼接数据 this.data = this.data.concat(responseData.data); // 重新渲染 this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); // 关闭刷新动画 if (resolve !== undefined){ setTimeout(() => { resolve(); }, 1000); } // 存储数组中最后一个元素的id let searchLastID = responseData.data[responseData.data.length - 1].id; AsyncStorage.setItem('searchLastID', searchLastID.toString()); }) .catch((error) => { }) } // 加载更多数据的网络请求 loadMoreData(value) { let params = { "q" : this.changeText, "sinceid" : value }; HTTPBase.get('http://guangdiu.com/api/getresult.php', params) .then((responseData) => { // 拼接数据 this.data = this.data.concat(responseData.data); this.setState({ dataSource: this.state.dataSource.cloneWithRows(this.data), loaded:true, }); // 存储数组中最后一个元素的id let searchLastID = responseData.data[responseData.data.length - 1].id; AsyncStorage.setItem('searchLastID', searchLastID.toString()); }) .catch((error) => { }) } // 加载更多数据操作 loadMore() { // 读取id AsyncStorage.getItem('searchLastID') .then((value) => { // 数据加载操作 this.loadMoreData(value); }) } // 返回 pop() { // 回收键盘 dismissKeyboard(); this.props.navigator.pop(); } // 返回左边按钮 renderLeftItem() { return( <TouchableOpacity onPress={() => {this.pop()}} > <View style={{flexDirection:'row', alignItems:'center'}}> <Image source={{uri:'back'}} style={styles.navbarLeftItemStyle} /> <Text>返回</Text> </View> </TouchableOpacity> ); } // 返回中间按钮 renderTitleItem() { return( <Text style={styles.navbarTitleItemStyle}>搜索全网折扣</Text> ); } // ListView尾部 renderFooter() { return ( <View style={{height: 100}}> <ActivityIndicator /> </View> ); } // 根据网络状态决定是否渲染 listview renderListView() { if (this.state.loaded === false) { return( <NoDataView /> ); }else { return( <PullList onPullRelease={(resolve) => this.loadData(resolve)} dataSource={this.state.dataSource} renderRow={this.renderRow.bind(this)} showsHorizontalScrollIndicator={false} style={styles.listViewStyle} initialListSize={5} renderHeader={this.renderHeader} onEndReached={this.loadMore} onEndReachedThreshold={60} renderFooter={this.renderFooter} /> ); } } // 跳转到详情页 pushToDetail(value) { this.props.navigator.push({ component:CommunalDetail, params: { url: 'https://guangdiu.com/api/showdetail.php' + '?' + 'id=' + value } }) } // 返回每一行cell的样式 renderRow(rowData) { return( <TouchableOpacity onPress={() => this.pushToDetail(rowData.id)} > <CommunalCell image={rowData.image} title={rowData.title} mall={rowData.mall} pubTime={rowData.pubtime} fromSite={rowData.fromsite} /> </TouchableOpacity> ); } render() { return ( <View style={styles.container}> {/* 导航栏样式 */} <CommunalNavBar leftItem = {() => this.renderLeftItem()} titleItem = {() => this.renderTitleItem()} /> {/* 顶部工具栏 */} <View style={styles.toolsViewStyle} > {/* 左边 */} <View style={styles.inputViewStyle} > <Image source={{uri:'search_icon_20x20'}} style={styles.searchImageStyle} /> <TextInput style={styles.textInputStyle} keyboardType="default" placeholder="请输入搜索商品关键字" placeholderTextColor='gray' autoFocus={true} clearButtonMode="while-editing" onChangeText={(text) => {this.changeText = text}} onEndEditing={() => this.loadData()} /> </View> {/* 右边 */} <View style={{marginRight:10}}> <TouchableOpacity onPress={() => this.pop()} > <Text style={{color:'green'}}>取消</Text> </TouchableOpacity> </View> </View> {/* 根据网络状态决定是否渲染 listview */} {this.renderListView()} </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', backgroundColor: 'white', }, navbarLeftItemStyle: { width:20, height:20, marginLeft:15, }, navbarTitleItemStyle: { fontSize:17, color:'black', marginRight:50 }, navbarRightItemStyle: { width:20, height:20, marginRight:15, }, toolsViewStyle: { width:width, height:44, flexDirection:'row', alignItems:'center', justifyContent:'space-between', }, inputViewStyle: { height:35, flexDirection:'row', alignItems:'center', justifyContent:'center', backgroundColor:'rgba(239,239,241,1.0)', marginLeft:10, borderRadius:5 }, searchImageStyle: { width:15, height:15, marginLeft:8 }, textInputStyle: { width:width * 0.75, height:35, marginLeft:8 }, listViewStyle: { width:width, }, });
搜索页面.gif
设置
在 小时风云榜 模块,我们还有设置模块没有做,这边也快速来做一下从图中可以看出,这又是不一样的 cell样式 ,不过通过前面的经验,知道怎么来自定义了吧:
export default class GDSettingsCell extends Component { static propTypes = { leftTitle:PropTypes.string, isShowSwitch:PropTypes.bool, }; // 构造 constructor(props) { super(props); // 初始状态 this.state = { isOn:false, }; } // 返回需要的组件 renderRightContent() { let component; if (this.props.isShowSwitch) { // 显示 Switch 按钮 component = <Switch value={this.state.isOn} onValueChange={() => {this.setState({isOn: !this.state.isOn})}} /> }else { component = <Image source={{uri:'icon_cell_rightArrow'}} style={styles.arrowStyle} /> } return( component ) } render() { return( <View style={styles.container}> {/* 左边 */} <View> <Text>{this.props.leftTitle}</Text> </View> {/* 右边 */} <View style={styles.rightViewStyle}> {this.renderRightContent()} </View> </View> ) } } const styles = StyleSheet.create({ container: { flex:1, flexDirection:'row', height:Platform.OS === 'ios' ? 44 : 36, justifyContent:'space-between', alignItems:'center', borderBottomColor:'gray', borderBottomWidth:0.5, marginLeft:15, }, rightViewStyle:{ marginRight:15, }, arrowStyle: { width:10, height:10, } });
自定义完成,来试下好不好用:
export default class GDSettings extends Component { // 返回 pop() { this.props.navigator.pop(); } // 返回左边按钮 renderLeftItem() { return( <TouchableOpacity onPress={() => {this.pop()}} > <View style={{flexDirection:'row', alignItems:'center'}}> <Image source={{uri:'back'}} style={styles.navbarLeftItemStyle} /> <Text>返回</Text> </View> </TouchableOpacity> ); } // 返回中间按钮 renderTitleItem() { return( <Text style={styles.navbarTitleItemStyle}>设置</Text> ); } render() { return( <View style={styles.container}> {/* 导航栏样式 */} <CommunalNavBar leftItem = {() => this.renderLeftItem()} titleItem = {() => this.renderTitleItem()} /> {/* 内容 */} <ScrollView style={styles.scollViewStyle} > {/* 第一个cell */} <SettingsCell leftTitle="淘宝天猫快捷下单" isShowSwitch={true} /> {/* 第二个cell */} <SettingsCell leftTitle="清理图片缓存" isShowSwitch={false} /> </ScrollView> </View> ) } } const styles = StyleSheet.create({ container: { flex:1 }, navbarLeftItemStyle: { width:20, height:20, marginLeft:15, }, navbarTitleItemStyle: { fontSize:17, color:'black', marginRight:50 }, scollViewStyle: { backgroundColor:'white', }, });
设置.gif
相关文章推荐
- React Native商城项目实战06 - 设置安卓中的启动页
- React Native商城项目实战15 - 首页购物中心
- React-Native 之 项目实战(二)
- React-Native 之 项目实战(五)
- React-Native 之 项目实战(四)
- React Native商城项目实战07 - 设置“More”界面导航条
- React-Native 之 项目实战(一)
- React-Native 之 项目实战(三)
- React-Native项目实战技术分享
- React-Native 之 项目实战(五)
- React Native商城项目实战13 - 首页中间上部分内容
- React Native实战项目企业通信录(含视频教程)-环境搭建
- ReactNative For Android 项目实战总结
- React-Native 之 项目实战(三)
- React Native商城项目实战03 - 包装Navigator
- React Native商城项目实战14 - 首页中间下部分
- 一个上架了的React Native项目实战总结
- 一个上架了的React Native项目实战总结
- React-Native 之 项目实战(四)
- React-Native 之 项目实战(三)