欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

安卓开发:自定义PopupWindow,实现模仿iOS底部弹出菜单

程序员文章站 2022-05-30 11:54:34
...

先贴上效果图安卓开发:自定义PopupWindow,实现模仿iOS底部弹出菜单
如图,从下面弹出菜单,菜单上面的item是可以扩展的。

先说一下思路,具体布局没啥难点,上面是一个可以扩展的布局,使用ListView和 RecyclerView都可以,我就用RecyclerView做例子了,下面的“取消”就是一个可以点击的按钮或者文字。。。

菜单的子项都是其中的一个item,当然我写的比较简单,满足项目需求,使用的时候还可以加上小图标。。。

先写item的布局,就一个文字,还有一条横线,最下面的item没有横线,所以也需要命名,最后一条要隐藏掉,代码贴上:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="46dp"
    android:background="@drawable/selector_btn">

    <TextView
        android:id="@+id/item_popup_tv"
        android:layout_width="match_parent"
        android:layout_height="46dp"
        android:gravity="center"
        android:textColor="@color/blue"
        android:textSize="16dp" />

    <View
        android:id="@+id/item_popup_line"
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:background="#c8c8c8"
        android:layout_alignParentBottom="true" />
</RelativeLayout>

很简单,就一个textview,一条线。

接下来开始写自定义PopupWindow的布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="bottom">

    <View
        android:id="@+id/popup_btm_bg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/popup_btm_rv"
        android:background="#60000000" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/popup_btm_rv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/popup_btm_line"
        android:background="@color/white" />

    <View
        android:id="@+id/popup_btm_line"
        android:layout_width="match_parent"
        android:layout_height="6dp"
        android:layout_above="@+id/popup_btm_cancel_tv"
        android:background="@color/tm_huise" />

    <TextView
        android:id="@+id/popup_btm_cancel_tv"
        android:layout_width="match_parent"
        android:layout_height="46dp"
        android:layout_alignParentBottom="true"
        android:background="@drawable/tm_selector_btn_anxia"
        android:gravity="center"
        android:text="取消"
        android:textColor="@color/tm_blue"
        android:textSize="16dp" />

</RelativeLayout>

也很简单,上面半透明的view是为了实现半透明效果,点击此处也可以实现关闭PopupWindow,中间是一个RecyclerView,用来放我们定义的菜单项,下面的就是一条分割线和取消按钮了,点击“取消”就可以关闭PopupWindow了;

然后再来写RecyclerView的Adapter;自从用了RecyclerView,就迷上他了,不知道是不是心里作用,感觉RecyclerView比ListView效率高一些(好多大牛也这么说),话不多说,贴上Adapter代码

private class RvAdapter extends RecyclerView.Adapter<RvAdapter.ViewHolder> {
        @Override
        public int getItemCount() {
            return datas.size();
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, final int position) {
            holder.itemPopupTv.setText(datas.get(position));
            //最后一条要隐藏分割线
            holder.itemPopupLine.setVisibility(position + 1 == datas.size() ? View.GONE : View.VISIBLE);
            //实现item的点击事件
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dismiss();
                    itemClickListener.onItemClick(v, position);
                }
            });
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(context).inflate(R.layout.item_custom_popup, parent, false);
            ViewHolder viewHolder = new ViewHolder(view);
            return viewHolder;
        }

        public class ViewHolder extends RecyclerView.ViewHolder {
            private TextView itemPopupTv;
            private View itemPopupLine;

            public ViewHolder(View itemView) {
                super(itemView);
                itemPopupTv = (TextView) itemView.findViewById(R.id.item_popup_tv);
                itemPopupLine = itemView.findViewById(R.id.item_popup_line);
            }
        }
    }

最后,重头戏来了,万事俱备,就差PopupWindow代码了:

public class BottomPopupWindow extends PopupWindow {
    private String TAG = "BottomPopupWindow";

    private FragmentActivity context;
    //RecyclerView的数据源
    private List<String> datas;
    //RecyclerView的item点击回调
    private OnItemClickListener itemClickListener;

    public BottomPopupWindow(FragmentActivity context, List<String> datas, OnItemClickListener itemClickListener) {
        this.context = context;
        this.datas = datas;
        this.itemClickListener = itemClickListener;
        foundPopup();
    }

    private void foundPopup() {
        View contentView = View.inflate(context, R.layout.popup_custom_btm, null);

        View popupBtmBg = contentView.findViewById(R.id.popup_btm_bg);
        RecyclerView popupBtmRv = (RecyclerView) contentView.findViewById(R.id.popup_btm_rv);
        TextView popupBtmCancelTv = (TextView) contentView.findViewById(R.id.popup_btm_cancel_tv);
        LinearLayoutManager layoutManager = new LinearLayoutManager(context);
        layoutManager.setAutoMeasureEnabled(true);
        popupBtmRv.setLayoutManager(layoutManager);

        setContentView(contentView);
        setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
        setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
        //设置弹出动画
        setAnimationStyle(R.style.popWindow_animation_anim);
        //使其聚集 ,要想监听菜单里控件的事件就必须要调用此方法
        setFocusable(true);
        //设置允许在外点击消失
        setOutsideTouchable(true);
        //设置背景,点击back可消失
        setBackgroundDrawable(new BitmapDrawable());
        //PopupWindow的显示及位置设置
        showAtLocation(contentView, Gravity.BOTTOM, 0, 0);

        popupBtmRv.setAdapter(new RvAdapter());
        //取消按钮-点击关闭
        popupBtmCancelTv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dismiss();
            }
        });
        //上部半透明背景-点击关闭
        popupBtmBg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dismiss();
            }
        });
    }
}

RecyclerView的点击回调

public interface OnItemClickListener {
    void onItemClick(View view, int position);
}

这样,我们的可扩展的PopupWindow已经完工了,接下来说一下使用方法;
相信各位大牛已经看懂怎么是用了吧,初始化的时候把需要显示的item数据传递过来就可以了,然后做RecyclerView的Item点击事件就ok了。

使用如下:
首先需要初始化数据:

List<String> items = new ArrayList<>();
                items.add("拍摄照片/视频");
                items.add("从手机相册选择");
                items.add("网页分享");

然后就可以调用了,因为我们在BottomPopupWindow里已经实现了各种情况下的关闭事件,所以,就不需要写show(),dismiss()方法了,

new BottomPopupWindow(context, items, new OnItemClickListener() {
                    @Override
                    public void onItemClick(View view, int position) {
                            //position是从0开始的
                        if (position == 0) {
                           //这里处理点击第一个item的事件
                        } else if (position == 1) {
                           //这里处理点击第二个item的事件
                        } else {
                          //这里处理点击第n个item的事件,可以继续往下写,items有几个就可以实现几个
                        }
                        finish();
                    }
                });

就这样,拜拜,等会把代码传上去