Android的Dialog弹出时隐藏导航栏效果,目前认为的最优解

时间:2022-07-22
本文章向大家介绍Android的Dialog弹出时隐藏导航栏效果,目前认为的最优解,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

原本Android的ProgressDialog用法很简单,两三行代码就搞定了。但是,但是,但是,用在无人值守的自助终端上,总是把之前隐藏掉的导航栏和状态栏显示出来。这是不可接受的。总不能让设备给用户随意摆弄吧,进入系统把你应用给搞没了都有可能。

项目中用到一个Android的ProgressDialog显示操作的进度条,机器要求是屏蔽或隐藏掉导航栏和虚拟按键的显示。

但是试了好多方法,也参考了网上的很多做法,隐藏安卓底部导航栏之后 弹出dialog或者popupwindow后,导航栏会再次显示出来,虽然可以设置在dialog的onStart中再次隐藏导航栏,但是会出现一个导航栏显示出来又马上隐藏掉的一个效果。这样会很影响体验,会闪一下虚拟栏再隐藏,或者隐藏了再显示回来。

经过一连串的尝试摸索,找到了个目前认为是见到过的最优解的方法。

如果谁有更好更简单的实现,欢迎留言,共同学习学习。

其间遇到过问题:

android.util.AndroidRuntimeException: requestFeature() must be called before adding content

这个错是因为调用的顺序问题,网上有解决办法。

在Activity中隐藏状态栏,要在setContentView(R.layout.activity_main)之前调用。

而Dialog中,需要在dialog.show()方法之后去调用。

alert.setCentView(xx); alertDialog.getWindow();放到alertDialog.show();后边调用。

至于原因,网上有人从源码的角度分析过这个问题。多学习多研究还是很有好处的,能够进一步提高能力。

在Activity中,虽然在setContentView(R.layout.activity_main)之前调用隐藏状态栏的代码,但是一旦Activity跳转,就又出来了,

解决办法是在隐藏状态栏逻辑代码的下面,加上一个状态栏变化的响应处理,在把它隐藏掉。

如下:

 /**
     * 隐藏虚拟按键:必须放到setContentView前面
     */
    protected void hideBottomUIMenu() {
        //隐藏虚拟按键,并且全屏
        if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
            View v = this.getWindow().getDecorView();
            v.setSystemUiVisibility(View.GONE);
        } else if (Build.VERSION.SDK_INT >= 19) {
            //for new api versions.
            View decorView = getWindow().getDecorView();
//            int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
//                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
//            int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |View.SYSTEM_UI_FLAG_LAYOUT_STABLE
//                    | View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_FULLSCREEN;
//            int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
//                    | View.INVISIBLE |
//                    View.SYSTEM_UI_FLAG_FULLSCREEN
//                    |View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
            int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.INVISIBLE
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                    | View .SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
            decorView.setSystemUiVisibility(uiOptions);
        }
    }

    protected void showBottomUIMenu() {
        //隐藏虚拟按键,并且全屏
        if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
            View v = this.getWindow().getDecorView();
            v.setSystemUiVisibility(View.VISIBLE);
        } else if (Build.VERSION.SDK_INT >= 19) {
            //for new api versions.
            View decorView =this.getWindow().getDecorView();
            decorView.setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_IMMERSIVE
                            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
        }
    }


//调用如下:
//在BaseActivity的OnCreate中,
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        hideBottomUIMenu();
        this.getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                hideBottomUIMenu();
            }
        });
        //setOrientation();
        //setContentView(initLayout());
        if (getLayResId() > 0) {
            setContentView(getLayResId());
        }
}

如何解决上述问题呢,直接封装一个类,继承自ProcessDialog,并且实现了调整默认字体的方法,

往下不多说了。直接贴出来代码:

package com.newcapec.smartorder.dialog;


import android.app.ProgressDialog;
import android.content.Context;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
/**
 * Created by yangyongzhen on 2019/05/22.
 */
public class MyProgressDialog extends ProgressDialog {

    private Window window;
    public MyProgressDialog(Context context) {
        super(context);
        this.window = getWindow();
    }

    /**
     * dialog 需要全屏的时候用,和clearFocusNotAle() 成对出现
     * 在show 前调用  focusNotAle   show后调用clearFocusNotAle
     *
     * @param window
     */
    private void focusNotAle(Window window) {
        window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
    }

