正在做商城项目的同学有福啦,看看是你们想要的效果吗?
项目地址:https://github.com/pengzhenjin/react-native-mall
效果图
已实现功能
沉浸式状态栏
酷炫的顶部导航动画
消息角标
循环轮播图
搜索
商品一级分类
商品二级分类
商品子分类
顶部滑动的tab、智能下拉菜单
用到的技术
自定义 Badge(角标)
动画、动画插值器
Swiper 轮播图
自定义 tab
自定义 popup 弹窗下拉菜单
FlatList、SectionList
重点代码解析
MallHome.js
/**
* 滚动条监听事件
* @param event
*/
onScrollFunc = (event) => {
// 将滚动的值绑定到渐变动画
Animated.event([{nativeEvent: {contentOffset: {y: this.state.logoOpacity}}}])(event)
// 将滚动的值绑定到边距动画
Animated.event([{nativeEvent: {contentOffset: {y: this.state.searchViewMargin}}}])(event)
}
renderSearchView = () => {
const AnimatedTouchableOpacity = Animated.createAnimatedComponent(TouchableOpacity)
const marginRight = this.state.searchViewMargin.interpolate({
inputRange: [0, 80], // 当滚动条滚动到0~80的位置时
outputRange: [0, 80], // 将右边距改为从0~80
extrapolate: 'clamp' // 滚动超出0~80的范围,不在更改边距
})
const marginTop = this.state.searchViewMargin.interpolate({
inputRange: [0, 160], // 当滚动条滚动到0~160的位置时
outputRange: [0, -36], // 将上边距改为从0~-36
extrapolate: 'clamp' // 滚动超出0~160的范围,不在更改边距
})
return (
<AnimatedTouchableOpacity
style={styles.top_search_container(marginRight, marginTop)}
activeOpacity={0.8}
onPress={this.gotoSearch}
>
<Image style={styles.top_search_icon} source={iconSearch} />
<Text style={styles.top_search_text}>{'新品'}</Text>
</AnimatedTouchableOpacity>
)
}
GoodsCategory.js 解析
render() {
return (
<View style={styles.container}>
<View style={styles.first_category_container}>
// 一级分类列表,采用FlatList
<FlatList
ref={refs => this.flatList = refs}
keyExtractor={(item, index) => index.toString()}
data={this.state.firstCategoryData}
renderItem={this.renderFirstCategoryItem}
ItemSeparatorComponent={this.renderSeparatorLine}
/>
</View>
<View style={styles.second_category_container}>
// 二级、三级分类列表,采用SectionList
<SectionList
ref={refs => this.sectionList = refs}
renderSectionHeader={this.renderSecondCategorySectionHeader}
renderItem={this.renderSecondCategoryItem}
sections={this.state.secondCategoryData}
ItemSeparatorComponent={null}
ListHeaderComponent={null}
ListFooterComponent={null}
keyExtractor={(item, index) => index + item}
/>
</View>
</View>
);
}
// 点击一级分类时,需要计算滚动条的位置
onClickFirstCategoryItem = (item, index) => {
this.setState({selectedFirstCategoryIndex: index});
// 计算当前 item 的高度
const indexHeight = firstCategoryItemHeight * index;
// 计算屏幕一半的高度
const halfHeight = (height - 65) / 2;
// 如果当前 item 的高度 大于 屏幕一半的高度,就让滚动条滚动 indexHeight - halfHeight 高度(类似京东商品分类效果)
if (indexHeight > halfHeight) {
this.flatList.scrollToOffset({
animated: true,
offset: indexHeight - halfHeight,
});
}
this.sectionList.scrollToLocation({
animated: true,
itemIndex: 0,
sectionIndex: 0,
});
};
TopTabView.js 解析
/**
* 显示下拉菜单
* @param index 当前选中时的 tab 下标
*/
showDropdownMenu = (index) => {
// measure方法测量"箭头图标"在页面中的位置、宽高
this.arrowIcon.measure((x, y, width, height, pageX, pageY) => {
const topOffset = pageY + height // 计算"下拉菜单"距离页面顶部的偏移量
this.dropdownMenu.show(topOffset, index) // 显示"下拉菜单"
})
}
组件的 measure((x, y, width, height, pageX, pageY) => {}) 方法可以动态的获取组件在屏幕中的位置、宽高信息。measure 方法的参数 x,y 表示组件的相对位置,width,height 表示组件的宽度和高度,pageX,pageY 表示组件相对于屏幕的绝对位置。
TopDropdownMenu.js 解析
// 使用 Modal 来实现弹窗菜单,达到遮罩效果
render() {
const {isVisible, data, topOffset} = this.state;
return (
<Modal
animationType="fade"
transparent={true}
onRequestClose={() => this.hide()}
visible={isVisible}
>
<TouchableOpacity
style={styles.container}
activeOpacity={1}
onPress={() => this.hide()}
>
<FlatList
style={[styles.content_container, {top: topOffset}]}
keyExtractor={(item, index) => index.toString()}
data={data}
renderItem={this.renderItem}
horizontal={false}
numColumns={2}
renderSeparator={null}
/>
</TouchableOpacity>
</Modal>
);
}
// 使用绝对布局和 top 来计算弹窗菜单的位置,其中 top 是动态计算的
content_container: {
position: 'absolute',
top: 0,
backgroundColor: '#FFFFFF',
},
Copyright: 采用 知识共享署名4.0 国际许可协议进行许可
Links: https://www.pengzhenjin.top/archives/react-native版高仿淘宝京东商城首页商品分类页面
最后
本文在开源项目:https://github.com/xieyuliang/Note-Android中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中...
网友评论