【android】夜间模式简单实现
完整代碼,請(qǐng)參考我的博客園客戶端,git地址:http://git.oschina.net/yso/CNBlogs
關(guān)于閱讀類的app,有個(gè)夜間模式真是太重要了。
那么有兩種方式可以實(shí)現(xiàn)夜間模式
1:修改theme,重啟activity
優(yōu)點(diǎn):正兒八經(jīng)的夜間模式,配色看著舒服
缺點(diǎn):圖片刺眼、閃屏
核心思路:自定義一個(gè)顏色屬性名 A,A在日間和夜間模式下都有具體的顏色代碼,頁(yè)面布局文件只管引用A,至于是日間還是夜間,由后臺(tái)主題決定。
2:使用一個(gè)帶黑色帶透明度的View,蓋在現(xiàn)有的activity上,效果類似你帶上墨鏡,看著太陽(yáng)不刺眼。
優(yōu)點(diǎn):不用重啟activity,不閃屏;加上透明度過(guò)渡動(dòng)畫,模式之間切換非常舒服,解決了1中,白底圖片依舊刺眼的問(wèn)題。;
缺點(diǎn):配色沒變化,就算帶上墨鏡,白天依舊是白天。
核心思路:使用WindowManager,在當(dāng)前activity上,通過(guò)addView,添加一個(gè)黑色帶透明度的View。
?
本方案整合了兩種解決方案。在夜間配色的基礎(chǔ)上,再加上一層墨鏡,讓圖片也變得柔和起來(lái),效果圖如下:
可以看待chrome圖標(biāo)的白色底,在夜間模式下也變得柔和了
好,下面來(lái)講講具體的實(shí)現(xiàn)步驟,本環(huán)節(jié)使用的開發(fā)環(huán)境是android Studio
1 首先,在values下要準(zhǔn)備好三個(gè)文件,沒有就自己創(chuàng)建
attrs.xml(聲明屬性的類型,布局xml中用) reference可以使用系統(tǒng)的資源ID,比如R.color.gray; color可以直接使用#ffffff顏色代碼
<?xml version="1.0" encoding="utf-8"?> <resources><attr name="containerBackground" format="reference|color"></attr><attr name="cardBackground" format="reference|color"></attr><attr name="titleColor" format="reference|color"></attr><attr name="textColor" format="reference|color"></attr><attr name="selectorBtn" format="reference"></attr><attr name="selectorListItem" format="reference"></attr> </resources>?
colors.xml(調(diào)色板,集中管理顏色hex)遵循優(yōu)秀格式規(guī)范,即調(diào)色板模式,避免使用btn1,btn2,fontTitle,fontText之類的顏色名。
<?xml version="1.0" encoding="utf-8"?> <resources><color name="white">#fafafa</color><color name="white_dark">#f3f3f3</color><color name="gray_light">#cccccc</color><color name="gray">#777</color><color name="gray_dark">#383838</color><color name="green_light">#8e9ea4</color><color name="green">#34515c</color><color name="green_dark">#1e3e4a</color><color name="night_mask">#90000000</color> </resources>?
styles.xml(日間、夜間主題)
<resources><!-- Application theme. --><style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"></style><!-- 日間模式 --><style name="AppTheme.day" parent="AppTheme"><item name="containerBackground">@color/white_dark</item><item name="titleColor">@color/gray_dark</item><item name="textColor">@color/gray</item><item name="selectorBtn">@drawable/navigator_list_item_day</item><item name="selectorListItem">@drawable/list_item_day</item></style><!-- 夜間模式 --><style name="AppTheme.night" parent="AppTheme"><item name="containerBackground">@color/green_dark</item><item name="titleColor">@color/white_dark</item><item name="textColor">@color/green_light</item><item name="selectorBtn">@drawable/navigator_list_item_night</item><item name="selectorListItem">@drawable/list_item_night</item></style> </resources>2定義activity父類,自動(dòng)托管日間、夜間模式
BaseApplication就是自己包裝的Application,通過(guò)它,保存日間、夜間模式
Application和Activity,Service一樣是android框架的一個(gè)系統(tǒng)組件,當(dāng)android程序啟動(dòng)時(shí)系統(tǒng)會(huì)創(chuàng)建一個(gè) application對(duì)象,用來(lái)存儲(chǔ)系統(tǒng)的一些信息。通常我們是不需要指定一個(gè)Application的,這時(shí)系統(tǒng)會(huì)自動(dòng)幫我們創(chuàng)建,如果需要?jiǎng)?chuàng)建自己 的Application,也很簡(jiǎn)單創(chuàng)建一個(gè)類繼承 Application并在manifest的application標(biāo)簽中進(jìn)行注冊(cè)(只需要給Application標(biāo)簽增加個(gè)name屬性把自己的 Application的名字定入即可)。
android系統(tǒng)會(huì)為每個(gè)程序運(yùn)行時(shí)創(chuàng)建一個(gè)Application類的對(duì)象且僅創(chuàng)建一個(gè),所以Application可以說(shuō)是單例 (singleton)模式的一個(gè)類.且application對(duì)象的生命周期是整個(gè)程序中最長(zhǎng)的,它的生命周期就等于這個(gè)程序的生命周期。因?yàn)樗侨?的單例的,所以在不同的Activity,Service中獲得的對(duì)象都是同一個(gè)對(duì)象。所以通過(guò)Application來(lái)進(jìn)行一些,數(shù)據(jù)傳遞,數(shù)據(jù)共享 等,數(shù)據(jù)緩存等操作。
public class BaseActionBarActivity extends ActionBarActivity {private BaseApplication mBaseApp = null;private WindowManager mWindowManager = null;private View mNightView = null;private LayoutParams mNightViewParam; private boolean mIsAddedView; @Overrideprotected void onCreate(Bundle savedInstanceState) {mBaseApp = (BaseApplication) getApplication();if (mBaseApp.isNightMode())setTheme(R.style.AppTheme_night);elsesetTheme(R.style.AppTheme_day);super.onCreate(savedInstanceState);mIsAddedView = false; if (mBaseApp.isNightMode()) {initNightView();mNightView.setBackgroundResource(R.color.night_mask);}}@Overrideprotected void onDestroy() {if (mIsAddedView) {mBaseApp = null;mWindowManager.removeViewImmediate(mNightView);mWindowManager = null;mNightView = null;} super.onDestroy();}public void ChangeToDay() {mBaseApp.setIsNightMode(false);mNightView.setBackgroundResource(android.R.color.transparent);}public void ChangeToNight() {mBaseApp.setIsNightMode(true);initNightView();mNightView.setBackgroundResource(R.color.night_mask);}/*** wait a time until the onresume finish*/public void recreateOnResume() {new Handler().postDelayed(new Runnable() {public void run() {recreate();}}, 100);}private void initNightView() {if (mIsAddedView == true)return;mNightViewParam = new LayoutParams(LayoutParams.TYPE_APPLICATION,LayoutParams.FLAG_NOT_TOUCHABLE | LayoutParams.FLAG_NOT_FOCUSABLE,PixelFormat.TRANSPARENT);mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);mNightView = new View(this);mWindowManager.addView(mNightView, mNightViewParam);mIsAddedView = true;} }值得一提的是recreateOnResume()函數(shù),因?yàn)槭菑腞esume里面重建activity的(避免閃屏)此時(shí),直接調(diào)用系統(tǒng)的recreate函數(shù)時(shí),會(huì)報(bào)錯(cuò),原因是resume還沒執(zhí)行完,就被recreate了,因此,我們函數(shù)需要延時(shí)一會(huì),等待系統(tǒng)完成resume就好了。一般延時(shí)1毫秒就可以了,但是我的app里面用到抽屜式導(dǎo)航欄,保存的時(shí)間要長(zhǎng)點(diǎn)。
準(zhǔn)備工作到這里已經(jīng)結(jié)束了。只要activity集成自該父類,就會(huì)自動(dòng)托管日間、夜間模式了
3調(diào)用方式
在布局文件里,引用顏色的地方,我們使用問(wèn)號(hào)來(lái)訪問(wèn)定義在styles.xml里面主題的屬性。換句話說(shuō),這種方式的神奇之處在于,我在夜間主題、白天主題都定義了titleColor,布局只管引用titleColor,至于是白天的還是晚上的,則由activity的setTheme指定。
?
?表示引用屬性
“?”引用主題屬性,當(dāng)您使用這個(gè)標(biāo)記,你所提供的資源名必須能夠在主題屬性中找到,因?yàn)橘Y源工具認(rèn)為這個(gè)資源屬性是被期望得到的,您不需要明確的指出它的類型
?
?
子類只要調(diào)用ChangeToDay、ChangeToNight就可以完成模式的切換了。別忘了recreate activity來(lái)生效哦,實(shí)例代碼如下:
void changeViewMode() {boolean isNight = getMyApplication().isNightMode();if (isNight)ChangeToDay();elseChangeToNight();recreate();}?
OK,如過(guò)你能堅(jiān)持看到這里,說(shuō)明閣下是有耐心的人,奉上一個(gè)彩蛋。
關(guān)于WebView網(wǎng)頁(yè)如何實(shí)現(xiàn)日間、夜間模式。
這個(gè)問(wèn)題比我們現(xiàn)象的要簡(jiǎn)單的多。因?yàn)榫W(wǎng)頁(yè)么,在生成html內(nèi)容時(shí),只要根據(jù)日間、還是夜間模式,替換css路徑為日間.css、夜間.css就好了。
栗子來(lái)了,瞧,就是這個(gè)"{style}",我們要替換的對(duì)象。
<html> <head><title>Cnblogs</title><link rel="stylesheet" type="text/css" href="{style}"/><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0, user-scalable=no"/> </head>在對(duì)webview加載內(nèi)容文本時(shí),替換該字符串的css
replace("{style}",baseApplication.isNightMode() ? "style_night.css" : "style_day.css")結(jié)構(gòu)如下:
切換主題如何避免閃屏
我們知道,通過(guò)reCreate(),來(lái)重啟activity的時(shí)候,會(huì)閃屏;
那么?在切換之前,先截屏作為activity蓋在當(dāng)前的activity上面,然后重啟activity,完畢之后,把蓋著的activity通過(guò)alpha動(dòng)畫消失,這樣切換主題動(dòng)作就會(huì)變的很柔和了
?
轉(zhuǎn)載于:https://www.cnblogs.com/kimmy/p/4555197.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的【android】夜间模式简单实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 红酒价格差距为什么大?
- 下一篇: blender 子弹时间 动画