Example code of the React Native imitation Meituan drop-down menu, reactnative
This article introduces the instance code of the React Native imitation Meituan drop-down menu. We are also learning React Native recently and share it with you by the way.
In many products, the drop-down menu selection function is involved. The best option is the Meituan. The effect is as follows:
To achieve the above effect, it is better to do it in the native, simply use the PopWindow component. If you use React Native to develop the above results, you need to pay attention to several issues:
1. There is an excessive animation effect in the drop-down list;
2. After the drop-down menu appears, click the menu item. You can select the menu item and trigger the corresponding event;
3. Items in the drop-down menu can be configured;
To implement the bullet box effect, we immediately think about using the Model component. To draw a hook icon and a drop-down triangle, we first want to use the ART implementation. Of course, you can also use the icon. For example, the Code for using ART to draw a check mark is as follows:
const Check = ()=>{ return ( <Surface width={18} height={12} > <Group scale={0.03}> <Shape fill={COLOR_HIGH} d={`M494,52c-13-13-33-13-46,0L176,324L62,211c-13-13-33-13-46,0s-13,33,0,46l137,136c6,6,15,10,23,10s17-4,23-10L494,99 C507,86,507,65,494,52z`} /> </Group> </Surface> );}
The implementation of the drop-down animation requires the use of Animated. For example, you must use Animated. timing to change the background color.
this.state.fadeInOpacity, { toValue: value, duration : 250, }
Running effect:
In this example, three files are designed: the navigation bar FoodActionBar. js, the drop-down box TopMenu. js and the file main class FoodView. js.
FoodActionBar. js
/*** Https://github.com/facebook/react-native * @ flow homepage title bar */import React, {Component} from 'react '; import {Platform, View, Dimensions, Text, StyleSheet, TouchableOpacity, image} from 'react-native '; import px2dp from '.. /util/Utils 'const isIOS = Platform. OS = "ios" const {width, height} = Dimensions. get ('window') const headH = px2dp (isIOS? 64: 44) export default class FoodActionBar extends Component {constructor (props) {super (props); this. state = {showPop: false, }}renderheader () {return (<View style = {styles. headerStyle }> <TouchableOpacity style = {styles. action }> <Image style = {styles. scanIcon}/> </TouchableOpacity> <TouchableOpacity style = {styles. searchBar }> <Image source = {require ('.. /images/ic_search.png ')} style = {styles. ico NStyle}/> <Text style = {fontSize: 13, color: "#666", marginLeft: 5 }}> enter the merchant name, category, and business area </Text> </TouchableOpacity> <TouchableOpacity style = {styles. action} onPress = {() => {this. setState ({showPop :! This. state. showPop}) }>< Image style = {styles. scanIcon} source = {require ('.. /images/icon_address.png ')}/> </TouchableOpacity> </View>)} render () {return (<View> {this. renderHeader () }</View>) ;}} const styles = StyleSheet. create ({headerStyle: {backgroundColor: "# ffffff", height: headH, paddingTop: px2dp (isIOS? 20: 0), flexDirection: 'row', alignItems: 'center',}, searchBar: {flex: 1, height: 30, borderRadius: 19, backgroundColor: '# e9e9e9', marginLeft: 10, flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', alignSelf: 'center', paddingLeft: 10 ,}, text: {fontSize: 16, color: '# ffff', justifyContent: 'center' ,}, iconStyle: {width: 22, height: 22 ,}, action: {flexDirection: 'row', justifyContent: 'center', alignItems: 'center', marginLeft: 10, marginRight: 10}, scanIcon: {width: 28, height: 28, alignItems: 'center',}, scanText: {fontSize: 14, color: '# ffff', justifyContent: 'center', alignItems: 'center ',},});
TopMenu. js
/*** Sample React Native App * https://github.com/facebook/react-native * @ flow */import React, {Component} from 'react '; import {AppRegistry, StyleSheet, Animated, ScrollView, Dimensions, PixelRatio, text, TouchableWithoutFeedback, TouchableHighlight, ART, View} from 'react-native '; const {Surface, Shape, Path, Group} = ART; const {width, height} = Dimensions. get ('window'); const T_WIDTH = 7; const T _ HEIGHT = 4; const COLOR_HIGH = '#00bea9'; const COLOR_NORMAL = '# 6c6c6c'; const LINE = 1/PixelRatio. get (); class Triangle extends React. component {render () {var path; var fill; if (this. props. selected) {fill = COLOR_HIGH; path = new Path (). moveTo (T_WIDTH/2, 0 ). lineTo (0, T_HEIGHT ). lineTo (T_WIDTH, T_HEIGHT ). close () ;}else {fill = COLOR_NORMAL; path = new Path (). moveTo (0, 0 ). lineTo (T_WIDT H, 0 ). lineTo (T_WIDTH/2, T_HEIGHT ). close ();} return (<Surface width = {T_WIDTH} height = {T_HEIGHT}> <Shape d = {path} stroke = "#00000000" fill = {fill} strokeWidth = {0}/> </Surface> )}} const TopMenuItem = (props) => {const onPress = () => {props. onSelect (props. index);} return (<TouchableWithoutFeedback onPress = {onPress}> <View style = {styles. item }> <Text style = {props. selected? Styles. menuTextHigh: styles. menuText }>{ props. label} </Text> <Triangle selected = {props. selected}/> </View> </TouchableWithoutFeedback>) ;}; const Subtitle = (props) =>{ let textStyle = props. selected? [Styles. tableItemText, styles. highlight, styles. marginHigh]: [styles. tableItemText, styles. margin]; let rightTextStyle = props. selected? [Styles. tableItemText, styles. highlight]: styles. tableItemText; let onPress = () => {props. onSelectMenu (props. index, props. subindex, props. data);} return (<TouchableHighlight onPress = {onPress} underlayColor = "# f5f5f5"> <View style = {styles. tableItem }> <View style = {styles. row >{props. selected & <Check/>}< Text style = {textStyle}> {props. data. title} </Text> </View> <Text style = {rightTextStyle}> {pr Ops. data. subtitle} </Text> </View> </TouchableHighlight>) ;}; const Title = (props) =>{ let textStyle = props. selected? [Styles. tableItemText, styles. highlight, styles. marginHigh]: [styles. tableItemText, styles. margin]; let rightTextStyle = props. selected? [Styles. tableItemText, styles. highlight]: styles. tableItemText; let onPress = () => {props. onSelectMenu (props. index, props. subindex, props. data);} return (<TouchableHighlight onPress = {onPress} underlayColor = "# f5f5f5"> <View style = {styles. titleItem }>{ props. selected & <Check/>}< Text style = {textStyle}> {props. data. title }</Text> </View> </TouchableHighlight>) ;}; const Check = () =>{ return (< Surface width = {18} height = {12}> <Group scale = {0.03}> <Shape fill = {COLOR_HIGH} d = {'m494, 52c-13-13-33-13-46, 0L176, 324L62, 211c-13-13-33-13-46, 0s-13, 33,0, 46l133, 136c6, 6,15, 86,507, 10s17-4, 23-10L494, 99 C507, 65,494, 52z'}/> </Group> </Surface>);} export default class TopMenu extends Component {constructor (props) {super (props); let array = props. config; let top = []; let maxHeight = []; let subse Lected = []; let height = []; // maximum height var max = parseInt (height-80) * 0.8/43); for (let I = 0, c = array. length; I <c; ++ I) {let item = array [I]; top [I] = item. data [item. selectedIndex]. title; maxHeight [I] = Math. min (item. data. length, max) * 43; subselected [I] = item. selectedIndex; height [I] = new Animated. value (0);} // analyze the data this. state = {top: top, maxHeight: maxHeight, subselected: subselec Ted, height: height, fadeInOpacity: new Animated. value (0), selectedIndex: null };} componentDidMount () {}createanimation = (index, height) =>{ return Animated. timing (this. state. height [index], {toValue: height, duration: 250}) ;}createfade = (value) =>{ return Animated. timing (this. state. fadeInOpacity, {toValue: value, duration: 250,}) ;}onselect = (index) =>{ if (index = this. stat E. selectedIndex) {// disappear this. hide (index);} else {this. setState ({selectedIndex: index, current: index}); this. onShow (index) ;}} hide = (index, subselected) =>{ let opts ={ selectedIndex: null, current: index}; if (subselected! = Undefined) {this. state. subselected [index] = subselected; this. state. top [index] = this. props. config [index]. data [subselected]. title; opts = {selectedIndex: null, current: index, subselected: this. state. subselected. concat () };} this. setState (opts); this. onHide (index);} onShow = (index) => {Animated. parallel ([this. createAnimation (index, this. state. maxHeight [index]), this. createFade (1)]). start ();} OnHide = (index) => {// other settings are 0 for (let I = 0, c = this. state. height. length; I <c; ++ I) {if (index! = I) {this. state. height [I]. setValue (0) ;}} Animated. parallel ([this. createAnimation (index, 0), this. createFade (0)]). start ();} onSelectMenu = (index, subindex, data) => {this. hide (index, subindex); this. props. onSelectMenu & this. props. onSelectMenu (index, subindex, data);} renderList = (d, index) => {let subselected = this. state. subselected [index]; let Comp = null; if (d. type = 'title') {Comp = Title;} else {Comp = Subtitle;} let enabled = this. state. selectedIndex = index | this. state. current = index; return (<Animated. view key = {index} pointerEvents = {enabled? 'Auto': 'none'} style = {[styles. content, {opacity: enabled? 1: 0, height: this. state. height [index]}] }> <ScrollView style = {styles. scroll}> {d. data. map (data, subindex) =>{ return <Comp onSelectMenu = {this. onSelectMenu} index = {index} subindex = {subindex} data = {data} selected = {subselected = subindex} key = {subindex}/> })} </ScrollView> </Animated. view>);} render () {let list = null; if (this. state. selectedIndex! = Null) {list = this. props. config [this. state. selectedIndex]. data;} console. log (list); return (<View style ={{ flex: 1 }}> <View style = {styles. topMenu}> {this. state. top. map (t, index) =>{ return <TopMenuItem key = {index} index = {index} onSelect = {this. onSelect} label = {t} selected = {this. state. selectedIndex === index}/>})} </View> {this. props. renderContent ()} <View style = {styles. bgContainer} pointerEv Ents = {this. state. selectedIndex! = Null? "Auto": "none" }> <Animated. view style = {[styles. bg, {opacity: this. state. fadeInOpacity}]}/> {this. props. config. map (d, index) => {return this. renderList (d, index) ;}</View> </View>) ;}} const styles = StyleSheet. create ({scroll: {flex: 1, backgroundColor: '# fff'}, bgContainer: {position: 'absolute', top: 40, width: width, height: height }, bg: {flex: 1, backgroundColor: 'rgba (50, 50, 0.2) '}, content: {position: 'absolute', width: width}, highlight: {color: COLOR_HIGH}, marginHigh: {marginLeft: 10}, margin: {marginLeft: 28}, titleItem: {height: 43, alignItems: 'center', paddingLeft: 10, paddingRight: 10, borderBottomWidth: LINE, borderBottomColor: '# eee', flexction ction: 'row',}, tableItem: {height: 43, alignItems: 'center', paddingLeft: 10, paddingRight: 10, borderBottomWidth: LINE, borderBottomColor: '# eee', flexction ction: 'row', justifyContent: 'Space-between'}, tableItemText: {fontWeight: '2013', fontSize: 14 }, row: {flexDirection: 'row'}, item: {flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center',}, menutexthweigh: {marginRight: 3, fontSize: 13, color: COLOR_HIGH}, menuText: {marginRight: 3, fontSize: 13, color: COLOR_NORMAL}, topMenu: {flexDirection: 'row ', height: 40, borderTopWidth: LINE, borderTopColor: '# bdbd', borderBottomWidth: 1, borderBottomColor:' # f2f2f2 '},});
Main class FoodView. js:
/*** Sample React Native App * https://github.com/facebook/react-native * @ flow */import React, {Component} from 'react '; import {AppRegistry, StyleSheet, TouchableOpacity, Dimensions, Text, view} from 'react-native '; const {width, height} = Dimensions. get ('window'); import FoodActionBar from ". /pop/FoodActionBar "; import Separator from ". /util/Separator "; import TopMenu from ". /pop/TopMenu "; const CONFIG = [{type: 'subtitle', selectedIndex: 1, data: [{title: 'all', subtitle: 'mongom '}, {title: 'buffer', subtitle: '300m'}, {title: 'buffer', subtitle: '200m'}, {title: 'buffer', subtitle: '500m'}, {title: 'buffer', subtitle: '800m'}, {title: 'buffer', subtitle: '700m'}, {title: 'buffer ', subtitle: '900m'},]}, {type: 'title', selectedIndex: 0, data: [{title: 'smart sorted'}, {title: 'closest to me'}, {title: 'High praise preview'}, {title: 'Most popular '}]; export default class dview fooextends Component {constructor (props) {super (props); this. state = {data :{};}rendercontent = () =>{ return (<TouchableOpacity> <Text style = {styles. text}> index: {this. state. index} subindex: {this. state. subindex} title: {this. state. data. title }</Text> </TouchableOpacity>); // alert (this. state. data. title)}; onSelectMenu = (index, subindex, data) => {this. setState ({index, subindex, data}) ;}; render () {return (<View style = {styles. container }> <FoodActionBar/> <Separator/> <TopMenu style = {styles. container} config = {CONFIG} onSelectMenu = {this. onSelectMenu} renderContent = {this. renderContent}/> </View>);} const styles = StyleSheet. create ({container: {flex: 1, width: width, backgroundColor: '# F5FCFF',}, text: {fontSize: 20, marginTop: 100, justifyContent: 'center ', alignItems: 'center ',},});
The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.