Android自定义控件:下拉菜单的实现与优化

下拉菜单

美团首页类似的下拉弹出菜单工程中经常遇到的控件,不同工程中菜单条目的类型与数量也不一样
所以需要根据实际需要填充不同内容。先写个demo,一倍不时之需吧。

既然每个项目用到的菜单样式不同,此时我们必须根据实际情况填充,这样就需要将容器和内容分开。

这里写图片描述

容器
容器的画当然就使用popWindow了,我们需要在点击指定控件后弹出window,需要

1.指定当前window的位置及大小
2.指定window出方式
3.如果要求其他部分变暗,我们必须指定变暗部分的高度

内容
内容需要被填充到容器中,根据不同的数据类型及需求,设置不同的页面填充。可以将其定义为**组合控件**或者一个**Holder**。
需要提供控件填充方法和数据刷新两个基本方法,同时还需要一个方法暴露一个View的引用,这样就可以将这个View填充到我们想添加的任何位置。

BaseHolder

/**
 * Created by Administrator on 2015/10/30 0030.
 */
public abstract class BaseHolder<T> {

    private View mView;

    public abstract View initView();
    public abstract void refreshView(T info);

    public BaseHolder(){
        mView = initView();
        mView.setTag(this);
    }

    public View getView(){
        return mView;
    }
}
弹窗代码

假定我们现在按下一个按键,然后弹出popwindow,此时我们需要继承一个Button,
复写Button的OnClick方法,从而实现点击按键在按键正下方弹出popwindow的效果。

public class PopMenuButton extends Button  implements View.OnClickListener {

    private Context mCtx;
    private PopupWindow mPopupWindow;
    private LinearLayout mPopupWindowView;
    //根布局设置为Button 弹出popwindow的位置可以以根布局为参照
    private View mRootView;
    private View mShodowView;
    private LinearLayout mContentView;

    private int[] mLocation = new int[2];
    private int mStartY;
    private int mScreenHeight;

    public PopMenuButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        mCtx = context;
        mRootView = this;
    }

    public PopMenuButton(Context context) {
        super(context);
        mCtx = context;
        mRootView = this;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        initPopWindow();
    }

    public void setContentView(View view){

        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        mContentView.addView(view, params);
    }

    private void initView(){
        mPopupWindowView = (LinearLayout) View.inflate(mCtx, R.layout.popmenu_layout, null);
        mContentView = (LinearLayout) mPopupWindowView.findViewById(R.id.rl_content);
        mShodowView = mPopupWindowView.findViewById(R.id.rl_shodow);

        mShodowView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mPopupWindow.dismiss();
            }
        });

        setOnClickListener(this);
    }

    private void initPopWindow(){

        initView();
        //获取按键的位置
        mRootView.getLocationOnScreen(mLocation);
        mStartY = mLocation[1] + mRootView.getHeight();
    }

    @Override
    public void onClick(View v) {

        if(mPopupWindow == null) {
            //initPopWindow();

            int[] location = new int[2];
            this.getLocationOnScreen(location);
            //y轴起始位置
            int start = location[1] + this.getHeight() + 1;
            //测量屏幕的高度
            int screenHeight = ((Activity) mCtx).getWindowManager().getDefaultDisplay().getHeight();

            //设置弹框的大小  弹框位置在按钮以下,占据所有屏幕
            mPopupWindow = new PopupWindow(mPopupWindowView, ViewGroup.LayoutParams.MATCH_PARENT, screenHeight - start, false);
            // mPopupWindow = new PopupWindow(mPopupWindowView,  ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,false);
            mPopupWindow.setBackgroundDrawable(new ColorDrawable(0xb0000000));
            //mPopupWindow.setAnimationStyle(R.style.AnimationFade);
            mPopupWindow.setAnimationStyle(R.style.popupAnimation);
            mPopupWindow.setFocusable(true);
            mPopupWindow.setOutsideTouchable(true);
        }

        if (mPopupWindow.isShowing()) {
            mPopupWindow.dismiss();
        } else {

            int[] location1 = new int[2];
            this.getLocationOnScreen(location1);
            //设置弹框的位置
            mPopupWindow.showAtLocation(mRootView, Gravity.NO_GRAVITY, 0,  location1[1]+this.getHeight()+1);
        }
    }

    private int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale);
    }
}
二级菜单Holder

假设我们当前要弹出一个二级菜单,我们可以将逻辑封装到一个Holder中,最终让holder为我们提供页面,直接将页面贴到容器中。

/**
 * Created by vonchenchen on 2015/10/30 0030.
 */
public class DoubleListViewHolder extends BaseHolder<List<List<String>>> {

    private List<List<String>> mData;

    private ListView mLeftListView;
    private ListView mRightListView;

    private List<String> mLeftList;
    private List<String> mRightList;
    private TextListAdapter mLeftAdapter;
    private TextRightListAdapter mRightAdapter;

    private View mViewClickRecorder = null;
    private boolean mFirstMesure = true;

