TextClock
TextClock 可以將當前日期和/或時間顯示為格式化字串,TextClock 遵循 24 小時格式系統設定,因此,提供「兩種不同的格式化模式」:
-
以 24 小時制顯示日期/時間,
-
以 12 小時制顯示日期/時間,
可以呼叫「is24HourModeEnabled()」 來確定「系統當前是否處于 24 小時模式」,
如何格式化日期和時間的規則如下:
- 在 24 小時模式下:
-
如果沒獲取時間,首先通過 getFormat24Hour()回傳值
-
獲取失敗,則通過 getFormat12Hour()獲取回傳值
-
以上都獲取失敗則使用默認值,例如 ah:mm
-
- 在 12 小時模式下:
-
如果沒獲取時間,首先通過 getFormat12Hour()回傳值
-
獲取失敗,則通過 getFormat24Hour()獲取回傳值
-
以上都獲取失敗則使用默認值,例如 HH:mm
-
主要XML屬性如下:
「android:format12Hour」 設定12小時制的格式,
「android:format24Hour」 設定24小時制的格式,
「android:timeZone」 指定要使用的時區,設定后忽略系統時間變化,
常用方法
「setFormat12Hour(CharSequence format)」:設定12小時制的格式,
「setFormat24Hour(CharSequence format)」:設定24小時制的格式,
「setTimeZone(String timeZone)」:設定要在此時鐘中使用的指定時區,
「getFormat12Hour()」:回傳12小時制的格式,
「getFormat24Hour()」:回傳24小時制的格式,
「getTimeZone()」:指示此視圖當前使用的時區,
「is24HourModeEnabled()」:指「系統」當前是否使用 24 小時模式,
「onVisibilityAggregated(Boolean isVisible:)」:當此視圖的用戶可見性可能受到此視圖本身、祖先視圖或此視圖附加到的視窗的更改的影響時呼叫,
「refreshTime()」:如有必要,更新顯示的時間并使視圖無效(在API 30中添加),
示例
看上面介紹十分簡單,咱們還是搞個實體了解一下吧,先看效果圖,

主界面布局檔案
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_margin="@dimen/dimen_20"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_is24HourModeEnabled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen_10"
android:textSize="@dimen/text_size_16"
android:padding="@dimen/dimen_10"/>
<TextClock
android:id="@+id/tc_timeText_12"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/black"
android:textSize="30sp"
android:textStyle="bold"/>
<TextClock
android:id="@+id/tc_dateText_12"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/black"
android:textSize="20sp"/>
<TextView
android:id="@+id/tv_12hour"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen_10"
android:textSize="@dimen/text_size_16"
android:padding="@dimen/dimen_10"/>
<TextClock
android:id="@+id/tc_timeText_24"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen_20"
android:format12Hour="hh:mm:ss"
android:format24Hour="HH:mm:ss"
android:gravity="center"
android:textColor="@color/black"
android:textSize="30sp"
android:textStyle="bold"/>
<TextClock
android:id="@+id/tc_dateText_24"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:format12Hour="yyyy/MM/dd E"
android:format24Hour="yyyy/MM/dd E"
android:gravity="center"
android:textColor="@color/black"
android:textSize="20sp"/>
<TextView
android:id="@+id/tv_24hour"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen_10"
android:textSize="@dimen/text_size_16"
android:padding="@dimen/dimen_10"/>
</LinearLayout>
主界面代碼
public class TextClockActivity extends AppCompatActivity {
private TextClock tc_timeText_12,tc_dateText_12,tc_timeText_24,tc_dateText_24;
private TextView tv_12hour,tv_24hour,tv_is24HourModeEnabled;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_textview_textclock);//加載布局檔案
initView();
}
private void initView() {
tv_is24HourModeEnabled = findViewById(R.id.tv_is24HourModeEnabled);
tc_timeText_12 = findViewById(R.id.tc_timeText_12);
tc_dateText_12 = findViewById(R.id.tc_dateText_12);
tv_12hour = findViewById(R.id.tv_12hour);
//setTimeZone使用(UTC-7)無效,
//原因:原始碼未對UTC+(-)進行處理,下面有具體的原始碼分析
tc_timeText_12.setTimeZone("America/Los_Angeles");//有效
tc_dateText_12.setTimeZone("America/Los_Angeles");//有效
//tc_timeText_12.setTimeZone("GMT+7:00");//有效
//tc_dateText_12.setTimeZone("GMT+7:00");//有效
tc_dateText_12.setFormat24Hour("HH:mm");
tc_dateText_12.setFormat12Hour("yyyy/MM/dd E");
// EEEE:星期五 ;E/EE/EEE:周五;a:上午/下午
tc_dateText_12.setFormat24Hour("yyyy年MM月dd日 EEEE aa HH:mm:ss");
String format12 = "\n12小時模式格式:"+tc_timeText_12.getFormat12Hour();
format12 = format12+"\n24小時模式格式:"+tc_timeText_12.getFormat24Hour();
format12 = format12+"\n時區:"+tc_timeText_12.getTimeZone();
tv_12hour.setText("Format:"+format12);
tc_timeText_24 = findViewById(R.id.tc_timeText_24);
tc_dateText_24 = findViewById(R.id.tc_dateText_24);
tv_24hour = findViewById(R.id.tv_24hour);
String format = "\n24小時模式格式:"+tc_timeText_24.getFormat24Hour();
format = format+"\n12小時模式格式:"+tc_timeText_24.getFormat12Hour();
format = format+"\n時區:"+tc_timeText_24.getTimeZone();
String timeZome =TimeZone.getDefault().getDisplayName(true, TimeZone.SHORT);
format = format+"\n時區:"+timeZome;
tv_24hour.setText("Format:"+format);
String is24HourMode = String.format("系統當前是否使用 24 小時模式:%s,", tc_dateText_24.is24HourModeEnabled());
tv_is24HourModeEnabled.setText(is24HourMode);
}
}
示例分析
手機系統默認是24小時格式
例一的時間/日期顯示格式在代碼中設定;
例一的12小時制格式回傳:「ah:mm」 這個是默認值,
例二的時間/日期顯示格式在xml檔案中設定;
例二未設定時區所以時區回傳null,可通過下面代碼獲取系統時區來顯示
TimeZone.getDefault().getDisplayName(true, TimeZone.SHORT);
原始碼分析
setFormat12Hour()
public void setFormat12Hour(CharSequence format) {
mFormat12 = format;
chooseFormat();
onTimeChanged();
}
setFormat24Hour()
public void setFormat24Hour(CharSequence format) {
mFormat24 = format;
chooseFormat();
onTimeChanged();
}
看完「setFormat12Hour」和「setFormat24Hour」,你會發現他們除了各自格式賦值,后面都呼叫了「chooseFormat()」 和「onTimeChanged()」,下面咱看看這倆方法是干什么的,
chooseFormat()
先進行了判斷是不是24小時制,后面用到了「abc()」;mDescFormat12,mDescFormat24用于內容描述,下面講到,咱們接著往下看abc()
/**
* Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
* depending on whether the user has selected 24-hour format.
*/
private void chooseFormat() {
final boolean format24Requested = is24HourModeEnabled();
LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale);
if (format24Requested) {
mFormat = abc(mFormat24, mFormat12, ld.timeFormat_Hm);
mDescFormat = abc(mDescFormat24, mDescFormat12, mFormat);
} else {
mFormat = abc(mFormat12, mFormat24, ld.timeFormat_hm);
mDescFormat = abc(mDescFormat12, mDescFormat24, mFormat);
}
boolean hadSeconds = mHasSeconds;
mHasSeconds = DateFormat.hasSeconds(mFormat);
if (mShouldRunTicker && hadSeconds != mHasSeconds) {
if (hadSeconds) getHandler().removeCallbacks(mTicker);
else mTicker.run();
}
}
abc()
-
a不為null,回傳a;否則繼續往下看;
-
b不為null,回傳b;否則回傳c;
-
例如:24小時制:a=24小時格式;b=12小時格式,c默認格式
說白了就是上面的:「如何格式化日期和時間的規則,」
/**
* Returns a if not null, else return b if not null, else return c.
*/
private static CharSequence abc(CharSequence a, CharSequence b, CharSequence c) {
return a == null ? (b == null ? c : b) : a;
}
onTimeChanged()
獲取系統當前時間并展示,這里多了一個「setContentDescription()」;咱后面看看是干嘛的
/**
* Update the displayed time if this view and its ancestors and window is visible
*/
@UnsupportedAppUsage
private void onTimeChanged() {
mTime.setTimeInMillis(System.currentTimeMillis());
setText(DateFormat.format(mFormat, mTime));
setContentDescription(DateFormat.format(mDescFormat, mTime));
}
setContentDescription()
設定 控制元件 的內容描述,
@RemotableViewMethod
public void setContentDescription(CharSequence contentDescription) {
//mContentDescription:簡要描述視圖,主要用于輔助功能支持,
if (mContentDescription == null) {
if (contentDescription == null) {
return;
}
} else if (mContentDescription.equals(contentDescription)) {
return;
}
mContentDescription = contentDescription;
final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0;
if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
notifySubtreeAccessibilityStateChangedIfNeeded();
} else {
notifyViewAccessibilityStateChangedIfNeeded(
AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION);
}
}
setTimeZone()
設定時區
public void setTimeZone(String timeZone)
{
mTimeZone = timeZone;
createTime(timeZone);
onTimeChanged();
}
設定時區呼叫了兩個方法「createTime()」 和「onTimeChanged()」,onTimeChanged()獲取系統當前時間并展示,咱們在上面講過了,這里咱重點看createTime()
createTime()
判斷是使用設定的時區還是用系統時區
private void createTime(String timeZone) {
if (timeZone != null) {
mTime = Calendar.getInstance(TimeZone.getTimeZone(timeZone));
} else {
mTime = Calendar.getInstance();
}
}
從上面看出不管timeZong是否為null都會呼叫「Calendar.getInstance()」,區別在是否傳參,還有「TimeZone.getTimeZone(timeZone)」 在下面咱們看看這兩個方法,
TimeZone.getTimeZone(timeZone)
這個是重點,這里面包含了:
-
zone = ZoneInfoDb.getInstance().makeTimeZone(id);設定時區成功(如:America/Los_Angeles)
-
zone = getCustomTimeZone(id);設定時區成功(如:GMT+7:00)
-
UTC失敗,從這里看到設定UTC+(-)時區未做設定所以都無效,
public static synchronized TimeZone getTimeZone(String id) {
if (id == null) {
throw new NullPointerException("id == null");
}
// Special cases? These can clone an existing instance.
if (id.length() == 3) {
if (id.equals("GMT")) {
return (TimeZone) GMT.clone();
}
if (id.equals("UTC")) {
return (TimeZone) UTC.clone();
}
}
// In the database?
TimeZone zone = null;
try {
zone = ZoneInfoDb.getInstance().makeTimeZone(id);
} catch (IOException ignored) {
}
// Custom time zone?
if (zone == null && id.length() > 3 && id.startsWith("GMT")) {
zone = getCustomTimeZone(id);
}
// We never return null; on failure we return the equivalent of "GMT".
return (zone != null) ? zone : (TimeZone) GMT.clone();
}
下面咱們看看getCustomTimeZone(id),
getCustomTimeZone(id)
從下面代碼可以看到 回傳一個新的 SimpleTimeZone:格式為“GMT[+|-]hh[[:]mm]”的 ID,或者回傳null,
private static TimeZone getCustomTimeZone(String id) {
Matcher m = NoImagePreloadHolder.CUSTOM_ZONE_ID_PATTERN.matcher(id);
if (!m.matches()) {
return null;
}
int hour;
int minute = 0;
try {
hour = Integer.parseInt(m.group(1));
if (m.group(3) != null) {
minute = Integer.parseInt(m.group(3));
}
} catch (NumberFormatException impossible) {
throw new AssertionError(impossible);
}
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
return null;
}
char sign = id.charAt(3);
int raw = (hour * 3600000) + (minute * 60000);
if (sign == '-') {
raw = -raw;
}
String cleanId = String.format(Locale.ROOT, "GMT%c%02d:%02d", sign, hour, minute);
return new SimpleTimeZone(raw, cleanId);
}
上面的就是對傳參進行處理下面咱們看看剛剛說到的Calendar.getInstance()
Calendar.getInstance()
//設定的時區和系統時區對比看看是不是當前時區
public static Calendar getInstance(TimeZone zone)
{
return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
}
接著看下面的:createCalendar()
// END Android-added: add getJapaneseImperialInstance()
private static Calendar createCalendar(TimeZone zone, Locale aLocale)
{
// BEGIN Android-changed: only support GregorianCalendar here
return new GregorianCalendar(zone, aLocale);
// END Android-changed: only support GregorianCalendar here
}
再往下看GregorianCalendar(zone, aLocale)
/**
* Constructs a <code>GregorianCalendar</code> based on the current time
* in the given time zone with the given locale.
*
* @param zone the given time zone.
* @param aLocale the given locale.
*/
public GregorianCalendar(TimeZone zone, Locale aLocale) {
super(zone, aLocale);
gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
//根據給定的 long 值設定當前時間,
setTimeInMillis(System.currentTimeMillis());
}
以上就是本文的全部內容,希望對大家學習Android TextClock有所幫助和啟發,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/290470.html
標籤:其他
