把android 4.2平板的状态栏从底部挪到顶部 NavigationBar

23 篇文章 0 订阅

没在网上搜到相关文章,只能自己动手丰衣足食了,留下足迹以给后来人参考


需要修改的文件:

1、frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\tablet\TabletStatusBar.java 

把该文件中类似 Gravity.BOTTOM  都改为  Gravity.TOP

2、frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindowManager.java

这个文件很重要,很多需要隐藏状态栏的大大们都没有想到隐藏个状态栏还需要改这个东西,造成出现问题:状态栏是隐藏了,可是底部还是有一个黑色条

这个黑色的条其实就是状态栏的位置了

函数 beginLayoutLw

if (mNavigationBarOnBottom) {
                    // It's a system nav bar or a portrait screen; nav bar goes on bottom.
                    int top = displayHeight - mNavigationBarHeightForRotation[displayRotation];
                    mTmpNavigationFrame.set(0, top, displayWidth, displayHeight);
                    mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
                    if (navVisible) {
                        mNavigationBar.showLw(true);
                        mDockBottom = mTmpNavigationFrame.top;
                        mRestrictedScreenHeight = mDockBottom - mDockTop;
                    } else {
                        // We currently want to hide the navigation UI.
                        mNavigationBar.hideLw(true);
                    }
                    if (navVisible && !mNavigationBar.isAnimatingLw()) {
                        // If the nav bar is currently requested to be visible,
                        // and not in the process of animating on or off, then
                        // we can tell the app that it is covered by it.
                        mSystemBottom = mTmpNavigationFrame.top;
                    }
-》

             if (mNavigationBarOnBottom) {
                    // It's a system nav bar or a portrait screen; nav bar goes on bottom.
                    int top = displayHeight - mNavigationBarHeightForRotation[displayRotation];
	             if (DEBUG_LAYOUT) Log.i(TAG, "mStatusBarHeight: " + mStatusBarHeight+ "   mNavBarHeight:"+mNavBarHeight);

                    mTmpNavigationFrame.set(0, 0, displayWidth, mNavBarHeight);
                    mStableTop = mStableFullscreenTop = mTmpNavigationFrame.bottom;
                    if (navVisible) {
                        mNavigationBar.showLw(true);
                        mDockTop = mTmpNavigationFrame.bottom;
                        mRestrictedScreenHeight = mDockBottom - mDockTop;

			     mRestrictedScreenTop = mNavBarHeight; 	
                    } else {
                        // We currently want to hide the navigation UI.
                        mNavigationBar.hideLw(true);
                    }
                    if (navVisible && !mNavigationBar.isAnimatingLw()) {
                        // If the nav bar is currently requested to be visible,
                        // and not in the process of animating on or off, then
                        // we can tell the app that it is covered by it.
                        mSystemTop = mTmpNavigationFrame.bottom;

其中

mNavBarHeight 是新增的变量可以通过以下方法初始化
mNavBarHeight = mContext.getResources().getDimensionPixelSize(
        com.android.internal.R.dimen.navigation_bar_height);


3、frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\tablet\NotificationPanel.java   

修改内部类 Choreographer的方法createAnimation     这处修改是为点击notification区域的弹出和隐藏动画的,修改前是向底部隐藏从底部出现,修改后是向顶部隐藏从顶部出现

            if (appearing) {
                // we want to go from near-the-top to the top, unless we're half-open in the right
                // general vicinity
                end = 0;
                if (mNotificationCount == 0) {
                    end += mContentFrameMissingTranslation;
                }
                start = HYPERSPACE_OFFRAMP+end;
            } else {
                start = y;
                end = y + HYPERSPACE_OFFRAMP;
            }

-》

            if (appearing) {
                // we want to go from near-the-top to the top, unless we're half-open in the right
                // general vicinity
                end = 0;
                if (mNotificationCount == 0) {
                    end += mContentFrameMissingTranslation;
                }
                start = - HYPERSPACE_OFFRAMP;
            } else {
                start = y;
                 end = y - HYPERSPACE_OFFRAMP;
           }

4、frameworks\base\core\java\android\view\ViewRootImpl.java    这个是为了修改bug: 把状态栏从底部移动到顶部 隐藏状态栏后无法再显示状态栏

                if(e1.getY()>dm.heightPixels-GESTURE_AREA_HEIGHT){
                    float y = e1.getY()-e2.getY();
->

                if(e1.getY()<GESTURE_AREA_HEIGHT){
                    float y = e2.getY()-e1.getY();


5、xml文件

Index: styles.xml
===================================================================
--- styles.xml	(revision 16)
+++ styles.xml	(revision 15)
@@ -129,16 +129,15 @@
     <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer" />
 
     <style name="Animation" />
-    
+
     <style name="Animation.ShirtPocketPanel">
-        <item name="android:windowEnterAnimation">@*android:anim/grow_fade_in</item>
-        <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out</item>
+        <item name="android:windowEnterAnimation">@*android:anim/grow_fade_in_from_bottom</item>
+        <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out_from_bottom</item>
     </style>
 
     <style name="Animation.RecentPanel">
-        <item name="android:windowEnterAnimation">@*android:anim/grow_fade_in</item>
-        <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out</item>
+        <item name="android:windowEnterAnimation">@*android:anim/grow_fade_in_from_bottom</item>
+        <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out_from_bottom</item>
     </style>
 
     <!-- Standard animations for hiding and showing the status bar. -->
@@ -169,7 +168,7 @@
     <style name="ClingTitleText">
         <item name="android:layout_width">wrap_content</item>
         <item name="android:layout_height">wrap_content</item>
-        <item name="android:layout_marginTop">5dp</item>
+        <item name="android:layout_marginBottom">5dp</item>
         <item name="android:textSize">23sp</item>
         <item name="android:textColor">#49C0EC</item>
         <item name="android:shadowColor">#000000</item>
Index: system_bar_notification_panel.xml
===================================================================
--- system_bar_notification_panel.xml	(revision 16)
+++ system_bar_notification_panel.xml	(revision 15)
@@ -21,16 +21,16 @@
     android:id="@+id/content_parent"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
-    android:gravity="right|top"
+    android:gravity="right"
     >
 
     <!-- lift the panel up off the status bar while leaving a touchable are -->
     <Space
         android:id="@+id/system_bar_notification_panel_bottom_space"
-        android:layout_height="50dp"
+        android:layout_height="56dp"
         android:layout_width="478dp"
         android:layout_alignParentRight="true"
-        android:layout_alignParentTop="true"
+        android:layout_alignParentBottom="true"
         />
 
     <LinearLayout
@@ -40,8 +40,8 @@
         android:layout_width="478dp"
         android:orientation="vertical"
         android:layout_alignParentRight="true"
-        android:layout_below="@id/system_bar_notification_panel_bottom_space"
-        android:paddingTop="8dp"
+        android:layout_above="@id/system_bar_notification_panel_bottom_space"
+        android:paddingBottom="8dp"
         >
 
         <include layout="@layout/system_bar_notification_panel_title"
Index: system_bar.xml
===================================================================
--- system_bar.xml	(revision 16)
+++ system_bar.xml	(revision 15)
@@ -23,12 +23,11 @@
     android:background="@drawable/system_bar_background"
     >
     
     <FrameLayout
         android:id="@+id/bar_contents_holder"
         android:layout_width="match_parent"
         android:layout_height="@*android:dimen/system_bar_height"
-        android:layout_gravity="top"
+        android:layout_gravity="bottom"
         >
         <RelativeLayout
             android:id="@+id/bar_contents"
@@ -136,7 +135,7 @@
         android:id="@+id/bar_shadow_holder"
         android:layout_width="match_parent"
         android:layout_height="@*android:dimen/system_bar_height"
-        android:layout_gravity="top"
+        android:layout_gravity="bottom"
         >
         <!-- lights out shade -->
         <RelativeLayout
@@ -152,7 +151,7 @@
                 android:layout_height="48dip"
                 android:src="@drawable/ic_sysbar_lights_out_dot_small"
                 android:layout_alignParentLeft="true"
-                android:layout_alignParentTop="true"
+                android:layout_alignParentBottom="true"
                 />
             <ImageView
                 android:id="@+id/dot1"
@@ -160,7 +159,7 @@
                 android:layout_height="48dip"
                 android:src="@drawable/ic_sysbar_lights_out_dot_large"
                 android:layout_toRightOf="@+id/dot0"
-                android:layout_alignParentTop="true"
+                android:layout_alignParentBottom="true"
                 />
             <ImageView
                 android:id="@+id/dot2"
@@ -168,7 +167,7 @@
                 android:layout_height="48dip"
                 android:src="@drawable/ic_sysbar_lights_out_dot_small"
                 android:layout_toRightOf="@+id/dot1"
-                android:layout_alignParentTop="true"
+                android:layout_alignParentBottom="true"
                 />
             <ImageView
                 android:id="@+id/dot3"
@@ -176,7 +175,7 @@
                 android:layout_height="48dip"
                 android:src="@drawable/ic_sysbar_lights_out_dot_small"
                 android:layout_alignParentRight="true"
-                android:layout_alignParentTop="true"
+                android:layout_alignParentBottom="true"
                 />
         </RelativeLayout>
     </FrameLayout>


以下内容转自 : http://blog.csdn.net/yunnywu/article/details/7629760


android4.0系统可以运行于平板电脑和手机上面,这样对于状态栏来说,也是有不同风格的,从SystemUi的代码分类我就可以看出来,google考虑了不同情况下状态栏的显示等,

在源代码里面有这么两个文件夹需要注意:

com.android.systemui.statusbar.phone  这个是针对手机而需要的status bar

com.android.systemui.statusbar.tablet   这个是针对平板电脑而需要的staus bar(system bar)

 

首先状态栏是如何启动起来的呢?

我们都知道系统刚启动,在SystemServer会加载系统的各种服务,状态栏也不例外,就是在这个时候创建的,代码如下:

SystemServer.java

 ActivityManagerService.self().systemReady(new Runnable() {
            public void run() {
                Slog.i(TAG, "Making services ready");

                startSystemUi(contextF);
                try {
                    if (batteryF != null) batteryF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Battery Service ready", e);
                }

 

static final void startSystemUi(Context context) {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.android.systemui",
                    "com.android.systemui.SystemUIService"));
        Slog.d(TAG, "Starting service: " + intent);
        context.startService(intent);
    }

 

通过上面的代码我就看到系统启动了com.android.systemui.SystemUIService 这个服务,在这个服务里面就会启动状态栏,

但是这里就会有个选择,是启动status bar呢 还是启动 system bar呢,android是这么决定的:

public void onCreate() {
        // Pick status bar or system bar.
        IWindowManager wm = IWindowManager.Stub.asInterface(
                ServiceManager.getService(Context.WINDOW_SERVICE));
        try {
            SERVICES[0] = wm.canStatusBarHide()  (1)
                    ? R.string.config_statusBarComponent(2)
                    : R.string.config_systemBarComponent;(3)
        } catch (RemoteException e) {
            Slog.w(TAG, "Failing checking whether status bar can hide", e);
        }

        final int N = SERVICES.length;
        mServices = new SystemUI[N];
        for (int i=0; i<N; i++) {
            Class cl = chooseClass(SERVICES[i]);
            Slog.d(TAG, "loading: " + cl);
            try {
                mServices[i] = (SystemUI)cl.newInstance();
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InstantiationException ex) {
                throw new RuntimeException(ex);
            }
            mServices[i].mContext = this;
            Slog.d(TAG, "running: " + mServices[i]);
            mServices[i].start();
        }
    }

 

上面的(1) 出,会调用到phoneWIndowManager里面对应的那个函数,在那里面会根据配置文件,手机宽高等信息来判断使用哪一种bar,代码如下

public boolean canStatusBarHide() {
        return mStatusBarCanHide;
    }

 if (width > height) {
            shortSize = height;
          .........

        } else {
            shortSize = width;
          .......

        }

        // Determine whether the status bar can hide based on the size
        // of the screen.  We assume sizes > 600dp are tablets where we
        // will use the system bar.
        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);

 

这里假如手机宽(高) 小于600dp,就认为是手机了,这样mStatusBarHide = true;

我们回到这里

SERVICES[0] = wm.canStatusBarHide()  

                    ? R.string.config_statusBarComponent;

                    : R.string.config_systemBarComponent;

这样SERVICES[0]  = R.string.config_statusBarComponent (这个字符串就是 com.anroid.systemui.statusbar.phone)

实际上SERVERCES这个数组里面就两个元素,一个是我们上面的那个com.anroid.systemui.statusbar.phone ,另外一个是PowerUI,这个暂且不管,这个主要是根据电量等信息弹出一些提示框,比如电量低,或者充电器有问题等框。

接下来会调用com.anroid.systemui.statusbar.phone的start方法,注意com.anroid.systemui.statusbar.phone这个类不是一个服务,就是一个普通的类,start方法也是它的一个普通的方法而已。

在start方法里面就会创建状态栏那些界面对应的各种view,包括下拉状态栏后的view等,把这些view都创建好以后,就把这个view加载windowmanager里面就可以了,这样状态栏就可以显示出来了,代码如下:

 

final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                height,
                WindowManager.LayoutParams.TYPE_STATUS_BAR,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                PixelFormat.OPAQUE);
        
        // the status bar should be in an overlay if possible
        final Display defaultDisplay 
            = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
                .getDefaultDisplay();
        if (ActivityManager.isHighEndGfx(defaultDisplay)) {
            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        }

        lp.gravity = getStatusBarGravity();
        lp.setTitle("StatusBar");
        lp.packageName = mContext.getPackageName();
        lp.windowAnimations = R.style.Animation_StatusBar;
        WindowManagerImpl.getDefault().addView(sb, lp);  //这里的sb就是状态栏view

 

这里需要注意的是 平时看到的状态栏和下拉后的状态栏是两个东西,不要混到一起,而且这里也会创建两个view,一个是普通的状态栏view,另外一个下拉后的view,这两个view都要加载WindosManager里面,添加的代码基本一样,但是最重要的是那个参数里面的type是不一样的,一个是WindowManager.LayoutParams.TYPE_STATUS_BAR,而下拉的那个type是WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;



  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要取消 Android 底部导航栏的半透明/毛玻璃效果,可以在 styles.xml 文件中的 AppTheme 样式中添加以下属性: ```xml <item name="android:navigationBarColor">@android:color/transparent</item> <item name="android:windowTranslucentNavigation">false</item> ``` 其中,`android:navigationBarColor` 属性设置为 `@android:color/transparent` 表示将导航栏的颜色设置为透明,`android:windowTranslucentNavigation` 属性设置为 `false` 表示取消导航栏的半透明效果。 完整的 AppTheme 样式如下: ```xml <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- 取消导航栏的半透明效果 --> <item name="android:navigationBarColor">@android:color/transparent</item> <item name="android:windowTranslucentNavigation">false</item> <!-- 其他属性 --> <!-- ... --> </style> ``` 如果想要实现 Android 底部导航栏毛玻璃效果,可以使用 Android 系统提供的 `BlurDrawable` 类来实现。具体实现步骤可以参考以下代码: ```java // 创建一个 BlurDrawable 对象 BlurDrawable blurDrawable = new BlurDrawable(); // 设置模糊半径和颜色 blurDrawable.setBlurRadius(10); blurDrawable.setColor(Color.parseColor("#66000000")); // 将 BlurDrawable 对象设置为导航栏的背景 getWindow().setNavigationBarColor(Color.TRANSPARENT); getWindow().setNavigationBarDividerColor(Color.TRANSPARENT); getWindow().setNavigationBarColor(blurDrawable.getColor()); getWindow().setNavigationBarDividerColor(blurDrawable.getColor()); ``` 其中,`BlurDrawable` 对象的 `setBlurRadius` 方法用于设置模糊半径,`setColor` 方法用于设置毛玻璃颜色。最后将 `BlurDrawable` 对象设置为导航栏的背景即可。 需要注意的是,`BlurDrawable` 类是 Android 11 引入的新类,如果你的应用最低支持 Android 版本不是 11,需要在 build.gradle 文件中添加以下依赖: ```groovy implementation 'androidx.appcompat:appcompat:1.4.0' implementation 'androidx.core:core-ktx:1.6.0' implementation 'androidx.window:window:1.0.0' ``` 并且在代码中导入以下类: ```java import androidx.appcompat.graphics.drawable.BlurDrawable; import androidx.window.WindowManager; ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值