android 史上最简单的下拉选择菜单DropDownMenu 几行代码轻松搞定!

这是我在CSDN上第一篇原创文章,趁着从上家公司离职去考驾照的这段日子,想通过写技术博客的方式,锻炼一下自己的语言表达能力,以及对之前工作的总结。废话不多说了,直接进入正题

先给客官来张效果图:

android 史上最简单的下拉选择菜单DropDownMenu 几行代码轻松搞定!_第1张图片

一、思路

下拉菜单首先让我想到了PopupWindow,PopupWindow上的contentView是一个半透明的LineaLayout,再上面是一个ListView。popupWindow的showAsDropDown方法可以让popupWindow显示到某个控件的下方,出现和隐藏的时候加个动画就行了。那么下拉菜单已经有了,接下来上部的菜单按钮要怎么实现呢,无非就是LinearLayout上有个TextView和View,文字右边的箭头可以调用TextView的方法画到右边,无非多加一个状态参数来判定到底是画哪个。好了,思路有了,接下来我们看是怎么实现的。

二、实现

首先我封装了一个PopupUtil类:

public class PopWinDownUtil {
    private Context context;
    private View contentView;
    private View relayView;
    private PopupWindow popupWindow;
    public PopWinDownUtil(Context context, View contentView, View relayView){
        this.context = context;
        this.contentView = contentView;
        this.relayView = relayView;
        init();
    }
    public void init(){
        //内容,高度,宽度
        popupWindow = new PopupWindow(contentView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, true);
        //动画效果
        popupWindow.setAnimationStyle(R.style.AnimationTopFade);
        //菜单背景色
        ColorDrawable dw = new ColorDrawable(Color.TRANSPARENT);
        popupWindow.setBackgroundDrawable(dw);
        popupWindow.setOutsideTouchable(true);
        //关闭事件
        popupWindow.setSoftInputMode(PopupWindow.INPUT_METHOD_NEEDED);
        popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

        popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                if(onDismissLisener != null){
                    onDismissLisener.onDismiss();
                }
            }
        });
    }
    public void show(){
        //显示位置
        popupWindow.showAsDropDown(relayView);
    }
    public void hide(){
        if(popupWindow != null && popupWindow.isShowing()){
            popupWindow.dismiss();
        }
    }

    private OnDismissLisener onDismissLisener;
    public void setOnDismissListener(OnDismissLisener onDismissLisener){
        this.onDismissLisener = onDismissLisener;
    }
    public interface OnDismissLisener{
        void onDismiss();
    }
    public boolean isShowing(){
        return popupWindow.isShowing();
    }
}
可以直接把contenView和显示到哪个控件下面的View传进来,添加了一个监听popupWindow窗口消失的回调接口,代码很简单就不多说了。

之后就该菜单按钮了,代码如下:

public class DropdownButton extends RelativeLayout implements Checkable, View.OnClickListener, PopWinDownUtil.OnDismissLisener, AdapterView.OnItemClickListener {
    /**
     * 菜单按钮文字内容
     */
    private TextView text;
    /**
     * 菜单按钮底部的提示条
     */
    private View bLine;
    private boolean isCheced;
    private PopWinDownUtil popWinDownUtil;
    private Context mContext;
    private DropDownAdapter adapter;
    /**
     * 传入的数据
     */
    private List drops;
    /**
     * 当前被选择的item位置
     */
    private int selectPosition;

    public DropdownButton(Context context) {
        this(context, null);
    }

