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(),重新绘制视图。
以上就是经过简化的功能。