目前很多App都有夜间模式的功能,网上教程也是很多,最近项目不忙,抽空学习了下,在这做下记录,希望能帮到正在看博客的你,我们先来看下知乎的效果:
看我的效果:
卧槽,好像啊,哈哈,好吧,有点神似,关于知乎实现的分析,大家可以看下这位大神的分析,那咱们废话少说,开始实现吧。
在support.v7包中google提供了AppCompatDelegate类,可以用于实现夜间模式,实现起来比较简单:
一、设置Activity主题,继承自Theme.AppCompat.DayNight等夜间相关的主题
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
二、通过setDefaultNightMode(Mode)方法来设置当前的模式
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
该模式有三种
以上来自模式介绍.
三、通过在res目录下建立value-night,drawable-night等目录来进行匹配,当设置为夜间模式的时候,会取-night下的资源,反之,会取默认的资源,看下效果:
以上实现的是白天和夜间分别加载不同的图片和background,不过使用这种方式有个问题,就是如果设置夜间模式后,不进行跳转,本页面要想有反应必须调用activity的recreate()方法,会出现闪屏问题,所以虽然实现简单,但是效果并不好,这里不再过多介绍,源码下载文末给出。
思路借鉴上文对知乎分析文章的介绍,首先制造出一个和当前页面一样的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保存即可,然后初始化的时候加载相应的设置主题的代码,不再敖述。
本文旨在给出一些基本的思路和简单实现,具体使用中还需对细节进行处理,望各位看官注意!
源码在这里:夜间模式源码点击下载