您的位置:首页 > Web前端 > React

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: