ReactNative学习笔记--下拉选择菜单的简单封装

ReactNative 学习笔记--封装下拉菜单

单个下拉子项

先看整体要做的效果

1.实现原理:

先做一行按钮,使我们要点击弹出菜单列表的按钮,然后计算点击的按钮所在的位置,再通过点击按钮的高度计算出要弹出列表的位置和宽度高度等,利用绝对布局在Modal组件上显示,并设置对应的效果,例如'fade',弹出的Modal覆盖整个界面,选择列表子项或者点击其他位置(Modal上)都要让Modal消失,再次点击按钮的时候,显示下拉菜单前重新计算对应按钮的位置和点击按钮对应的下拉菜单的位置,然后重新更改下拉菜单的位置和内容并显示,后面就按这个逻辑。

2.实现代码

分两步:

单个子项 SiftListItem

先看render了解整体布局

render() {
        return (
            <View {...this.props}>
                {this._renderButton()}
                {this._renderSiftList()}
            </View>
        );
    }


_renderButton函数 负责按钮 showSiftList控制着是否显示SiftList
里面的item:

item:
{
      title:'交易方向',
     tag:0,
     list:[],
 }
_renderButton = ()=> {
        const {item,textStyle,style}=this.props;
        const {showSiftList}=this.state;
        let icon = showSiftList?require('../images/icon_up.svg'):require('../images/btn_down.svg');
        return (
            <TouchableOpacity 
                    onPress={this._onButtonPress}>
                <View style={[styles.button,style]}>
                    <Text style={[styles.buttonText, textStyle]}
                          numberOfLines={1}>
                        {item.title}
                    </Text>
                    <SvgImage
                        style={{marginLeft:4}}
                        height={6}
                        source={icon}
                    />
                </View>
            </TouchableOpacity>
        );
    };
_renderSiftList负责下拉菜单绘制,可以写成ListView,如果下拉菜单的高度不大,且确定就可以用ScrollView,这里就是用的ScrollView
_renderModal = ()=> {
        const {showSiftList,selectedIndex}=this.state;
        const {style,item}=this.props;
        if (showSiftList && this._buttonFrame) {
            let frameStyle = this._calculatePosition();
            return (
                <Modal animationType='fade'
                       transparent={true}
                >
                    <TouchableWithoutFeedback onPress={this._onModalPress}>
                        <View style={[styles.modal]}>
                            <View style={[frameStyle,styles.dropdown,{height:item.list?30*item.list.length:0},{width:style.width}]}>
                                {
                                    item.list?item.list.map((sublist,i)=>{
                                    return(
                                        <TouchableOpacity
                                            onPress={()=>this.select(i)}
                                            key={i}
                                        >
                                            <View style={[styles.subItemStyle,{width:style.width-1},selectedIndex===i&&{backgroundColor:System_styles.hei_240}]}
                                            >
                                                <Text style={[styles.rowText,selectedIndex===i&&{color:System_styles.blue}]}>
                                                    {sublist}
                                                </Text>
                                            </View>
                                        </TouchableOpacity>
                                    )
                                }):null}
                            </View>
                        </View>
                    </TouchableWithoutFeedback>
                </Modal>
            );
        }
    };


计算SiftList菜单的位置

_calculatePosition = ()=> {
         const {style}=this.props;
        let dimensions = Dimensions.get('window');
        let windowWidth = dimensions.width;
        let windowHeight = dimensions.height;

        let dropdownHeight = (style && StyleSheet.flatten(style).height) ||
            StyleSheet.flatten(styles.dropdown).height;

        let bottomSpace = windowHeight - this._buttonFrame.y - this._buttonFrame.h;
        let rightSpace = windowWidth - this._buttonFrame.x;
        let showInBottom = bottomSpace >= dropdownHeight || bottomSpace >= this._buttonFrame.y;
        let showInLeft = rightSpace >= this._buttonFrame.x;

        var style = {
            height: dropdownHeight,
            top: (showInBottom ? this._buttonFrame.y + this._buttonFrame.h : Math.max(0, this._buttonFrame.y - dropdownHeight))-0.5,
        }

        if (showInLeft) {
            style.left = this._buttonFrame.x;
        } else {
            let dropdownWidth = (style && StyleSheet.flatten(style).width) || -1;
            if (dropdownWidth !== -1) {
                style.width = dropdownWidth;
            }
            style.right = rightSpace - this._buttonFrame.w;
        }

        if (this.props.adjustFrame) {
            style = this.props.adjustFrame(style) || style;
        }

        return style;
    };


子项的选中和下拉菜单的显示、隐藏方法

show = ()=> {
        this._updatePosition(() => {
            this.setState({
                showSiftList: true,
            });
        });
    };

    hide = ()=> {
        this.setState({
            showSiftList: false,
        });
    };

    select = (index)=>  {
        const {item,selectedCallBack}=this.props;
        const {selectedIndex}=this.state;

        if (index == null || item.list == null || index >= item.list.length) {
            index = selectedIndex;
        }
        this.setState({
            selectedIndex: index,
        });
        selectedCallBack&&selectedCallBack(index,item.tag);
        this.hide();
    };


获取按钮对应位置的方法

 
 _updatePosition = (callback)=>  {
        if (this._button && this._button.measure) {
            this._button.measure((fx, fy, width, height, px, py) => {
                this._buttonFrame = {x: px, y: py, w: width, h: height};
                callback && callback();
            });
        }
    };

封装成一个组件SiftListControl
export default class SiftListControl extends Component {

    static defaultProps = {
        items:[
            {
                title:'交易方向',
                tag:0,
                icon:require('../images/btn_down.svg'),
                list:[],
            }
        ]
    };

    constructor(){
        super();
        this.state = {

        };
    }

    _selectedIndex = (index,tag)=>{
        const {callBack}=this.props;
        callBack&&callBack(index,tag);
    };

    render() {
        const {items,subItemStyle}=this.props;
        return (
            <View style={[styles.listBar,this.props.style]}>
                {
                 items.map((item,i)=>{
                     return(
                         <SiftListViewNew
                             style={{backgroundColor:'white',width:subItemStyle.width}}
                             item={item}
                             key={i}
                             selectedCallBack={this._selectedIndex}
                         >
                         </SiftListViewNew>
                     )
                 })   
                }
            </View>
        );
    }
}

const styles = StyleSheet.create({
    listBar:{
        height:32,
        flexDirection:'row',
    }
});


下载链接:http://7xrqmg.com1.z0.glb.clouddn.com/Sift.zip


链接:http://www.imooc.com/article/15100

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值