Android安卓水滴屏适配状态栏图标(图标过多时显示一个点)
程序员文章站
2022-06-23 09:27:07
在没有下拉状态栏时,原生android将...
源码路径:com.android.systemui.statusbar.phone/StatusIconContainer.java
布局文件路径:SystemUI/res/layout/status_bar.xml
一、状态栏布局
在没下拉状态栏时,原生android会将状态栏分为两部分(如下图及布局源码)
1、android:id="@+id/notification_icon_area
2、android:id="@+id/system_icon_area"
从下面的布局文件可以看到这两块区域的权重都是1,左边放通知图标,右边放系统图标,中间留有一块控件用来放缺口(也就是水滴或刘海的位置),在这里如果没有水滴的话可以修改权重,来放置更多的系统图标或通知图标(有水滴的话改了图标过多时就会遮挡住图标)
<FrameLayout
android:layout_height="match_parent" android:layout_width="0dp" android:layout_weight="1"> <include layout="@layout/heads_up_status_bar_layout" /> <!-- The alpha of the left 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_left_side" android:layout_height="match_parent" 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.phone.StatusIconContainer android:id="@+id/statusIcons_left" android:layout_width="wrap_content" android:layout_height="match_parent" android:paddingEnd="@dimen/signal_cluster_battery_padding" android:gravity="center_vertical" android:orientation="horizontal"/> <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/notification_icon_area" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="horizontal" android:clipChildren="false"/> </LinearLayout> </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" /> <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/centered_icon_area" android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal" android:clipChildren="false" android:gravity="center_horizontal|center_vertical"/> <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="horizontal" android:gravity="center_vertical|end" > <LinearLayout
android:id="@+id/system_icons" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical"> <com.android.systemui.statusbar.phone.StatusIconContainer android:id="@+id/statusIcons" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:paddingEnd="@dimen/signal_cluster_battery_padding" android:gravity="center_vertical" android:orientation="horizontal"/> <com.android.systemui.BatteryMeterView android:id="@+id/battery" android:layout_height="match_parent" android:layout_width="wrap_content" android:clipToPadding="false" android:clipChildren="false" android:textAppearance="@style/TextAppearance.StatusBar.Clock" /> <!-- HCT lishuo for show new battery icon style --> <include layout="@layout/hct_status_bar_battery"/> <!-- HCT lishuo for show new battery icon style end --> <android.widget.Space
android:layout_width="2dp" android:layout_height="match_parent" /> <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:paddingBottom="2dip" android:singleLine="true" android:gravity="center_vertical|end" /> </LinearLayout> </com.android.keyguard.AlphaOptimizedLinearLayout>
二、状态栏右侧系统图标显示过多时显示一个点
在源码中,控制右侧系统图标显示的有两个限制:
1、图标个数
2、宽度限制
主要方法:onMeasure 和 calculateIconTranslations (下方贴上源代码)
在onMeasure中会测量水滴右边区域能放的下的图标的总宽度(totalWidth)
在calculateIconTranslations中会判断如果图标个数大于限定个数并且剩余宽度不足以绘制一个图标时,就去绘制那个点,达到开始那张图的效果
// Max 8 status icons including battery private static final int MAX_ICONS = 7;
安卓原生定义了最大显示图标个数是8个(包括电池图标)
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mMeasureViews.clear(); int mode = MeasureSpec.getMode(widthMeasureSpec); final int width = MeasureSpec.getSize(widthMeasureSpec); final int count = getChildCount(); // Collect all of the views which want to be laid out for (int i = 0; i < count; i++) { StatusIconDisplayable icon = (StatusIconDisplayable) getChildAt(i); if (icon.isIconVisible() && !icon.isIconBlocked() && !mIgnoredSlots.contains(icon.getSlot())) { mMeasureViews.add((View) icon); } } int visibleCount = mMeasureViews.size(); int maxVisible = visibleCount <= MAX_ICONS ? MAX_ICONS : MAX_ICONS - 1; int totalWidth = mPaddingLeft + mPaddingRight; boolean trackWidth = true; // Measure all children so that they report the correct width int childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED); mNeedsUnderflow = mShouldRestrictIcons && visibleCount > MAX_ICONS; for (int i = 0; i < mMeasureViews.size(); i++) { // Walking backwards View child = mMeasureViews.get(visibleCount - i - 1); measureChild(child, childWidthSpec, heightMeasureSpec); if (mShouldRestrictIcons) { if (i < maxVisible && trackWidth) { totalWidth += getViewTotalMeasuredWidth(child); } else if (trackWidth) { // We've hit the icon limit; add space for dots totalWidth += mUnderflowWidth; trackWidth = false; } } else { totalWidth += getViewTotalMeasuredWidth(child); } } if (mode == MeasureSpec.EXACTLY) { if (!mNeedsUnderflow && totalWidth > width) { mNeedsUnderflow = true; } setMeasuredDimension(width, MeasureSpec.getSize(heightMeasureSpec)); } else { if (mode == MeasureSpec.AT_MOST && totalWidth > width) { mNeedsUnderflow = true; totalWidth = width; } setMeasuredDimension(totalWidth, MeasureSpec.getSize(heightMeasureSpec)); } }
private void calculateIconTranslations() { mLayoutStates.clear(); float width = getWidth(); float translationX = width - getPaddingEnd(); float contentStart = getPaddingStart(); //HCT: lishuo statusbar new style if(isLayoutOpposite){ translationX = width - getPaddingStart(); contentStart = getPaddingEnd(); } //HCT: lishuo statusbar new style end int childCount = getChildCount(); // Underflow === don't show content until that index if (DEBUG) android.util.Log.d(TAG, "calculateIconTranslations: start=" + translationX + " width=" + width + " underflow=" + mNeedsUnderflow); // Collect all of the states which want to be visible //HCT: lishuo statusbar new style, Exchange SIM icons position View firstSimIconView = null; View secondSimIconView= null; if(isLayoutOpposite){ for (int i = childCount - 1; i >= 0; i--) { View child = getChildAt(i); if(child instanceof StatusBarMobileView && firstSimIconView == null){ firstSimIconView = child; }else if(child instanceof StatusBarMobileView && firstSimIconView != null){ secondSimIconView = child; break; } } } //HCT: lishuo statusbar new style, Exchange SIM icons position end for (int i = childCount - 1; i >= 0; i--) { View child = getChildAt(i); //HCT: lishuo statusbar new style if(isLayoutOpposite && firstSimIconView != null && secondSimIconView != null){ if(child.equals(firstSimIconView)){ child = secondSimIconView; }else if(child.equals(secondSimIconView)){ child = firstSimIconView; } } //HCT: lishuo statusbar new style end StatusIconDisplayable iconView = (StatusIconDisplayable) child; StatusIconState childState = getViewStateFromChild(child); if (!iconView.isIconVisible() || iconView.isIconBlocked() || mIgnoredSlots.contains(iconView.getSlot())) { childState.visibleState = STATE_HIDDEN; if (DEBUG) Log.d(TAG, "skipping child (" + iconView.getSlot() + ") not visible"); continue; } childState.visibleState = STATE_ICON; childState.xTranslation = translationX - getViewTotalWidth(child); mLayoutStates.add(0, childState); translationX -= getViewTotalWidth(child); } // Show either 1-MAX_ICONS icons, or (MAX_ICONS - 1) icons + overflow int totalVisible = mLayoutStates.size(); int maxVisible = totalVisible <= MAX_ICONS ? MAX_ICONS : MAX_ICONS - 1; mUnderflowStart = 0; int visible = 0; int firstUnderflowIndex = -1; for (int i = totalVisible - 1; i >= 0; i--) { StatusIconState state = mLayoutStates.get(i); // Allow room for underflow if we found we need it in onMeasure if (mNeedsUnderflow && (state.xTranslation < (contentStart + mUnderflowWidth))|| (mShouldRestrictIcons && visible >= maxVisible)) { firstUnderflowIndex = i; break; } mUnderflowStart = (int) Math.max(contentStart, state.xTranslation - mUnderflowWidth); visible++; } if (firstUnderflowIndex != -1) { int totalDots = 0; int dotWidth = mStaticDotDiameter + mDotPadding; int dotOffset = mUnderflowStart + mUnderflowWidth - mIconDotFrameWidth; for (int i = firstUnderflowIndex; i >= 0; i--) { StatusIconState state = mLayoutStates.get(i); if (totalDots < MAX_DOTS) { state.xTranslation = dotOffset; state.visibleState = STATE_DOT; dotOffset -= dotWidth; totalDots++; } else { state.visibleState = STATE_HIDDEN; } } } // Stole this from NotificationIconContainer. Not optimal but keeps the layout logic clean if(isLayoutOpposite){ if (isLayoutRtl()) { }else{ for (int i = 0; i < childCount; i++) { View child = getChildAt(i); StatusIconState state = getViewStateFromChild(child); state.xTranslation = width - state.xTranslation - child.getWidth(); } } }else if (isLayoutRtl()) { for (int i = 0; i < childCount; i++) { View child = getChildAt(i); StatusIconState state = getViewStateFromChild(child); state.xTranslation = width - state.xTranslation - child.getWidth(); } } }
本文地址:https://blog.csdn.net/weixin_43624165/article/details/107700877