    /**
     * dialog 需要全屏的时候用,focusNotAle() 成对出现
     * 在show 前调用  focusNotAle   show后调用clearFocusNotAle
     *
     * @param window
     */
    private void clearFocusNotAle(Window window) {
        window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
    }

    /**
     * 隐藏虚拟栏 ,显示的时候再隐藏掉
     *
     * @param window
     */
    public void hideNavigationBar(final Window window) {
        window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
        window.getDecorView().setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                        //布局位于状态栏下方
                        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
                        //全屏
                        View.SYSTEM_UI_FLAG_FULLSCREEN |
                        //隐藏导航栏
                        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
                        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
                if (Build.VERSION.SDK_INT >= 19) {
                    uiOptions |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
                } else {
                    uiOptions |= View.SYSTEM_UI_FLAG_LOW_PROFILE;
                }
                window.getDecorView().setSystemUiVisibility(uiOptions);
            }
        });
    }

    @Override
    public void show() {
        focusNotAle(window);
        super.show();
        hideNavigationBar(window);
        clearFocusNotAle(window);
    }

    public void setTextSize(View v, int size) {
        if (v instanceof ViewGroup) {
            ViewGroup parent = (ViewGroup) v;
            int count = parent.getChildCount();
            for (int i = 0; i < count; i++) {
                View child = parent.getChildAt(i);
                setTextSize(child, size);
            }
        } else if (v instanceof TextView) {
            ((TextView) v).setTextSize(size);
        }
    }
}

关于如何使用这个类,贴出来封装的一个工具类,支持调整进度条的透明度和长宽高,显示位置等属性:

package com.newcapec.smartorder.utils;

import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Point;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;

import com.newcapec.smartorder.dialog.MyProgressDialog;
/**
 * Created by yangyongzhen on 2019/05/22.
 */
public class ProgressDialogUtils {
    private static MyProgressDialog mProgressDialog;

    /**
     * 显示ProgressDialog
     *
     * @param context
     * @param message
     */
    public static void showProgressDialog(Context context, CharSequence message) {
        if (mProgressDialog == null) {
            mProgressDialog = new MyProgressDialog(context);
            mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);// 设置进度条的形式为圆形转动的进度条
            mProgressDialog.setCancelable(true);// 设置是否可以通过点击Back键取消
            mProgressDialog.setCanceledOnTouchOutside(true);// 设置在点击Dialog外是否取消Dialog进度条
            mProgressDialog.setMessage(message);
            mProgressDialog.show();
            Point size = new Point();
            mProgressDialog.getWindow().getWindowManager().getDefaultDisplay().getSize(size);
            int width = size.x;//获取界面的宽度像素
            int height = size.y;
            WindowManager.LayoutParams params = mProgressDialog.getWindow().getAttributes();//一定要用mProgressDialog得到当前界面的参数对象,否则就不是设置ProgressDialog的界面了
            params.alpha = 0.8f;//设置进度条背景透明度
            params.height = height / 8;//设置进度条的高度
            params.gravity = Gravity.LEFT;//设置ProgressDialog的重心
            params.x = 90;
            params.width = 3 * width / 5;//设置进度条的宽度
            params.dimAmount = 0f;//设置半透明背景的灰度,范围0~1,系统默认值是0.5,1表示背景完全是黑色的,0表示背景不变暗,和原来的灰度一样
            mProgressDialog.getWindow().setAttributes(params);//把参数设置给进度条,注意,一定要先show出来才可以再设置,不然就没效果了,因为只有当界面显示出来后才可以获得它的屏幕尺寸及参数等一些信息

            View v = mProgressDialog.getWindow().getDecorView();
            mProgressDialog.setTextSize(v,24);
            mProgressDialog.getWindow().getDecorView().setSystemUiVisibility(uiOptions);
//				}
//			});
        } else {
            mProgressDialog.show();
        }
        //setDialogText(v);
        //隐藏状态栏和底部的虚拟键
    }

    /**
     * 关闭ProgressDialog
     */
    public static void dismissProgressDialog() {
        if (mProgressDialog != null) {
            mProgressDialog.dismiss();
            mProgressDialog = null;
        }
    }
}