    @Override
    public View initView() {
        View view = View.inflate(MyApplication.getContext(), R.layout.doublelistview_layout, null);

        mLeftListView = (ListView) view.findViewById(R.id.ll_left);
        mRightListView = (ListView) view.findViewById(R.id.ll_right);



        mLeftListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                //如果点击条目,更换被点击条目的颜色
                if(mViewClickRecorder != view){
                    view.setBackgroundColor(MyApplication.getContext().getResources().getColor(R.color.normal_selected_color));
                    if(mViewClickRecorder != null) {
                        mViewClickRecorder.setBackgroundColor(MyApplication.getContext().getResources().getColor(R.color.normal_unselected_color));
                    }
                   mViewClickRecorder = view;
                }

                mRightList = mData.get(position+1);

                mRightAdapter = new TextRightListAdapter(mRightList);
                mRightListView.setAdapter(mRightAdapter);
            }
        });

        return view;
    }

    @Override
    public void refreshView(List<List<String>> info) {

        this.mData = info;

        mLeftList = info.get(0);
        mLeftAdapter = new TextListAdapter(mLeftList);

        mRightList = info.get(1);
        mRightAdapter = new TextRightListAdapter(mRightList);

        mLeftListView.setAdapter(mLeftAdapter);
        mRightListView.setAdapter(mRightAdapter);
    }

    class TextListAdapter extends MyAdapter{

        public TextListAdapter(List list) {
            super(list);
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {

            TextViewHolder holder = null;
            if(convertView == null){
                holder = new TextViewHolder();
            }else{
                holder = (TextViewHolder) convertView.getTag();
            }

            convertView = holder.getView();
            holder.refreshView((String) getItem(position));

            //防止多次测量
            if(position == 0 && mFirstMesure){
                mFirstMesure = false;
                convertView.setBackgroundColor(MyApplication.getContext().getResources().getColor(R.color.normal_selected_color));
                mViewClickRecorder = convertView;
            }

            return convertView;
        }
    }

    class TextRightListAdapter extends MyAdapter{

        public TextRightListAdapter(List list) {
            super(list);
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {

            TextViewHolder holder = null;
            if(convertView == null){
                holder = new TextViewHolder();
            }else{
                holder = (TextViewHolder) convertView.getTag();
            }

            convertView = holder.getView();
            holder.refreshView((String) getItem(position));
            return convertView;
        }
    }

    /**
     * ListView 中的 Holder
     */
    private class TextViewHolder extends BaseHolder<String>{

        private TextView mTextView;

        @Override
        public View initView() {
            View view = View.inflate(MyApplication.getContext(), R.layout.simpletext_item, null);
            mTextView = (TextView) view.findViewById(R.id.tv_text);
            return view;
        }

        @Override
        public void refreshView(String info) {
            mTextView.setText(info);
        }
    }
}
将内容添加到容器中

调用的时候分为以下四步。这样,显示,逻辑和数据就自然分离开来了。

        //创建容器
        PopMenuButton mPopMenuButton = (PopMenuButton) findViewById(R.id.btn_pop);
        //创建Holder,提供内容
        DoubleListViewHolder holder = new DoubleListViewHolder();

        //将 内容 贴到 容器 中
        mPopMenuButton.setContentView(holder.getView());
        //用数据刷新容器的显示内容
        holder.refreshView(mLists); 

git:https://git.oschina.net/vonchenchen/pulldownmenu.git

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spinner控件本身不支持多选功能,但可以通过自定义适配器来实现多选下拉菜单。 以下是一个示例代码: ```java public class MultiSpinnerAdapter extends ArrayAdapter<String> implements OnItemClickListener { private List<String> items; private boolean[] selected; private Spinner spinner; public MultiSpinnerAdapter(Context context, int textViewResourceId, List<String> items, Spinner spinner) { super(context, textViewResourceId, items); this.items = items; this.selected = new boolean[items.size()]; this.spinner = spinner; spinner.setOnItemClickListener(this); } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); TextView textView = (TextView) view.findViewById(android.R.id.text1); if (selected[position]) { textView.setTextColor(Color.RED); } else { textView.setTextColor(Color.BLACK); } return view; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selected[position] = !selected[position]; getView(position, view, parent); } public List<String> getSelectedItems() { List<String> selectedItems = new ArrayList<>(); for (int i = 0; i < items.size(); i++) { if (selected[i]) { selectedItems.add(items.get(i)); } } return selectedItems; } } ``` 在Activity中使用该适配器: ```java Spinner spinner = (Spinner) findViewById(R.id.spinner); List<String> items = Arrays.asList("Item 1", "Item 2", "Item 3", "Item 4"); MultiSpinnerAdapter adapter = new MultiSpinnerAdapter(this, android.R.layout.simple_spinner_item, items, spinner); spinner.setAdapter(adapter); // 获取选中的项 List<String> selectedItems = adapter.getSelectedItems(); ``` 以上代码实现了一个多选下拉菜单,当用户点击列表项时,会切换该项的选中状态,并且选中状态的文本颜色将变为红色。getSelectedItems()方法可以获取选中的项。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值