PopupWindow实现屏幕底部弹出

PopupWindow实现屏幕底部弹出_第1张图片

1 实现原理:

1)通过style实现弹出与消失的动画
2)Window实现背景在弹框显示消失时的明暗效果
3)showAtLocation控制弹框位置

2 代码

1、 MainActivity和PopupWindow布局

activity_main.xml:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/layout_main"
    android:gravity="center_horizontal"
    tools:context="com.bpj.popwindow.MainActivity">

    <Button
        android:layout_marginTop="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="popup"
        android:onClick="popup"
         />
    <Button
        android:layout_marginTop="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="dismiss"
        android:onClick="dismiss"
        />
LinearLayout>

popu.xml:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="200dp"
    android:layout_height="60dp"
    android:background="@color/colorPrimary"
    >
    <TextView
        android:layout_width="wrap_content"
        android:text="111"
        android:layout_height="60dp" />

LinearLayout>

2、定义style

anim文件夹下:
menu_bottombar_in.xml显示动画


<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromYDelta="100.0%"
        android:toYDelta="0.0" />
set>

menu_bottombar_out.xml消失动画


<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromYDelta="0.0"
        android:toYDelta="100%" />
set>

style中:

 

3、MainActivity中

public class MainActivity extends AppCompatActivity {

    private PopupWindow popupWindow;
    private WindowManager.LayoutParams params;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         params = getWindow().getAttributes();
    }

    /**
     * 这里popupWindow用的是showAtLocation而不是showAsDropDown
     * popupWindow.isShowing会一直返回false,所以要重新定义一个变量
     * 要注意setOutsideTouchable的干扰
     */
    private boolean mIsShowing = false;

    public void popup(View view){
        if(popupWindow == null){
            initPopup();
        }
        if(!mIsShowing){
            params.alpha= 0.3f;
            getWindow().setAttributes(params);
            popupWindow.showAtLocation(findViewById(R.id.layout_main),Gravity.BOTTOM,0,0);
            mIsShowing = true;
        }
    }

    private void initPopup() {
        View pop = View.inflate(this, R.layout.popu, null);
        popupWindow = new PopupWindow(pop, ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
        popupWindow.setTouchable(true);
        popupWindow.setOutsideTouchable(false);
        popupWindow.setBackgroundDrawable(new BitmapDrawable(getResources(), (Bitmap) null));
        popupWindow.setAnimationStyle(R.style.anim_menu_bottombar);
        mIsShowing = false;
    }


    public void dismiss(View view){
        if(popupWindow != null &&mIsShowing){
            popupWindow.dismiss();
            mIsShowing = false;
            params.alpha= 1f;
            getWindow().setAttributes(params);
        }
    }
}

3 注意

1 异常:Activity has leaked window android.widget.PopupWindow

产生原因:窗体泄漏,每一个Activity都有个WindowManager窗体管理器,同样,构建在某个Activity之上的对话框、PopupWindow也有相应的WindowManager窗体管理器。因为对话框、PopupWindown不能脱离Activity而单独存在着,所以当某个Dialog或者某个PopupWindow正在显示的时候我们去finish()了承载该Dialog(或PopupWindow)的Activity时,就会抛Window Leaked异常了,因为这个Dialog(或PopupWindow)的WindowManager已经没有谁可以附属了,所以它窗体管理器已经泄漏了。Activity 中create 一个Dialog,若你先关闭Dialog再关闭Activity就是正常的,若你先关闭Activity再关闭Dialog就会报错这个android.view.WindowLeaked错误了。

解决方法:关闭(finish)某个Activity前,要确保附属在上面的Dialog或PopupWindow已经关闭(dismiss)了。也可在OnCreateDialog()中创建Dialog,让系统去管理对话框

2 isShowing()一直返回false

popupWindow用的是showAtLocation而不是showAsDropDown
* popupWindow.isShowing会一直返回false,所以要重新定义一个变量
* 要注意setOutsideTouchable的干扰,setOutsideTouchable设置为false

3 showAsDropDown在某些版本报错

重新该方法:

    @Override
public void showAsDropDown(View anchorView, int xoff, int yoff, int gravity) {
        if (getHeight() == ViewGroup.LayoutParams.MATCH_PARENT &&
                Build.VERSION.SDK_INT >= 24) { // Build.VERSION_CODES.N
            int[] a = new int[2];
            anchorView.getLocationInWindow(a);

            int yoffInWindow = a[1] + anchorView.getHeight() + yoff;

            setHeight(getPopMatchHeight(anchorView.getContext(), yoffInWindow));

            showAtLocation(anchorView, gravity, xoff, yoffInWindow);
        } else {
            super.showAsDropDown(anchorView, xoff, yoff, gravity);
        }
}

  private int getPopMatchHeight(Context context, int yoffInWindow) {
        return  context.getResources().getDisplayMetrics().heightPixels - yoffInWindow;
    }

你可能感兴趣的:(Android应用)