文章目錄
一、狀態(tài)欄顯示AM/PM二、鎖屏界面顯示AM/PM
一、狀態(tài)欄顯示AM/PM
先查看狀態(tài)欄的布局文件:\vendor\mediatek\proprietary\packages\apps\SystemUI\res\layout\status_bar.xml 找到和時間相關(guān)的布局:
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" /> 再根據(jù)此自定義的java文件: \vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\policy\Clock.java 其是繼承TextView的自定義時鐘布局文件,其中定義了三個跟AM/PM顯示有關(guān)的靜態(tài)全局變量: private static final int AM_PM_STYLE_NORMAL = 0;// AM/PM大小與前面時間的大小一致。 private static final int AM_PM_STYLE_SMALL = 1;// AM/PM大小是前面時間的大小的0.7倍,具體是在getSmallTime()方法中實現(xiàn)。 private static final int AM_PM_STYLE_GONE = 2;// AM/PM不可見 狀態(tài)欄顯示AM/PM的修改方法如下(在其構(gòu)造函數(shù)中進(jìn)行修改): public Clock(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mCommandQueue = Dependency.get(CommandQueue.class); TypedArray a = context.getTheme().obtainStyledAttributes( attrs, R.styleable.Clock, 0, 0); try { mSystemUIFactoryBase = OpSystemUICustomizationFactoryBase.getOpFactory(context); mStatusBarExt = mSystemUIFactoryBase.makeSystemUIStatusBar(context); /*mAmPmStyle = mStatusBarExt.getClockAmPmStyle(a.getInt(R.styleable.Clock_amPmStyle, AM_PM_STYLE_GONE));*/ mAmPmStyle = mStatusBarExt.getClockAmPmStyle(a.getInt(R.styleable.Clock_amPmStyle, AM_PM_STYLE_SMALL));// 設(shè)置為AM/PM相對時間0.7倍顯示,具體為啥為0.7倍參考方法getSmallTime mNonAdaptedColor = getCurrentTextColor(); } finally { a.recycle(); } mBroadcastDispatcher = Dependency.get(BroadcastDispatcher.class); mUserTracker = Dependency.get(UserTracker.class); } 查看Clock.java下的getSmallTime()方法: private final CharSequence getSmallTime() { Context context = getContext(); boolean is24 = DateFormat.is24HourFormat(context, mCurrentUserId); if (mDateTimePatternGenerator == null) { // Despite its name, getInstance creates a cloned instance, so reuse the generator to // avoid unnecessary churn. mDateTimePatternGenerator = DateTimePatternGenerator.getInstance( context.getResources().getConfiguration().locale); } final char MAGIC1 = '\uEF00'; final char MAGIC2 = '\uEF01'; final String formatSkeleton = mShowSeconds ? is24 ? "Hms" : "hms" : is24 ? "Hm" : "hm"; String format = mDateTimePatternGenerator.getBestPattern(formatSkeleton); if (!format.equals(mContentDescriptionFormatString)) { mContentDescriptionFormatString = format; mContentDescriptionFormat = new SimpleDateFormat(format); /* * Search for an unquoted "a" in the format string, so we can * add marker characters around it to let us find it again after * formatting and change its size. */ if (mAmPmStyle != AM_PM_STYLE_NORMAL) { int a = -1; boolean quoted = false; for (int i = 0; i < format.length(); i++) { char c = format.charAt(i); if (c == '\'') { quoted = !quoted; } if (!quoted && c == 'a') { a = i; break; } } if (a >= 0) { // Move a back so any whitespace before AM/PM is also in the alternate size. final int b = a; while (a > 0 && Character.isWhitespace(format.charAt(a-1))) { a--; } format = format.substring(0, a) + MAGIC1 + format.substring(a, b) + "a" + MAGIC2 + format.substring(b + 1); } } mClockFormat = new SimpleDateFormat(format); } String result = mClockFormat.format(mCalendar.getTime()); if (mAmPmStyle != AM_PM_STYLE_NORMAL) { int magic1 = result.indexOf(MAGIC1); int magic2 = result.indexOf(MAGIC2); if (magic1 >= 0 && magic2 > magic1) { SpannableStringBuilder formatted = new SpannableStringBuilder(result); if (mAmPmStyle == AM_PM_STYLE_GONE) { formatted.delete(magic1, magic2+1); } else { if (mAmPmStyle == AM_PM_STYLE_SMALL) { CharacterStyle style = new RelativeSizeSpan(0.7f);// 此RelativeSizeSpan就是實現(xiàn)文字相對大小的樣式,故為上述提到的AM/PM為時間大小的0.7倍 formatted.setSpan(style, magic1, magic2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); } formatted.delete(magic2, magic2 + 1); formatted.delete(magic1, magic1 + 1); } return formatted; } } return result; } 二、鎖屏界面顯示AM/PM 鎖屏界面對應(yīng)的布局文件:\SystemUI\res-keyguard\layout\keyguard_clock_switch.xml # 鎖屏界面顯示通知時的時間布局 android:id="@+id/lockscreen_clock_view" android:layout_width="match_parent" android:layout_height="@dimen/small_clock_height" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:clipChildren="false" android:paddingStart="@dimen/clock_padding_start" android:visibility="invisible" /> # 鎖屏界面不顯示通知的時間布局 android:id="@+id/lockscreen_clock_view_large" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false" android:visibility="gone" /> 根據(jù)id查詢具體布局使用到的位置:選中id對應(yīng)的參數(shù),Ctrl + N 查詢到文件:SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java 在如下加載布局的方法使用: @Override protected void onFinishInflate() { super.onFinishInflate(); mSmallClockFrame = findViewById(R.id.lockscreen_clock_view); mLargeClockFrame = findViewById(R.id.lockscreen_clock_view_large); mStatusArea = findViewById(R.id.keyguard_status_area); onConfigChanged(); } 再根據(jù)對mSmallClockFrame、mLargeClockFrame兩個參數(shù)在上述Java文件的查詢和跟蹤,發(fā)現(xiàn)在下面方法中設(shè)置了時間的布局: void setClock(ClockController clock, int statusBarState) { mClock = clock; // Disconnect from existing plugin. mSmallClockFrame.removeAllViews(); mLargeClockFrame.removeAllViews(); if (clock == null) { if (mLogBuffer != null) { mLogBuffer.log(TAG, LogLevel.ERROR, "No clock being shown"); } return; } // Attach small and big clock views to hierarchy. if (mLogBuffer != null) { mLogBuffer.log(TAG, LogLevel.INFO, "Attached new clock views to switch"); } mSmallClockFrame.addView(clock.getSmallClock().getView()); mLargeClockFrame.addView(clock.getLargeClock().getView()); updateClockTargetRegions(); updateStatusArea(/* animate= */false); } 在通過查找ClockController,發(fā)現(xiàn)其為定義在下面文件中的一個接口: \vendor\mediatek\proprietary\packages\apps\SystemUI\plugin\src\com\android\systemui\plugins\ClockProviderPlugin.kt /** Interface for controlling an active clock */ interface ClockController { /** A small version of the clock, appropriate for smaller viewports */ val smallClock: ClockFaceController /** A large version of the clock, appropriate when a bigger viewport is available */ val largeClock: ClockFaceController /** Determines the way the hosting app should behave when rendering either clock face */ val config: ClockConfig /** Events that clocks may need to respond to */ val events: ClockEvents /** Initializes various rendering parameters. If never called, provides reasonable defaults. */ fun initialize( resources: Resources, dozeFraction: Float, foldFraction: Float, ) /** Optional method for dumping debug information */ fun dump(pw: PrintWriter) } 在溯源ClockFaceController,發(fā)現(xiàn)其定義在如下文件中了一個內(nèi)部類: \vendor\mediatek\proprietary\packages\apps\SystemUI\customization\src\com\android\systemui\shared\clocks\DefaultClockController.kt 查看此文件,其中的init方法如下: init { val parent = FrameLayout(ctx) smallClock = DefaultClockFaceController( layoutInflater.inflate(R.layout.clock_default_small, parent, false) as AnimatableClockView, settings?.seedColor ) largeClock = LargeClockFaceController( layoutInflater.inflate(R.layout.clock_default_large, parent, false) as AnimatableClockView, settings?.seedColor ) clocks = listOf(smallClock.view, largeClock.view) events = DefaultClockEvents() events.onLocaleChanged(Locale.getDefault()) } 其中顯示全部通知時的鎖屏?xí)r間布局為:\vendor\mediatek\proprietary\packages\apps\SystemUI\customization\res\layout\clock_default_small.xml 不顯示通知的鎖屏?xí)r間布局為: \vendor\mediatek\proprietary\packages\apps\SystemUI\customization\res\layout\clock_default_large.xml 下面查看clock_default_small.xml: xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="start" android:gravity="start" android:textSize="@dimen/small_clock_text_size" android:fontFamily="@*android:string/config_clockFontFamily" android:elegantTextHeight="false" android:ellipsize="none" android:singleLine="true" android:fontFeatureSettings="pnum" chargeAnimationDelay="350" dozeWeight="200" lockScreenWeight="400" /> 其也是一個自定義布局:\vendor\mediatek\proprietary\packages\apps\SystemUI\customization\src\com\android\systemui\shared\clocks\AnimatableClockView.kt 鎖屏界面顯示AM/PM具體的修改如下: fun refreshTime() { time.timeInMillis = timeOverrideInMillis ?: System.currentTimeMillis() contentDescription = DateFormat.format(descFormat, time) //add code var formattedText = DateFormat.format(format, time) val formattedTextStr = trimAllWhitespace(formattedText.toString()) if (format!!.contains("a")) { var formatted = SpannableStringBuilder(formattedTextStr) val ampm = DateFormat.format("a", time).toString() val style = RelativeSizeSpan(0.5f) //參考Clock.java中設(shè)置字體風(fēng)格 val ampmStart = formattedTextStr!!.indexOf(ampm, 0) val ampmLength = ampm.length formatted.setSpan(style, ampmStart, ampmStart + ampmLength, Spannable.SPAN_EXCLUSIVE_INCLUSIVE) formattedText = formatted } //end code logBuffer?.log(TAG, DEBUG, { str1 = formattedText?.toString() }, { "refreshTime: new formattedText=$str1" } ) // Setting text actually triggers a layout pass (because the text view is set to // wrap_content width and TextView always relayouts for this). Avoid needless // relayout if the text didn't actually change. if (!TextUtils.equals(text, formattedText)) { text = formattedText logBuffer?.log(TAG, DEBUG, { str1 = formattedText?.toString() }, { "refreshTime: done setting new time text to: $str1" } ) // Because the TextLayout may mutate under the hood as a result of the new text, we // notify the TextAnimator that it may have changed and request a measure/layout. A // crash will occur on the next invocation of setTextStyle if the layout is mutated // without being notified TextInterpolator being notified. if (layout != null) { textAnimator?.updateLayout(layout) logBuffer?.log(TAG, DEBUG, "refreshTime: done updating textAnimator layout") } requestLayout() logBuffer?.log(TAG, DEBUG, "refreshTime: after requestLayout") } } // add function 去除解析的時間格式字符串中間的空白字符串 fun trimAllWhitespace(str: String?): String? { if (str != null) { val len = str.length if (len > 0) { val dest = CharArray(len) var destPos = 0 for (i in 0 until len) { val c = str[i] if (!java.lang.Character.isWhitespace(c)) { dest[destPos++] = c } } return String(dest, 0, destPos) } } return str } 做到此處,還是不能解決,需要修改下面參數(shù),還是在AnimatableClockView.kt中,修改下面參數(shù): @VisibleForTesting var isAnimationEnabled: Boolean = false//true 取消動畫,不然字體還是會顯示為與時間同樣大小(因為需求是需要設(shè)置鎖屏界面的AM/PM比時間?。?。 如果顯示尺寸過大,則需要修改下面參數(shù): \vendor\mediatek\proprietary\packages\apps\SystemUI\customization\res\values\dimens.xml 對上面的large_clock_text_size和small_clock_text_size進(jìn)行修改。 最后編譯運行解決。 精彩鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。