Android PopupWindow下拉筛选

俗话说:不想当工程师的泥瓦工不是好程序员!
今天我们要实现的最终效果,如下:
Android PopupWindow下拉筛选_第1张图片

其实实现这样的效果不是很难,俗话说:条条大路通罗马。正常路子走不通,咱还不会走野路子呀。
方案一:在RecyclerView上面覆盖一层布局,设置显示和隐藏,大不了在显示和隐藏的时候加个动画呗;
方案二:使用PopupWindow;
方案三:使用Dialog。其他方案自行查找!
此时我想起我有一次面试,面试官问拿着他们开发的app,给我看一个侧滑菜单的功能,然后就问我这个你知道是怎么实现的吗?我说最简单的就弄个布局设置显示隐藏呗,面试官严肃的给我说这个不是这样实现的,一边摇头一边说不是,我就说这样也可以实现的,再说我也没说其他方式实现不了呀。我心里面一万个羊驼在奔腾呀!言归正传,撸码
首先自定义一个popupWindow,如下:

public DownPopupWindow(Activity context, List popupWindowList, String checkedName) {
        super(context);
        this.mContext = context;
        this.mPopupWindowList = popupWindowList;
        this.mCheckedName = checkedName;

        View view = LayoutInflater.from(mContext).inflate(R.layout.layout_popupwindow, null, false);
        this.setContentView(view);
        this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
        this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
        ColorDrawable colorDrawable = new ColorDrawable(mContext.getResources().getColor(R.color.color_66000000));
        this.setBackgroundDrawable(colorDrawable);
        this.setFocusable(true);
        this.setOutsideTouchable(true);
        this.update();


        mPopupWindowAdapter = new PopupWindowAdapter(mPopupWindowList, mContext);
        RecyclerView recyclerView = view.findViewById(R.id.rv_recycler);
        recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
        recyclerView.setAdapter(mPopupWindowAdapter);

        for (int i = 0; i < mPopupWindowList.size(); i++) {
            if (mCheckedName.equals(mPopupWindowList.get(i).getName())) {
                mPopupWindowList.get(i).setChecked(true);
            } else {
                mPopupWindowList.get(i).setChecked(false);
            }
        }
    }

代码很简单,设置布局的宽高,透明的背景以及外部焦点,还有在里面加了一个RecyclerView的列表数据。
布局如下:


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

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_recycler"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:overScrollMode="never"
        android:background="#ffffff">
    android.support.v7.widget.RecyclerView>

FrameLayout>

也很简单就一个RecyclerView展示我们需要的筛选条件。
我们提供一个展示的方法,如下:

public void showDialog(View view){
        if (this.isShowing()) {
            dismiss();
        } else {
            this.showAsDropDown(view);
        }
    }

在我们的Activity中调用这个方法,如下:

llTwo.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        mDownPopupWindow = new DownPopupWindow(MainActivity.this, TestBean.getPopupWindowList(), tvTwo.getText().toString()) {
            @Override
            public void getItem(String id, String name) {
                if (mDownPopupWindow.isShowing()) {
                    dismiss();
                }
                tvTwo.setText(name);
                tvTwo.setTextColor(getColor(R.color.colorAccent));
            }
        };

        mDownPopupWindow.showDialog(llTwo);
    }
});

运行看一下效果,如下:
Android PopupWindow下拉筛选_第2张图片
what?说好的半透明呢。网上都说设置setBackgroundDrawable属性就好,再看咱的代码也设置了呀,但是没有啥软用呀?那就解决呗,方式一:覆盖一层半透明,在PopupWindow show的时候显示,dismiss的时候隐藏,不好看?加动画呗(很简单暂时不做代码展示)。方式二:网上的另一种解决方案,给整个手机屏幕设置半透明,那就实现一下呗,代码如下:

public static void setBackgroundAlpha(Activity activity, float bgAlpha) {
    WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
    lp.alpha = bgAlpha;
    if (bgAlpha == 1) {
        //不移除该Flag的话,在有视频的页面上的视频会出现黑屏的bug
        activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    } else {
        //此行代码主要是解决在华为手机上半透明效果无效的bug
        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    }
    activity.getWindow().setAttributes(lp);
}

在我们PopupWindow展示的方法中设置半透明,如下:

public void showDialog(View view){
    if (this.isShowing()) {
        dismiss();
    } else {
        this.showAsDropDown(view);
        setBackgroundAlpha(mContext,0.5f);
    }
}

然后在PopupWindow的dismiss监听中设置全透明,如下

this.setOnDismissListener(new OnDismissListener() {
    @Override
    public void onDismiss() {
        setBackgroundAlpha(mContext,1f);
    }
});

运行看一下效果,如下
Android PopupWindow下拉筛选_第3张图片
什么鬼?用户看到这效果,心里一万个羊驼在奔腾呀!从底部弹出的效果使用这样的方式可以。如下图:
Android PopupWindow下拉筛选_第4张图片
问题是我们要的不是这样的需求呀!看来这种效果此方案是行不通的,方案三:showAtLocation,代码如下

public void showDialog2(View view){
        if (isShowing()) {
            dismiss();
        } else {
            int[] location = new int[2];
            view.getLocationOnScreen(location);
            WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
            int screenHeight = wm.getDefaultDisplay().getHeight();
            setHeight(screenHeight - location[1] - view.getHeight());
            showAtLocation(view, Gravity.NO_GRAVITY, 0, location[1] + view.getHeight());
        }
    }

运行结果如下
Android PopupWindow下拉筛选_第5张图片
完美实现我们开始想要的效果。

效果是实现了,但是功能上体验如何?点击半透明部分PopopWindow消失?我们试试,果然没啥反应。问题是我们也设置了属性:

this.setFocusable(true);
this.setOutsideTouchable(true);

那为啥不行呢?因为我们的布局是设置除了选择按钮以上部分的屏幕剩余全部部分,也就是对于我们的PopupWindow布局没有外面的布局可以显示了,我们设置的属性是点击PopupWindow之外可以消失。何以见的?我们按照开始设置PopupWindow方式:

public void showDialog(View view){
        if (this.isShowing()) {
            dismiss();
        } else {
            this.showAsDropDown(view);
        }
    }

没有半透明的背景,也就是我们的PopupWindow不是全屏的,这个时候我们点击外部试一试,果然能让PopupWindow消失。我们也可以点击按钮上面的部分也就是标题部分,也能让PopupWindow消失。
既然我们想要半透明的效果还希望点击半透明部分区域能够让PopupWindow消失,那我们就自己处理半透明部分的点击事件,方式一:

this.setTouchInterceptor(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
                    dismiss();
                    return true;
                }
                return false;
            }
        });

其实这个和上面设置属性没啥区别,无效。方式二:

this.setTouchInterceptor(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (isShowing()) {
                    dismiss();
                    return true;
                }
                return false;
            }
        });

判断条件变了,测试发现点击半透明部分可以实现让PopupWindow消失,但是,当我们点击我们的筛选条件选项的时候就出问题了,点击之后没有选中我们点击的,PopupWindow就直接消失了,测试发现这个RecyclerView选项的点击事件被后来我们设置的监听消费掉了。方式三:

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

view是什么呢?就是PopupWindow的布局,我们给整个布局加上一个点击事件,完美解决问题。

备注:

这种实现方式在某些非常规手机上是否会存在问题呢?比如:全面屏手机,刘海屏手机。

你可能感兴趣的:(Android,PopupWindow)