Android4.0的StatusBar和NavigationBar

本文详细解析了Android系统中平板与手机UI布局的切换原理,重点介绍了如何通过调整屏幕密度实现不同设备间的布局变化,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要是注意平板和手机之间布局的区别:
几个关键的java类
SystemUIService
PhoneWindowManager
WindowManagerPolicy
PhoneStatusBar
TabletStatusBar
NavigationBar


    SystemUIService-->onCreate中判断加载平板布局还是手机布局
       
 	// Pick status bar or system bar.
        IWindowManager wm = IWindowManager.Stub.asInterface(
                ServiceManager.getService(Context.WINDOW_SERVICE));
        try {
            SERVICES[0] = wm.canStatusBarHide()
                    ? R.string.config_statusBarComponent
                    : R.string.config_systemBarComponent;
        } catch (RemoteException e) {
            Slog.w(TAG, "Failing checking whether status bar can hide", e);
        }
    然后在frameworks\base\packages\systemui\res\values\config.xml中
        
	<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>
        <string name="config_systemBarComponent" translatable="false">com.android.systemui.statusbar.tablet.TabletStatusBar</string>

    然后通过类加载器加载PhoneStatusBar或者TabletStatusBar。也就是手机的状态栏还是平板的状态栏。
    判断的关键就在wm.canStatusBarHide()这个方法里面。
    我们跳过几个类后最后跟进到PhoneWindowManager中:    
	public boolean canStatusBarHide() {
            return mStatusBarCanHide;
        }
    mStatusBarCanHide是一个成员变量,修改它值得地方在:
     public void setInitialDisplaySize(int width, int height) {...}中。
	int shortSizeDp = shortSize
                * DisplayMetrics.DENSITY_DEFAULT
                / DisplayMetrics.DENSITY_DEVICE;
        mStatusBarCanHide = shortSizeDp < 600;
        mStatusBarHeight = mContext.getResources().getDimensionPixelSize(
                mStatusBarCanHide
                ? com.android.internal.R.dimen.status_bar_height
                : com.android.internal.R.dimen.system_bar_height);

        mHasNavigationBar = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_showNavigationBar);
        // Allow a system property to override this. Used by the emulator.
        // See also hasNavigationBar().
        String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
        if (! "".equals(navBarOverride)) {
            if      (navBarOverride.equals("1")) mHasNavigationBar = false;
            else if (navBarOverride.equals("0")) mHasNavigationBar = true;
        }

    这个方法略微有点长,绕过前面的判断,取上面一部分来分析。大致的意思是:
    首先取shortSize,shortSize指的是屏幕最短的像素,比如1024*600,那么值就是600。 shortSizeDp是把pix单位转化成dip单位。  DisplayMetrics.DENSITY_DEFAULT的值是固定死的160,在更具手机的密度算出shortSizeDp。突出标记的地方就是平板和手机状态栏切换的关键了。只有最短屏幕dp大于600的设备才会加载平板布局。
    剩下的代码用来判断底部虚拟按键是否显示的关键。首先是去读取frameworks\base\core\res\res\values\config.xml中config_showNavigationBar这个key,下面 SystemProperties.get("qemu.hw.mainkeys")这个属性主要是给模拟器使用,可以直接忽略掉。
    分析完毕!
    现在如何切换平板和手机状态栏布局已经很明了了,就是让shortSizeDp 的值>=600。以1024*600为例,因为DisplayMetrics.DENSITY_DEFAULT的值已经固定死是160,所以只要把DisplayMetrics.DENSITY_DEVICE的值<=160即可。修改屏幕密度的方法:
    /build/tools/buildinfo.sh中设定 ro.sf.lcd_density=160,
    当然MTK自己定义了一套属性,MTK项目中可以通过这个属性来设置,比较保险
    /mediatek/config/[Project_name]/system.prop中设定该属性的值
如此基本大功告成。mm编译,然后报错。。。。
错误定位到TabletStatusBar的makeStatusBarView()中,代码如下:
   
	 try {
            // Sanity-check that someone hasn't set up the config wrong and asked for a navigation
            // bar on a tablet that has only the system bar
            if (mWindowManager.hasNavigationBar()) {
                throw new RuntimeException(
                        "Tablet device cannot show navigation bar and system bar");
            }
        } catch (RemoteException ex) {
        }

    问题很明显,平板设备中不需要NavigationBar,因为NavigationBar的东西已经全部合并到StatusBar里面了。修改方法:
    frameworks\base\core\res\res\values\config.xml中config_showNavigationBar修改为false


啰嗦半天,其实就两个问题:
    一。虚拟按键的隐藏和显示:
     修改frameworks\base\core\res\res\values\config.xml中config_showNavigationBar

    二。状态栏平板和手机之间的切换:
    1.        /build/tools/buildinfo.sh中设定 ro.sf.lcd_density=160,
        当然MTK自己定义了一套属性,MTK项目中可以通过这个属性来设置,比较保险
        /mediatek/config/[Project_name]/system.prop中设定该属性的值
  2.    frameworks\base\core\res\res\values\config.xml中config_showNavigationBar修改为false
    

Android Q中,实现SystemUI的插件化开发,允许开发者自定义statusBarnavigationBar的外观功能,这对于提供个性化用户体验至关重要。具体步骤包括: 参考资源链接:[AndroidQ SystemUI插件化实战:创建与应用](https://wenku.csdn.net/doc/6cuhxt07ou?spm=1055.2569.3001.10343) 1. **创建插件类**:首先需要创建一个继承自`OverlayPlugin`的插件类,例如`MyOverlayPlugin`,并实现接口定义的方法。 2. **实现接口方法**:实现`onPluginConnected()``onPluginDisconnected()`方法,分别在插件加载卸载时执行特定操作。 3. **管理插件状态**:通过`PluginManager`监听插件的连接与断开,并利用`ArraySet`管理已连接插件的集合。 4. **自定义UI组件**:在`setup()`方法中获取statusBarnavigationBarView的实例,并实现自定义的UI逻辑。 5. **添加版本控制**:使用`@Requires`注解进行版本管理,确保插件与SystemUI版本兼容。 6. **编译部署**:将插件编译为APK文件,并通过设备的系统设置部署,或者作为系统应用的一部分进行安装。 在这一过程中,开发者可以参考《AndroidQ SystemUI插件化实战:创建与应用》提供的详细指导示例代码,该文档深入解析了插件化机制的原理实践操作,为开发者提供了从概念到实现的完整知识链条。 通过上述步骤,开发者可以灵活地修改扩展statusBarnavigationBar的功能外观,例如更改颜色、布局或添加新的手势操作,从而使得应用更加符合特定的用户需求。 参考资源链接:[AndroidQ SystemUI插件化实战:创建与应用](https://wenku.csdn.net/doc/6cuhxt07ou?spm=1055.2569.3001.10343)
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值