Android 14中状态栏的显示是由SystemUI负责的,除此SystemUI还要负责QS(快捷菜单),消息通知(Notification),导航栏,系统状态(Wifi,BT,电池,信号强度)等。
其中status_bar.xml是负责显示Android设备状态栏的layout文件,里面的显示如下:前半部分显示运营商,时间,通话状态;后半部显示 使用者,系统状态图标(BT,Mobile,Wifi),电池状态等。后半部分主要Layout文件为 system_icon.xml,要深入研究,请认真复习system_icon的布局。
status_bar.xml
<com.android.systemui.statusbar.phone.PhoneStatusBarView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:layout_width="match_parent"
android:layout_height="@dimen/status_bar_height"
android:id="@+id/status_bar"
android:orientation="vertical"
android:focusable="false"
android:paddingStart="@dimen/status_bar_padding_start_pre"
android:paddingEnd="@dimen/status_bar_padding_end_rear"
android:descendantFocusability="afterDescendants"
android:accessibilityPaneTitle="@string/status_bar"
>
<ImageView
android:id="@+id/notification_lights_out"
android:layout_width="@dimen/status_bar_icon_size"
android:layout_height="match_parent"
android:paddingStart="@dimen/status_bar_padding_start"
android:paddingBottom="2dip"
android:src="@drawable/ic_sysbar_lights_out_dot_small"
android:scaleType="center"
android:visibility="gone"
/>
<LinearLayout android:id="@+id/status_bar_contents"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingStart="@dimen/status_bar_padding_start"
android:paddingEnd="@dimen/status_bar_padding_end"
android:paddingTop="@dimen/status_bar_padding_top"
android:orientation="horizontal">
<!-- Container for the entire start half of the status bar. It will always use the same
width, independent of the number of visible children and sub-children. -->
<FrameLayout
android:id="@+id/status_bar_start_side_container"
android:layout_height="match_parent"
android:layout_width="0dp"
android:clipChildren="false"
android:layout_weight="1">
<!-- Container that is wrapped around the views on the start half of the status bar.
Its width will change with the number of visible children and sub-children.
It is useful when we want to know the visible bounds of the content. -->
<FrameLayout
android:id="@+id/status_bar_start_side_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipChildren="false">
<include layout="@layout/heads_up_status_bar_layout" />
<!-- The alpha of the start side is controlled by PhoneStatusBarTransitions, and the
individual views are controlled by StatusBarManager disable flags DISABLE_CLOCK
and DISABLE_NOTIFICATION_ICONS, respectively -->
<LinearLayout
android:id="@+id/status_bar_start_side_except_heads_up"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:clipChildren="false">
<ViewStub
android:id="@+id/operator_name"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout="@layout/operator_name" />
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
android:singleLine="true"
android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
android:gravity="center_vertical|start"
/>
<include layout="@layout/ongoing_call_chip" />
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/notification_icon_area"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:clipChildren="false"/>
</LinearLayout>
</FrameLayout>
</FrameLayout>
<!-- Space should cover the notch (if it exists) and let other views lay out around it -->
<android.widget.Space
android:id="@+id/cutout_space_view"
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="center_horizontal|center_vertical"
/>
<!-- Container for the entire end half of the status bar. It will always use the same
width, independent of the number of visible children and sub-children. -->
<FrameLayout
android:id="@+id/status_bar_end_side_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:clipChildren="false">
<!-- Container that is wrapped around the views on the end half of the
status bar. Its width will change with the number of visible children and
sub-children.
It is useful when we want know the visible bounds of the content.-->
<com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/status_bar_end_side_content"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:orientation="horizontal"
android:gravity="center_vertical|end"
android:clipChildren="false">
<include
android:id="@+id/user_switcher_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/status_bar_user_chip_end_margin"
layout="@layout/status_bar_user_chip_container" />
<include layout="@layout/system_icons" />
</com.android.keyguard.AlphaOptimizedLinearLayout>
</FrameLayout>
</LinearLayout>
</com.android.systemui.statusbar.phone.PhoneStatusBarView>
本文主要讲的内容是如何在时间的后面同样显示日期。而显示时间的类是com.android.systemui.statusbar.policy.Clock中CharSequence getSmallTime()这个api,里面做了时间获取的流程处理。
由于Android 14上的SystemUI使用Dagger的注入和关联方式,要想在Clock的下面添加一个VariableDateView的方法比较麻烦,实现起来修改量比较大而烦。所以经过多次修改和验证,终于找到一种很方面的方法:就在statusbar.policy.Clock的getSmallTime()方法中增加时间的获取,并添加到时间的后面。
但这样已修改,所有使用statusbar.policy.Clock的地方都会显示日期,导致已使用VariableDateView的地方显示重复日期,所以接下要做的事情是根据需要显示日期。即在layout布局中增加属性showDate,用于显示日期,默认是不显示日期。
在attrs.xml属性文件中,对Clock新增一个boolean属性的showDate值。
在status_bar.xml的Clock下新增一个 app:showDate="true"属性。切记,需要在xml的顶部添加app属性声明:xmlns:app="http://schemas.android.com/apk/res-auto"
Clock类文件中同样做修改:
所以最后的时间显示部分修改为:
最终达成时间后面显示日期的目的: