React-Native 之 项目实战(四)

时间:2022-09-30 11:14:03

前言


  • 本文有配套视频,可以酌情观看。
  • 文中内容因各人理解不同,可能会有所偏差,欢迎朋友们联系我。
  • 文中所有内容仅供学习交流之用,不可用于商业用途,如因此引起的相关法律法规责任,与我无关。
  • 如文中内容对您造成不便,烦请联系 277511806@qq.com 处理,谢谢。
  • 转载麻烦注明出处,谢谢。

数据持久化


  • 数据持久化是移动端的一个重要部分,刚发现 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,
    });
    })
    }
  • 到这里,我们就完成了 数据本地持久化 并且成功将数据取出,这边数据持久化的实验就完成了。

React-Native 之 项目实战(四)

译注:

  • 有关 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,这边完成了,我们到首页中试一下是不是好使的。

React-Native 之 项目实战(四)

译注:

  • 这边需要注意的是时间的转化,方式有很多,这边就以最直接的方式来计算。

  • 还有需要注意的是在 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',
},
});

React-Native 之 项目实战(四)

首页筛选功能


  • 从图中,我们可以看出筛选的下拉菜单类似 九宫格,这个我们在 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) => { })
}
  • 至此,首页的筛选功能也完成了,在 海淘模块 内也使用一下就可以了。

React-Native 之 项目实战(四)

搜索模块


  • 点击 首页或者海淘 右侧按钮,我们跳转到搜索模块,解析图奉上:

  • 根据解析图我们添加相应子组件。

    	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,
    },
    });

React-Native 之 项目实战(四)

设置


  • 小时风云榜 模块,我们还有设置模块没有做,这边也快速来做一下

  • 从图中可以看出,这又是不一样的 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',
    },
    });

React-Native 之 项目实战(四)

React-Native 之 项目实战(四)的更多相关文章

  1. React Native 之 项目实战(一)

    前言 本文有配套视频,可以酌情观看. 文中内容因各人理解不同,可能会有所偏差,欢迎朋友们联系我. 文中所有内容仅供学习交流之用,不可用于商业用途,如因此引起的相关法律法规责任,与我无关. 如文中内容对 ...

  2. React Native商城项目实战04 - 封装TabNavigator&period;Item的创建

    1.Main.js /** * 主页面 */ import React, { Component } from 'react'; import { StyleSheet, Text, View, Im ...

  3. React Native商城项目实战02 - 主要框架部分&lpar;tabBar&rpar;

    1.安装插件,cd到项目根目录下执行: $ npm i react-native-tab-navigator --save 2.主框架文件Main.js /** * 主页面 */ import Rea ...

  4. React Native商城项目实战01 - 初始化设置

    1.创建项目 $ react-native init BuyDemo 2.导入图片资源 安卓:把文件夹放到/android/app/src/main/res/目录下,如图: iOS: Xcode打开工 ...

  5. React Native商城项目实战07 - 设置&OpenCurlyDoubleQuote;More”界面导航条

    1.More/More.js /** * 更多 */ import React, { Component } from 'react'; import { AppRegistry, StyleShee ...

  6. React Native商城项目实战05 - 设置首页的导航条

    1.Home.js /** * 首页 */ import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Te ...

  7. React Native商城项目实战06 - 设置安卓中的启动页

    1.Main 目录下新建LaunchImage.js: /** * 启动页 */ import React, { Component } from 'react'; import { AppRegis ...

  8. React Native商城项目实战03 - 包装Navigator

    1.在Home目录下新建首页详细页HomeDetail.js /** * 首页详情页 */ import React, { Component } from 'react'; import { App ...

  9. React Native商城项目实战16 - 购物中心详细页

    逻辑分析: 首页(Home)加载的购物中心组件(ShopCenter),传递url数据: ShopCenter里根据url加载购物中心详细页组件(ShopCenterDetail), ShopCent ...

  10. React Native商城项目实战15 - 首页购物中心

    1.公共的标题栏组件TitleCommonCell.js /** * 首页购物中心 */ import React, { Component } from 'react'; import { AppR ...

随机推荐

  1. YTU 3027&colon; 哈夫曼编码

    原文链接:https://www.dreamwings.cn/ytu3027/2899.html 3027: 哈夫曼编码 时间限制: 1 Sec  内存限制: 128 MB 提交: 2  解决: 2 ...

  2. 吐槽THINKPHP5命令行

    thinkphp,作为国内开源框架,一直在使用和学习. 但是实在忍不住想要吐槽一下他的开发文档,和 对初学者的不友好,建议刚接触MVC思想的人 还是尽量去使用其他框架当入门. 现在来吐槽一下think ...

  3. mysql中字符集的比较

    Mysql中utf8_general_ci与utf8_unicode_ci有什么区别呢? 在编程语言中,通常用unicode对中文字符做处理,防止出现乱码,那么在MySQL里,为什么大家都使用utf8 ...

  4. 使用gson在解析unicode时遇到的问题

    之前在用gson解析的时候未记录下来,所以今天做一个小的总结, 比如遇到像这种"\u003d"的unicode的字符,我们想解码这个字符,用gson可以这样表达 Gson gson ...

  5. ArrayList集合

    //在使用ArrayList时别忘了引用命名空间 using System.Collections;//首先得导入命名空间 //01.添加方法 add方法 //告诉内存,我要存储内容 ArrayLis ...

  6. Power Designer - 反向获取数据库物理模型时Unable to list the users 异常

    解决方案: 菜单栏 -> Database -> Change Current DBMS ,给DBMS选择Oracle Version 9i2.

  7. Currency System in Geraldion &lpar;Codeforces 560A&rpar;

    A  Currency System in Geraldion Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64 ...

  8. 妈蛋:kinMaxShow旋转木马异常,WebUploader图片上传坑爹,图像被压缩

    今天晚上在改造轮播图. 原来的代码是这种: <div> <img src="${static}/image/index/banner/`.jpg" /> & ...

  9. 洛谷 P1111 修复公路

    题目链接 https://www.luogu.org/problemnew/show/P1111 以后只发题目链接!!! 题目大意 给出A地区的村庄数N,和公路数M,公路是双向的.并告诉你每条公路的连 ...

  10. Windows下搭建kafka运行环境

    完整解决方案请参考: Setting Up and Running Apache Kafka on Windows OS   在环境搭建过程中遇到两个问题,在这里先列出来,以方便查询: 1. \Jav ...