React Native入门——布局实践:开发京东客户端首页(一

有了一些对React Native开发的简单了解,让我们从实战出发,一起来构建一个简单的京东客户端。

这个客户端是仿照之前版本的京东客户端开发的Android版应用,来源于CSDN上的一位分享者,再次向他表示感谢!

本文会对京东客户端首页的布局进行简单的分析,并对搜索框部分的开发进行介绍,其他内容在后面的文章中继续介绍。


后继文章:

React Native入门——布局实践:开发京东客户端首页(二)TabBar的构建

欢迎交流!


1.京东客户端首页布局分析


如图所示,京东客户端首页布局基本分为以下几个部分:

(1)头部:搜索栏,由京东logo、搜索输入框和扫描按钮组成

扫描二维码关注公众号,回复: 1086149 查看本文章

(2)内容部分:父级元素为ListView或ScrollView,可滑动,其中包括一个轮播图、一组功能按钮和秒杀、拍卖商品列表

(3)底部:TabBar,用于切换页面


2.创建工程和相关文件、目录

首先,我们利用react-native init命令创建一个名为JdApp(当然也可以自己起)的React Native工程(具体操作请参考: http://blog.csdn.net/yuanguozhengjust/article/details/50468050),项目结构如下图所示:

根据我们刚才对京东客户端结构的分析,目前可以先新建几个文件,用于拆分代码,具体方案如下:
images目录:用于存放相关图片
Header.js:用于构建头部搜索栏(本文主要介绍此文件中的内容)
MainScreen.js:主屏幕文件,起到最外层控制作用
HomePage.js:首页文件,用于构建轮播图、功能按钮、特价列表等

3.调研相关控件

目前App中需要用到轮播图、Tab这两个高级控件,而React Native原生的控件仅有TabBarIOS可供iOS平台使用,不能满足我们的需求,根据在Github上搜索的结果,我们可以选用以下几个第三方控件进行开发:
react-native-viewpager:可实现轮播图效果,地址: https://github.com/race604/react-native-viewpager
react-native-tab-navigator:可用于构建Tab,并可以轻松地进行页面切换,地址: https://github.com/exponentjs/react-native-tab-navigator
有兴趣的读者,还可以自行构建Tab和Swiper这种控件,做一个符合项目需求的控件并不难,但想要扩展性、通用性更强,不是一件容易的事情。

4.分析搜索栏的基本布局

头部的搜索栏,分为三个部分:logo、输入框、扫码按钮。
其中,logo可以使用Image控件
输入框稍复杂,外层是一个圆角的View,其内部左侧是一个Image,用于展示放大镜Icon,中间为一个TextInput控件用于输入,右侧为一个Image,用于展示语音搜索Icon
右侧扫码按钮也比较简单,仅为一个Image
那么根据FlexBox布局原则,可以按以下方式进行布局:

这里特别说明一下,由于React Native不支持自动计算Image等View的大小(参见: http://facebook.github.io/react-native/docs/images.html#why-not-automatically-size-everything),所以我们不能像Android的XML那样,设置为wrap_content,必须为Image指定宽度和高度,而由于React Native使用的是类似Android dp的像素,所以请根据设计图的尺寸自行计算,这里推荐一个网站: https://pixplicity.com/dp-px-converter/

5.代码实现

确定好了搜索栏的布局,那么我们就开始具体使用JavaScript代码进行实现,首先新建一个Header.js的文件,并引入我们需要用到的控件
[javascript] view plain copy
print ?
  1. ’use strict’;  
  2.   
  3. import React, {  
  4.     Component  
  5.     Image,  
  6.     TextInput  
  7.     View,  
  8.     StyleSheet  
  9. } from ’react-native’;  
'use strict';

import React, {
    Component
    Image,
    TextInput
    View,
    StyleSheet
} from 'react-native';
接着声明类和样式,之所以使用export,是因为要在其他类中使用(如:MainScreen)
[javascript] view plain copy
print ?
  1. export default class Header extends Component {  
  2.   
  3. }  
  4.   
  5. const styles = StyleSheet.create({  
  6.       
  7. });  
export default class Header extends Component {

}

const styles = StyleSheet.create({

});
然后在Header类的render()方法中编写JSX代码,在StyleSheet.create()方法中,编写类CSS的样式,如下:
[javascript] view plain copy
print ?
  1. export default class Header extends Component {  
  2.     render() {  
  3.         return (  
  4.             <View style={styles.container}>  
  5.   
  6.             </View>  
  7.         )  
  8.     }  
  9. }  
  10.   
  11. const styles = StyleSheet.create({  
  12.     container: {  
  13.         flexDirection: ’row’,  
  14.         paddingLeft: 10,  
  15.         paddingRight: 10,  
  16.         paddingTop: Platform.OS === ’ios’ ? 20 : 0,   // 处理iOS状态栏  
  17.         height: Platform.OS === ’ios’ ? 68 : 48,   // 处理iOS状态栏  
  18.         backgroundColor: ’#d74047’,  
  19.         alignItems: ’center’  
  20.     }});  
export default class Header extends Component {
    render() {
        return (
            <View style={styles.container}>

            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flexDirection: 'row',
        paddingLeft: 10,
        paddingRight: 10,
        paddingTop: Platform.OS === 'ios' ? 20 : 0,   // 处理iOS状态栏
        height: Platform.OS === 'ios' ? 68 : 48,   // 处理iOS状态栏
        backgroundColor: '#d74047',
        alignItems: 'center'
    }});
然后我们在模拟器或者真机上跑一下,看看效果
嗯,不错,貌似是我们想要的效果!接着把图片资源导入项目中去,很简单,只需要在目录创建文件夹,将图片复制进去,WebStorm等IDE即可自动识别

根据我们之前的分析,完成样式表的设计,如下:

[javascript] view plain copy
print ?
  1. const styles = StyleSheet.create({  
  2.     container: {  
  3.         flexDirection: ’row’,   // 水平排布  
  4.         paddingLeft: 10,  
  5.         paddingRight: 10,  
  6.         paddingTop: Platform.OS === ’ios’ ? 20 : 0,  // 处理iOS状态栏  
  7.         height: Platform.OS === ’ios’ ? 68 : 48,   // 处理iOS状态栏  
  8.         backgroundColor: ’#d74047’,  
  9.         alignItems: ’center’  // 使元素垂直居中排布, 当flexDirection为column时, 为水平居中  
  10.     },  
  11.     logo: {  
  12.         height: 24,  
  13.         width: 64,  
  14.         resizeMode: ’stretch’  // 设置拉伸模式  
  15.     },  
  16.     searchBox: {  
  17.         height: 30,  
  18.         flexDirection: ’row’,  
  19.         flex: 1,  // 类似于android中的layout_weight,设置为1即自动拉伸填充  
  20.         borderRadius: 5,  // 设置圆角边  
  21.         backgroundColor: ’white’,  
  22.         alignItems: ’center’,  
  23.         marginLeft: 8,  
  24.         marginRight: 12  
  25.     },  
  26.     scanIcon: {  
  27.         height: 26.7,  
  28.         width: 26.7,  
  29.         resizeMode: ’stretch’  
  30.     },  
  31.     searchIcon: {  
  32.         marginLeft: 6,  
  33.         marginRight: 6,  
  34.         width: 16.7,  
  35.         height: 16.7,  
  36.         resizeMode: ’stretch’  
  37.     },  
  38.     voiceIcon: {  
  39.         marginLeft: 5,  
  40.         marginRight: 8,  
  41.         width: 15,  
  42.         height: 20,  
  43.         resizeMode: ’stretch’  
  44.     },  
  45.     inputText: {  
  46.         flex: 1,  
  47.         backgroundColor: ’transparent’,  
  48.         fontSize: 14  
  49.     }  
  50. });  
const styles = StyleSheet.create({
    container: {
        flexDirection: 'row',   // 水平排布
        paddingLeft: 10,
        paddingRight: 10,
        paddingTop: Platform.OS === 'ios' ? 20 : 0,  // 处理iOS状态栏
        height: Platform.OS === 'ios' ? 68 : 48,   // 处理iOS状态栏
        backgroundColor: '#d74047',
        alignItems: 'center'  // 使元素垂直居中排布, 当flexDirection为column时, 为水平居中
    },
    logo: {
        height: 24,
        width: 64,
        resizeMode: 'stretch'  // 设置拉伸模式
    },
    searchBox: {
        height: 30,
        flexDirection: 'row',
        flex: 1,  // 类似于android中的layout_weight,设置为1即自动拉伸填充
        borderRadius: 5,  // 设置圆角边
        backgroundColor: 'white',
        alignItems: 'center',
        marginLeft: 8,
        marginRight: 12
    },
    scanIcon: {
        height: 26.7,
        width: 26.7,
        resizeMode: 'stretch'
    },
    searchIcon: {
        marginLeft: 6,
        marginRight: 6,
        width: 16.7,
        height: 16.7,
        resizeMode: 'stretch'
    },
    voiceIcon: {
        marginLeft: 5,
        marginRight: 8,
        width: 15,
        height: 20,
        resizeMode: 'stretch'
    },
    inputText: {
        flex: 1,
        backgroundColor: 'transparent',
        fontSize: 14
    }
});
请认真注意上面代码中的注释,标有注释的地方,即为和普通iOS、Android开发不太一样的地方!
由于我们已经将父级元素的排布方向改为水平,所以我们只需将需要展现的元素放入<View>的子元素即可,如下代码所示:
[javascript] view plain copy
print ?
  1. export default class Header extends Component {  
  2.     render() {  
  3.         return (  
  4.             <View style={styles.container}>  
  5.                 <Image source={require(’./images/header/header_logo.png’)} style={styles.logo}/>  
  6.                 <View style={styles.searchBox}>  
  7.                     <Image source={require(’./images/header/icon_search.png’)} style={styles.searchIcon}/>  
  8.                     <TextInput  
  9.                         keyboardType=’web-search’  
  10.                         placeholder=’搜索京东商品/店铺’  
  11.                         style={styles.inputText}/>  
  12.                     <Image source={require(’./images/header/icon_voice.png’)} style={styles.voiceIcon}/>  
  13.                 </View>  
  14.                 <Image source={require(’./images/header/icon_qr.png’)} style={styles.scanIcon}/>  
  15.             </View>  
  16.         )  
  17.     }  
  18. }  
export default class Header extends Component {
    render() {
        return (
            <View style={styles.container}>
                <Image source={require('./images/header/header_logo.png')} style={styles.logo}/>
                <View style={styles.searchBox}>
                    <Image source={require('./images/header/icon_search.png')} style={styles.searchIcon}/>
                    <TextInput
                        keyboardType='web-search'
                        placeholder='搜索京东商品/店铺'
                        style={styles.inputText}/>
                    <Image source={require('./images/header/icon_voice.png')} style={styles.voiceIcon}/>
                </View>
                <Image source={require('./images/header/icon_qr.png')} style={styles.scanIcon}/>
            </View>
        )
    }
}
需要注意的是
1.style的使用,当使用StyleSheet创建的样式时,外层只需要一层{},而直接声明需要再加一层,即直接声明了匿名变量
2.Image的source可以使用网络图片或本地资源,使用本地资源时,类似require.js的包引用,而使用网络资源时,使用方法如下:source={{uri:’http://xxxxxxx’}}
3.TextInput的键盘类型可以使用keyboardType进行设置,占位字符使用placeholder设置,具体请参见官方文档

这时在模拟器或真机上Reload JS一下,就可以看到我们想要的界面了:

        </div>
            </div>

有了一些对React Native开发的简单了解,让我们从实战出发,一起来构建一个简单的京东客户端。

这个客户端是仿照之前版本的京东客户端开发的Android版应用,来源于CSDN上的一位分享者,再次向他表示感谢!

本文会对京东客户端首页的布局进行简单的分析,并对搜索框部分的开发进行介绍,其他内容在后面的文章中继续介绍。


后继文章:

React Native入门——布局实践:开发京东客户端首页(二)TabBar的构建

欢迎交流!


1.京东客户端首页布局分析


如图所示,京东客户端首页布局基本分为以下几个部分:

(1)头部:搜索栏,由京东logo、搜索输入框和扫描按钮组成

(2)内容部分:父级元素为ListView或ScrollView,可滑动,其中包括一个轮播图、一组功能按钮和秒杀、拍卖商品列表

(3)底部:TabBar,用于切换页面


2.创建工程和相关文件、目录

首先,我们利用react-native init命令创建一个名为JdApp(当然也可以自己起)的React Native工程(具体操作请参考: http://blog.csdn.net/yuanguozhengjust/article/details/50468050),项目结构如下图所示:

根据我们刚才对京东客户端结构的分析,目前可以先新建几个文件,用于拆分代码,具体方案如下:
images目录:用于存放相关图片
Header.js:用于构建头部搜索栏(本文主要介绍此文件中的内容)
MainScreen.js:主屏幕文件,起到最外层控制作用
HomePage.js:首页文件,用于构建轮播图、功能按钮、特价列表等

3.调研相关控件

目前App中需要用到轮播图、Tab这两个高级控件,而React Native原生的控件仅有TabBarIOS可供iOS平台使用,不能满足我们的需求,根据在Github上搜索的结果,我们可以选用以下几个第三方控件进行开发:
react-native-viewpager:可实现轮播图效果,地址: https://github.com/race604/react-native-viewpager
react-native-tab-navigator:可用于构建Tab,并可以轻松地进行页面切换,地址: https://github.com/exponentjs/react-native-tab-navigator
有兴趣的读者,还可以自行构建Tab和Swiper这种控件,做一个符合项目需求的控件并不难,但想要扩展性、通用性更强,不是一件容易的事情。

4.分析搜索栏的基本布局

头部的搜索栏,分为三个部分:logo、输入框、扫码按钮。
其中,logo可以使用Image控件
输入框稍复杂,外层是一个圆角的View,其内部左侧是一个Image,用于展示放大镜Icon,中间为一个TextInput控件用于输入,右侧为一个Image,用于展示语音搜索Icon
右侧扫码按钮也比较简单,仅为一个Image
那么根据FlexBox布局原则,可以按以下方式进行布局:

这里特别说明一下,由于React Native不支持自动计算Image等View的大小(参见: http://facebook.github.io/react-native/docs/images.html#why-not-automatically-size-everything),所以我们不能像Android的XML那样,设置为wrap_content,必须为Image指定宽度和高度,而由于React Native使用的是类似Android dp的像素,所以请根据设计图的尺寸自行计算,这里推荐一个网站: https://pixplicity.com/dp-px-converter/

5.代码实现

确定好了搜索栏的布局,那么我们就开始具体使用JavaScript代码进行实现,首先新建一个Header.js的文件,并引入我们需要用到的控件
[javascript] view plain copy
print ?
  1. ’use strict’;  
  2.   
  3. import React, {  
  4.     Component  
  5.     Image,  
  6.     TextInput  
  7.     View,  
  8.     StyleSheet  
  9. } from ’react-native’;  
'use strict';

import React, {
    Component
    Image,
    TextInput
    View,
    StyleSheet
} from 'react-native';
接着声明类和样式,之所以使用export,是因为要在其他类中使用(如:MainScreen)
[javascript] view plain copy
print ?
  1. export default class Header extends Component {  
  2.   
  3. }  
  4.   
  5. const styles = StyleSheet.create({  
  6.       
  7. });  
export default class Header extends Component {

}

const styles = StyleSheet.create({

});
然后在Header类的render()方法中编写JSX代码,在StyleSheet.create()方法中,编写类CSS的样式,如下:
[javascript] view plain copy
print ?
  1. export default class Header extends Component {  
  2.     render() {  
  3.         return (  
  4.             <View style={styles.container}>  
  5.   
  6.             </View>  
  7.         )  
  8.     }  
  9. }  
  10.   
  11. const styles = StyleSheet.create({  
  12.     container: {  
  13.         flexDirection: ’row’,  
  14.         paddingLeft: 10,  
  15.         paddingRight: 10,  
  16.         paddingTop: Platform.OS === ’ios’ ? 20 : 0,   // 处理iOS状态栏  
  17.         height: Platform.OS === ’ios’ ? 68 : 48,   // 处理iOS状态栏  
  18.         backgroundColor: ’#d74047’,  
  19.         alignItems: ’center’  
  20.     }});  
export default class Header extends Component {
    render() {
        return (
            <View style={styles.container}>

            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flexDirection: 'row',
        paddingLeft: 10,
        paddingRight: 10,
        paddingTop: Platform.OS === 'ios' ? 20 : 0,   // 处理iOS状态栏
        height: Platform.OS === 'ios' ? 68 : 48,   // 处理iOS状态栏
        backgroundColor: '#d74047',
        alignItems: 'center'
    }});
然后我们在模拟器或者真机上跑一下,看看效果
嗯,不错,貌似是我们想要的效果!接着把图片资源导入项目中去,很简单,只需要在目录创建文件夹,将图片复制进去,WebStorm等IDE即可自动识别

根据我们之前的分析,完成样式表的设计,如下:

[javascript] view plain copy
print ?
  1. const styles = StyleSheet.create({  
  2.     container: {  
  3.         flexDirection: ’row’,   // 水平排布  
  4.         paddingLeft: 10,  
  5.         paddingRight: 10,  
  6.         paddingTop: Platform.OS === ’ios’ ? 20 : 0,  // 处理iOS状态栏  
  7.         height: Platform.OS === ’ios’ ? 68 : 48,   // 处理iOS状态栏  
  8.         backgroundColor: ’#d74047’,  
  9.         alignItems: ’center’  // 使元素垂直居中排布, 当flexDirection为column时, 为水平居中  
  10.     },  
  11.     logo: {  
  12.         height: 24,  
  13.         width: 64,  
  14.         resizeMode: ’stretch’  // 设置拉伸模式  
  15.     },  
  16.     searchBox: {  
  17.         height: 30,  
  18.         flexDirection: ’row’,  
  19.         flex: 1,  // 类似于android中的layout_weight,设置为1即自动拉伸填充  
  20.         borderRadius: 5,  // 设置圆角边  
  21.         backgroundColor: ’white’,  
  22.         alignItems: ’center’,  
  23.         marginLeft: 8,  
  24.         marginRight: 12  
  25.     },  
  26.     scanIcon: {  
  27.         height: 26.7,  
  28.         width: 26.7,  
  29.         resizeMode: ’stretch’  
  30.     },  
  31.     searchIcon: {  
  32.         marginLeft: 6,  
  33.         marginRight: 6,  
  34.         width: 16.7,  
  35.         height: 16.7,  
  36.         resizeMode: ’stretch’  
  37.     },  
  38.     voiceIcon: {  
  39.         marginLeft: 5,  
  40.         marginRight: 8,  
  41.         width: 15,  
  42.         height: 20,  
  43.         resizeMode: ’stretch’  
  44.     },  
  45.     inputText: {  
  46.         flex: 1,  
  47.         backgroundColor: ’transparent’,  
  48.         fontSize: 14  
  49.     }  
  50. });  
const styles = StyleSheet.create({
    container: {
        flexDirection: 'row',   // 水平排布
        paddingLeft: 10,
        paddingRight: 10,
        paddingTop: Platform.OS === 'ios' ? 20 : 0,  // 处理iOS状态栏
        height: Platform.OS === 'ios' ? 68 : 48,   // 处理iOS状态栏
        backgroundColor: '#d74047',
        alignItems: 'center'  // 使元素垂直居中排布, 当flexDirection为column时, 为水平居中
    },
    logo: {
        height: 24,
        width: 64,
        resizeMode: 'stretch'  // 设置拉伸模式
    },
    searchBox: {
        height: 30,
        flexDirection: 'row',
        flex: 1,  // 类似于android中的layout_weight,设置为1即自动拉伸填充
        borderRadius: 5,  // 设置圆角边
        backgroundColor: 'white',
        alignItems: 'center',
        marginLeft: 8,
        marginRight: 12
    },
    scanIcon: {
        height: 26.7,
        width: 26.7,
        resizeMode: 'stretch'
    },
    searchIcon: {
        marginLeft: 6,
        marginRight: 6,
        width: 16.7,
        height: 16.7,
        resizeMode: 'stretch'
    },
    voiceIcon: {
        marginLeft: 5,
        marginRight: 8,
        width: 15,
        height: 20,
        resizeMode: 'stretch'
    },
    inputText: {
        flex: 1,
        backgroundColor: 'transparent',
        fontSize: 14
    }
});
请认真注意上面代码中的注释,标有注释的地方,即为和普通iOS、Android开发不太一样的地方!
由于我们已经将父级元素的排布方向改为水平,所以我们只需将需要展现的元素放入<View>的子元素即可,如下代码所示:
[javascript] view plain copy
print ?
  1. export default class Header extends Component {  
  2.     render() {  
  3.         return (  
  4.             <View style={styles.container}>  
  5.                 <Image source={require(’./images/header/header_logo.png’)} style={styles.logo}/>  
  6.                 <View style={styles.searchBox}>  
  7.                     <Image source={require(’./images/header/icon_search.png’)} style={styles.searchIcon}/>  
  8.                     <TextInput  
  9.                         keyboardType=’web-search’  
  10.                         placeholder=’搜索京东商品/店铺’  
  11.                         style={styles.inputText}/>  
  12.                     <Image source={require(’./images/header/icon_voice.png’)} style={styles.voiceIcon}/>  
  13.                 </View>  
  14.                 <Image source={require(’./images/header/icon_qr.png’)} style={styles.scanIcon}/>  
  15.             </View>  
  16.         )  
  17.     }  
  18. }  
export default class Header extends Component {
    render() {
        return (
            <View style={styles.container}>
                <Image source={require('./images/header/header_logo.png')} style={styles.logo}/>
                <View style={styles.searchBox}>
                    <Image source={require('./images/header/icon_search.png')} style={styles.searchIcon}/>
                    <TextInput
                        keyboardType='web-search'
                        placeholder='搜索京东商品/店铺'
                        style={styles.inputText}/>
                    <Image source={require('./images/header/icon_voice.png')} style={styles.voiceIcon}/>
                </View>
                <Image source={require('./images/header/icon_qr.png')} style={styles.scanIcon}/>
            </View>
        )
    }
}
需要注意的是
1.style的使用,当使用StyleSheet创建的样式时,外层只需要一层{},而直接声明需要再加一层,即直接声明了匿名变量
2.Image的source可以使用网络图片或本地资源,使用本地资源时,类似require.js的包引用,而使用网络资源时,使用方法如下:source={{uri:’http://xxxxxxx’}}
3.TextInput的键盘类型可以使用keyboardType进行设置,占位字符使用placeholder设置,具体请参见官方文档

这时在模拟器或真机上Reload JS一下,就可以看到我们想要的界面了:

        </div>
            </div>

猜你喜欢

转载自blog.csdn.net/qq_21937107/article/details/80491404
今日推荐