【Android】仿知乎夜間模式的實現
1.簡介
目前很多App都有夜間模式的功能,網上教程也是很多,最近專案不忙,抽空學習了下,在這做下記錄,希望能幫到正在看部落格的你,我們先來看下知乎的效果:
看我的效果:
臥槽,好像啊,哈哈,好吧,有點神似,關於知乎實現的分析,大家可以看下這位大神的分析,那咱們廢話少說,開始實現吧。
2.AppCompatDelegate方式實現
在support.v7包中google提供了AppCompatDelegate類,可以用於實現夜間模式,實現起來比較簡單:
一、設定Activity主題,繼承自Theme.AppCompat.DayNight等夜間相關的主題
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
二、通過setDefaultNightMode(Mode)方法來設定當前的模式
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
該模式有三種
- AppCompatDelegate.MODE_NIGHT_AUTO,他會時刻知道你最後的位置和時間(如果您的應用程式已開啟位置許可權)用於白天和黑夜之間自動切換的 依據
- AppCompatDelegate.MODE_NIGHT_NO 強制設定了從不使用夜晚主題。
- AppCompatDelegate.MODE_NIGHT_YES 則強制設定了一直使用夜晚主題。
以上來自模式介紹.
三、通過在res目錄下建立value-night,drawable-night等目錄來進行匹配,當設定為夜間模式的時候,會取-night下的資源,反之,會取預設的資源,看下效果:
以上實現的是白天和夜間分別載入不同的圖片和background,不過使用這種方式有個問題,就是如果設定夜間模式後,不進行跳轉,本頁面要想有反應必須呼叫activity的recreate()方法,會出現閃屏問題,所以雖然實現簡單,但是效果並不好,這裡不再過多介紹,原始碼下載文末給出。
3.仿知乎夜間模式的實現
思路借鑑上文對知乎分析文章的介紹,首先製造出一個和當前頁面一樣的ImageView放在頁面的最上層,然後切換夜間模式時,設定需要設定的顏色,背景等屬性,然後對ImageView進行顏色漸變的實現,使其看起來更平滑,說的有點亂,看具體步驟:
一、獲取佈局檔案最外層Layout的截圖
/**
* 獲取view截圖對應的bitmap
* @param v
* @return
*/
public Bitmap loadBitmapFromView(View v) {
//width為螢幕寬度,height為螢幕高度,statusBarHeight為狀態列高度
Bitmap b = Bitmap.createBitmap(width, height-statusBarHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getLayoutParams().width, v.getLayoutParams().height);
v.draw(c);
return b;
}
二、建立臨時的ImageView並add到rootLayout中
final ImageView imageView = new ImageView(this);
imageView.setLayoutParams(new ViewGroup.LayoutParams(width, height-statusBarHeight));
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
Bitmap bitmap = loadBitmapFromView(rootLayout);
imageView.setImageBitmap(bitmap);
rootLayout.addView(imageView);
四、設定夜間/日間模式
/**
* 設定日漸模式具體程式碼
*/
private void setDayThemeInfo() {
rootLayout.setBackgroundColor(Color.parseColor("#FFFFFF"));
tvColor.setTextColor(Color.parseColor("#222222"));
imageView.setImageResource(R.mipmap.day_icom);
}
/**
* 設定夜間模式具體程式碼
*/
private void setNightThemeInfo() {
rootLayout.setBackgroundColor(Color.parseColor("#333444"));
tvColor.setTextColor(Color.parseColor("#666666"));
imageView.setImageResource(R.mipmap.night_icon);
}
五、漸變動畫,移除臨時的ImageView
int colorA = Color.parseColor("#ffffff");
int colorB = Color.parseColor("#333444");
ObjectAnimator objectAnimator = ObjectAnimator.ofInt(imageView, "backgroundColor", colorA, colorB);
objectAnimator.setDuration(800);
objectAnimator.setEvaluator(new ArgbEvaluator());
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
rootLayout.removeView(imageView);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
objectAnimator.start();
在以上介紹中,省略了一些簡單的步驟,比如獲取螢幕寬高,佈局檔案也沒有貼出來,實際專案中肯定還需要儲存當前的模式,一般使用SharedPreferences儲存即可,然後初始化的時候載入相應的設定主題的程式碼,不再敖述。
本文旨在給出一些基本的思路和簡單實現,具體使用中還需對細節進行處理,望各位看官注意!