android 夜间模式的实现

注:急速开发的人,可以直接看第三种实现方式

1:修改theme,重启activity(Google自家在内的很多应用都是采用此种方式实现夜间模式的)

优点:正儿八经的夜间模式,配色看着舒服

缺点:规模较大的应用,需要随theme变化的属性会很多,都需要逐一定义,有点麻烦,另外一个缺点是要使得新theme生效,一般需要restartActivity来切换UI,会导致切换主题时界面闪烁

核心思路:自定义一个颜色属性名 A,A在日间和夜间模式下都有具体的颜色代码,页面布局文件只管引用A,至于是日间还是夜间,由后台主题决定。

        

附上一二中方法的图

android 夜间模式的实现_第1张图片(原图)android 夜间模式的实现_第2张图片 (第一种实现)android 夜间模式的实现_第3张图片(第二种实现)

好,下面来讲讲具体的实现步骤,本环节使用的开发环境是Eclipse  demo地址http://www.oschina.net/code/snippet_2702417_55892

1 首先

attrs.xml(声明属性的类型,布局xml中用) reference可以使用系统的资源ID,比如R.color.gray; color可以直接使用#ffffff颜色代码

复制代码
   
      
      
      
      
      
      
      
  
     
         
      
      
      
      
      
     
复制代码

 

colors.xml(调色板,集中管理颜色hex)遵循优秀格式规范,即调色板模式,避免使用btn1,btn2,fontTitle,fontText之类的颜色名。

复制代码
xml version="1.0" encoding="utf-8"?>
<resources>
   #101115
   #FFFFFF 
resources>
复制代码

 string.xml

 dayandNight
    Hello world!
    白模式
    夜模式


styles.xml(日间、夜间主题)

复制代码
<resources>
      

    
    
    

    

    
resources>
复制代码

2activity的使用

protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		if(MyApp.isLightMode()){  
            this.setTheme(R.style.NightTheme);  
        }else{  
            this.setTheme(R.style.DayTheme);  
        }  
		setContentView(R.layout.activity_one);
	}
	
	public void onClick(View view){
		MyApp.setIslightMode(!MyApp.isLightMode());
		recreate();
	}

xml的布局:




    

    

    

    

    

    
    
注:遇到放回activity闪屏的问题可以

(1)在BaseActivity中创建下面的方法

public static void updateTheme(Activity activity,isNight)
{
  MyApp.setNightMode(isNight);
  activity.recreate();
}


2:使用一个带黑色带透明度的View,盖在现有的activity上,效果类似你带上墨镜,看着太阳不刺眼。

优点:不用重启activity,不闪屏;加上透明度过渡动画,模式之间切换非常舒服,解决了1中,白底图片依旧刺眼的问题。;

缺点:配色没变化,就算带上墨镜,白天依旧是白天。

核心思路:使用WindowManager,在当前activity上,通过addView,添加一个黑色带透明度的View。

//第二中方式,只是提供一种思路,逻辑没有去实习
	public void onClickT(View view){
		LayoutParams  mNightViewParam = new LayoutParams(
	                LayoutParams.TYPE_APPLICATION,
	                LayoutParams.FLAG_NOT_TOUCHABLE | LayoutParams.FLAG_NOT_FOCUSABLE,
	                PixelFormat.TRANSPARENT);

		WindowManager   mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
	    View   mNightView = new View(this);
	    mWindowManager.addView(mNightView, mNightViewParam);
	    mNightView.setBackgroundResource(R.color.night_mask);
}


3:通过修改Theme来切换夜间模式,不过不会出现闪屏()的情况。

android 夜间模式的实现_第4张图片和第一种方式一样需要theme的设置从上到下的代码


    
    


       





    

先看下BaseActivity
public abstract class BaseActivity extends Activity {
protected int skin;
public Context mContext;
SharedPreferences sp;


@Override
protected void onCreate(Bundle savedInstanceState) {
	setThemeMode(getSkinTypeValue());
	super.onCreate(savedInstanceState);
	init();
	}
	public abstract void init();
	protected void setThemeMode(SkinType skinType) {
	  switch (skinType) {
	  case Light:
		setTheme(R.style.AppTheme_Light);
	  break;
	 case Night:
		setTheme(R.style.AppTheme_Night);
	 break;
	 default:
		setTheme(R.style.AppTheme_Light);
	 break;
	}
}
//获取用户选取的模式
protected SkinType getSkinTypeValue() {
	if (sp == null) {
	sp = getSharedPreferences("AppSkinType", Context.MODE_PRIVATE);
	}
	int i = sp.getInt("AppSkinTypeValue", 0);
	switch (i) {
	 case 0:
		return SkinType.Light;
      case 1:
		return SkinType.Night;
	 default:
	 break;
	}
	return SkinType.Light;
}
//保存用户是选取的模式
public void saveSkinValue(int skin) {
	if (sp == null) {
	sp = getSharedPreferences("AppSkinType", Context.MODE_PRIVATE);
	}
	Editor editor = sp.edit();
	editor.putInt("AppSkinTypeValue", skin);
	editor.commit();

}

在看下第一个activity的使用的
public class MainActivity extends BaseActivity {
	private CheckBox cbSetting;
	private Button btnForward;
	private TextView tv_title;
	private View llNight;
	
	
	@Override
	public void init() {
		setContentView(R.layout.activity_main);
		llNight = findViewById(R.id.ll_night);
		tv_title = (TextView) findViewById(R.id.tv_title);
		btnForward = (Button) findViewById(R.id.forward);
		cbSetting = (CheckBox) findViewById(R.id.cb_setting);
		cbSetting.setOnCheckedChangeListener(new OnCheckedChangeListener() {
			@Override
			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
				if (isChecked) {
					// 夜间模式
					saveSkinValue(1);
					setTheme(R.style.AppTheme_Night);//防止getTheme()取出来的值是创建时候得值
					initView();
				} else {
					// 白天模式
					saveSkinValue(0);
					setTheme(R.style.AppTheme_Light);//防止getTheme()取出来的值是创建时候得值
					initView(); 
				}
			}
		});
		
		btnForward.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent intent = new Intent(MainActivity.this,SecondActivity.class);
				startActivity(intent);
			}
		});
	}
	//改变模式后手动修改UI,不然出现闪屏
	private void initView(){
		TypedValue typedValue = new TypedValue();
		Theme theme = getTheme();
		theme.resolveAttribute(R.attr.gray_3_double, typedValue, true);   
		btnForward.setTextColor(getResources().getColor(typedValue.resourceId));
		tv_title.setTextColor(getResources().getColor(typedValue.resourceId));
		theme.resolveAttribute(R.attr.source_bg, typedValue, true);   
		llNight.setBackgroundDrawable(getResources().getDrawable(typedValue.resourceId));  
	}	
}
大体就是这样实现,附上demo链接 http://www.oschina.net/code/snippet_2702417_55886

优点:

bug少,用户体验好

缺点:

UI控件多的时候,改起来工作量不小。代码量很大

4 通过模式库changesKin

http://www.codeceo.com/article/android-changeskin-usage.html





 注:这里提到的都是资源内嵌在Apk中的方案,像qq通过下载方式实现夜间的方式可以去百度一下。

参考: http://m.oschina.net/blog/668384

你可能感兴趣的:(android,开发)