    public DropdownButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DropdownButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mContext = context;
        //菜单按钮的布局
        View view =  LayoutInflater.from(getContext()).inflate(R.layout.dropdown_tab_button,this, true);
        text = (TextView) view.findViewById(R.id.textView);
        bLine = view.findViewById(R.id.bottomLine);
        //点击事件,点击外部区域隐藏popupWindow
        setOnClickListener(this);
    }
    /**
     * 添加数据,默认选择第一项
     * @param dropBeans
     */
    public void setData(List dropBeans){
        if(dropBeans == null || dropBeans.isEmpty()){
            return;
        }
        drops = dropBeans;
        drops.get(0).setChoiced(true);
        text.setText(drops.get(0).getName());
        selectPosition = 0;
        View view = LayoutInflater.from(mContext).inflate(R.layout.dropdown_content, null);
        view.findViewById(R.id.content).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                popWinDownUtil.hide();
            }
        });
        ListView listView = (ListView) view.findViewById(R.id.list);
        listView.setOnItemClickListener(this);

        adapter = new DropDownAdapter(drops,mContext);
        listView.setAdapter(adapter);

        popWinDownUtil = new PopWinDownUtil(mContext,view,this);
        popWinDownUtil.setOnDismissListener(this);
    }

    public void setText(CharSequence content) {
        text.setText(content);
    }
    /**
     * 根据传过来的参数改变状态
     * @param checked
     */
    @Override
    public void setChecked(boolean checked) {
        isCheced = checked;
        Drawable icon;
        if (checked) {
            icon = getResources().getDrawable(R.mipmap.ic_dropdown_actived);
            text.setTextColor(getResources().getColor(R.color.green));
            bLine.setVisibility(VISIBLE);
            popWinDownUtil.show();
        } else {
            icon = getResources().getDrawable(R.mipmap.ic_dropdown_normal);
            text.setTextColor(getResources().getColor(R.color.black));
            bLine.setVisibility(GONE);
            popWinDownUtil.hide();
        }
        //把箭头画到textView右边
        text.setCompoundDrawablesWithIntrinsicBounds(null, null, icon, null);
    }
    @Override
    public boolean isChecked() {
        return isCheced;
    }
    @Override
    public void toggle() {
        setChecked(!isCheced);
    }
    @Override
    public void onClick(View v) {
        setChecked(!isCheced);
    }

    @Override
    public void onDismiss() {
        setChecked(false);
    }

    @Override
    public void onItemClick(AdapterView parent, View view, int position, long id) {
        if(selectPosition == position){
            return;
        }
        drops.get(selectPosition).setChoiced(false);
        drops.get(position).setChoiced(true);
        text.setText(drops.get(position).getName());
        adapter.notifyDataSetChanged();
        selectPosition = position;
        popWinDownUtil.hide();
        if(onDropItemSelectListener != null){
            onDropItemSelectListener.onDropItemSelect(position);
        }
    }

    private OnDropItemSelectListener onDropItemSelectListener;
    public void setOnDropItemSelectListener(OnDropItemSelectListener onDropItemSelectListener){
        this.onDropItemSelectListener = onDropItemSelectListener;
    }
    public interface OnDropItemSelectListener{
        void onDropItemSelect(int Postion);
    }


    class DropDownAdapter extends BaseAdapter {
        private List drops;
        private Context context;
        public DropDownAdapter(List drops, Context context){
            this.drops = drops;
            this.context = context;
        }
        @Override
        public int getCount() {
            return drops.size();
        }
        @Override
        public Object getItem(int position) {
            return position;
        }
        @Override
        public long getItemId(int position) {
            return position;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if(convertView == null){
                holder = new ViewHolder();
                convertView = LayoutInflater.from(context).inflate(R.layout.dropdown_item,parent,false);
                holder.tv = (TextView) convertView.findViewById(R.id.name);
                holder.tig = (ImageView) convertView.findViewById(R.id.check);
                convertView.setTag(holder);
            }else{
                holder = (ViewHolder) convertView.getTag();
            }
            holder.tv.setText(drops.get(position).getName());
            if(drops.get(position).isChoiced()){
                holder.tig.setVisibility(VISIBLE);
            }else{
                holder.tig.setVisibility(GONE);
            }
            return convertView;
        }
        private class ViewHolder{
            TextView tv;
            ImageView tig;
        }
    }
}
逻辑并不难,重要的部分都有提示,还是要讲一下,控件用到的数据是我定义的一个DropBean集合,里边有要展示的文字内容和一个isChecked状态,用来决定该item是否已被选中。如果我们的列表数据是从服务端获取的,那么我们只要用个for循环赋值成DropBean集合就行了。然后直接调用菜单控件的setData就不用管了。

接下来是我的调用示例:

public class MainActivity extends AppCompatActivity {
    private DropdownButton dropdownButton1;
    private DropdownButton dropdownButton2;
    private DropdownButton dropdownButton3;
    private List times;
    private List types;
    private List names;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        dropdownButton1 = (DropdownButton) findViewById(R.id.time1);
        dropdownButton2 = (DropdownButton) findViewById(R.id.time2);
        dropdownButton3 = (DropdownButton) findViewById(R.id.time3);

        initSomeData();
        dropdownButton1.setData(times);
        dropdownButton2.setData(types);
        dropdownButton3.setData(names);
    }

    private void initSomeData() {
        times = new ArrayList<>();
        types = new ArrayList<>();
        names = new ArrayList<>();
        int mouth = 5;
        int year = 2016;
        times.add(new DropBean("全部时间"));

        times.add(new DropBean(year + "年 全年"));

        for (int i = 0; i < mouth; i++) {
            times.add(new DropBean(year + "年 " + (i + 1) + "月"));
        }

        types.add(new DropBean("交通"));
        types.add(new DropBean("饮食"));

        names.add(new DropBean("小张"));
        names.add(new DropBean("小王"));
        names.add(new DropBean("小c"));
        names.add(new DropBean("小刘"));
    }
}
代码很少,逻辑也很明确,这里就不多说了。对了我们的布局文件是这样的:


    
        
        
        
        
        
    
    

是不是很简单,需要几个就写几个。

dropdown_in.xml的代码:



    
dropdown_out.xml的代码:


    


到此史上最简单的下拉菜单就打造完了!

点击下载源码



你可能感兴趣的:(android)