Android夜间模式的实现

Android新手,在模仿知乎日报做一个App,今天遇到的问题是如何实现夜间模式。

夜间模式在网上有很多介绍,我采用的方法是更改app的style并且加入一张暗色的半透明的图片,下面叫做镜片视图。

在看代码方面自己的能力明显不足,所采用的方式是新建一个项目,然后从各位大牛里的代码找出来与自己想实现的功能有关的代码,然后在新项目里边理解变调试,

进入正题,实现夜间模式首先需要自定义至少一种theme:如图在value文件夹下新建styles.xml,color.xml,attrs.xml,代码可以参考这篇http://www.cnblogs.com/kimmy/p/4555197.html(我的代码就是从这位博主里抠出来的)。定义好之后就要开始理解application这个类了,application是在该app运行的时候自动创建的一个类,像app的名字,图标,主题等都是在这个类里配置的,其中主题就是我要更改的内容。一般来说该类是自动创建的,但是当需要更改app的设置的时候一般都要自己创建个BaseApplication继承至Application,并且要在AndroidManifest.xml中注册该类,注册方法:

<application
        android:name="com.example.z.BaseApplication"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

就是application标签下的第一行就是。


BaseApplication类的代码如下

package com.example.z;

import android.app.Application;

public class BaseApplication extends Application {
	private boolean mIsNightMode;

	public boolean isNightMode() {
		return mIsNightMode;
	}

	public void setIsNightMode(boolean isNightMode) {
		if (mIsNightMode == isNightMode)
			return;
		mIsNightMode = isNightMode;
	}
}
就是两个方法,mIsNightMode表示当前模式,isNightMode()用来判断当前模式类型,setIsNightMode则用来改变mIsNightMode的值。

新建一个BaseActivity继承至Activity:

package com.example.z;

import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;

public class BaseActivity extends Activity {
	private BaseApplication mBaseApp = null;
	private WindowManager mWindowManager = null;
	private View mNightView = null;
	private boolean mIsAddedView;
	private LayoutParams mNightViewParam;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		mBaseApp = (BaseApplication) getApplication();
		if (mBaseApp.isNightMode())
			setTheme(R.style.AppTheme_night);
		else
			setTheme(R.style.AppTheme_day);
		super.onCreate(savedInstanceState);
		if (mBaseApp.isNightMode()) {
			initNightView();
			mNightView.setBackgroundResource(R.color.night_mask);
		}
	}

	private void initNightView() {
		if (mIsAddedView)
			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;

	}

	public BaseApplication getApp() {
		return mBaseApp;
	}

	protected void recreateOnResume() {
		new Handler().postDelayed(new Runnable() {
			public void run() {
				recreate();
			}
		}, 100);
	}

	@Override
	protected void onDestroy() {
		if (mIsAddedView) {
			mBaseApp = null;
			mWindowManager.removeViewImmediate(mNightView);
			mWindowManager = null;
			mNightView = null;
		}
		super.onDestroy();
	}

	protected void ChangeToDay() {
		mBaseApp.setIsNightMode(false);
		mNightView.setBackgroundResource(android.R.color.transparent);
	}

	protected void ChangeToNight() {
		mBaseApp.setIsNightMode(true);
		initNightView();
		mNightView.setBackgroundResource(R.color.night_mask);
	}
}


BaseActivity主要起到俩个作用1.改变模式,2加入或除去镜片视图。

分析代码BaseApplication可以看做是一个服务类,首先得到该类实例mBaseApp,判断该app目前的style是否需要更改,setTheme(R.style.AppTheme_night);必须在super.onCreate(savedInstanceState)之前,网上都这么说,暂不深究原因,下面是判断如果是夜间模式还要加入一个镜片视图:初始化视图并设置镜片颜色,然后将镜片视图加载到主视图中,即下一个的初始化镜片的方法。在下一个是get方法不说了。recreateOnResume是在button点击时调用的方法,值得一提的是recreateOnResume()函数,因为是从Resume里面重建activity的(避免闪屏)此时,直接调用系统的recreate函数时,会报错,原因是resume还没执行完,就被recreate了,因此,我们函数需要延时一会,等待系统完成resume就好了。一般延时1毫秒就可以了,但是我的app里面用到抽屉式导航栏,保存的时间要长点。(引自http://www.cnblogs.com/kimmy/p/4555197.html
。 onDestroy()在activity结束时清空各值。最后ChangeToDay,ChangeToNight改变参数的。

介绍完以上内容就可以创建真正的MainActivity了,记得要继承至BaseActivity,代码如下:

package com.example.z;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends BaseActivity {
	Button button;
	private boolean mIsNightMode;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		 mIsNightMode = getApp().isNightMode();
		button = (Button) findViewById(R.id.a);
		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				changeViewMode();
			}
		});
	}

	@Override
	protected void onResume() {
		super.onResume();
		if (mIsNightMode != getApp().isNightMode()) {
			recreateOnResume();
		}
	}

	void changeViewMode() {
		boolean isNight = getApp().isNightMode();
		if (isNight) {
			ChangeToDay();
		} else {
			ChangeToNight();
		}
		recreate();
	}
}

相应的布局文件就是一哥button和一个imageview,这就不贴了。

mIsNightMode = getApp().isNightMode(),保证开启时是日间模式(如果需要记忆上一次的设置更改的话可以用SharedPreferences保存)然后实例化button,添加事件:判断当前模式并更改为另一种模式,这两个方法并没有直接将我们看到的视图更改,而是将参数更改后让视图recreate(),重新绘制视图。

以上就是经过简化的功能。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值