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

简介: 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;
        }
    }
}


相关文章
|
7月前
|
Java Maven Android开发
Android弹出dialog提示框演示
Android弹出dialog提示框演示
61 1
|
7月前
|
Android开发
Android Studio APP开发入门之对话框Dialog的讲解及使用(附源码 包括提醒对话框,日期对话框,时间对话框)
Android Studio APP开发入门之对话框Dialog的讲解及使用(附源码 包括提醒对话框,日期对话框,时间对话框)
182 0
|
4月前
|
API Android开发 开发者
Android经典实战之用WindowInsetsControllerCompat方便的显示和隐藏状态栏和导航栏
本文介绍 `WindowInsetsControllerCompat` 类,它是 Android 提供的一种现代化工具,用于处理窗口插入如状态栏和导航栏的显示与隐藏。此类位于 `androidx.core.view` 包中,增强了跨不同 Android 版本的兼容性。主要功能包括控制状态栏与导航栏的显示、设置系统窗口行为及调整样式。通过 Kotlin 代码示例展示了如何初始化并使用此类,以及如何设置系统栏的颜色样式。
244 2
|
4月前
|
API Android开发 Kotlin
Android实战经验分享之如何获取状态栏和导航栏的高度
在Android开发中,掌握状态栏和导航栏的高度对于优化UI布局至关重要。本文介绍两种主要方法:一是通过资源名称获取,简单且兼容性好;二是利用WindowInsets,适用于新版Android,准确性高。文中提供了Kotlin代码示例,并对比了两者的优缺点及适用场景。
393 1
|
5月前
|
XML Android开发 数据格式
Android 中如何设置activity的启动动画,让它像dialog一样从底部往上出来
在 Android 中实现 Activity 的对话框式过渡动画:从底部滑入与从顶部滑出。需定义两个 XML 动画文件 `activity_slide_in.xml` 和 `activity_slide_out.xml`,分别控制 Activity 的进入与退出动画。使用 `overridePendingTransition` 方法在启动 (`startActivity`) 或结束 (`finish`) Activity 时应用这些动画。为了使前 Activity 保持静止,可定义 `no_animation.xml` 并在启动新 Activity 时仅设置新 Activity 的进入动画。
154 12
|
5月前
|
XML Android开发 数据格式
Android面试题之DialogFragment中隐藏导航栏
在Android中展示全屏`DialogFragment`并隐藏状态栏和导航栏,可通过设置系统UI标志实现。 记得在布局文件中添加内容,并使用`show()`方法显示`DialogFragment`。
77 2
|
6月前
|
Android开发
Android中如何动态的调整Dialog的背景深暗
在Android开发中,Dialog和DialogFragment可通过设置`Window`的`backgroundDimAmount`来控制背景变暗,突出对话框。在DialogFragment的`onCreateDialog`或`onViewCreated`中,获取`Dialog`的`Window`,设置`LayoutParams.dimAmount`(例如0.5f)并添加`FLAG_DIM_BEHIND`标志。要动态调整,可保存`LayoutParams`并在需要时更新。对于Dialog,创建时直接设置同样属性。还可以通过定义主题样式设置背景模糊程度。
173 7
|
7月前
|
Java Android开发 Kotlin
Android Dialog 弹出时,隐藏 navigation bar
Android Dialog 弹出时,隐藏 navigation bar
138 1
|
7月前
|
XML 存储 测试技术
Android系统 添加动态控制SystemUI状态栏、导航栏和下拉菜单
Android系统 添加动态控制SystemUI状态栏、导航栏和下拉菜单
1334 1
|
7月前
|
XML Android开发 数据格式
android 9 Systemui 动态隐藏导航栏
android 9 Systemui 动态隐藏导航栏
243 0