需求:
由于应用连接硬件,显示硬件工作的实时状态。一个应用只有一个Activity的可能性应该不大,除非你的应用架构是Activity+Fragment。所以需要实现一个自定义的状态栏。其实和系统自带的状态栏类似。
大海捞针,都没有找到解决办法,可能大家没有遇到这样的需求或者本人使用搜索引擎的水平太弱。
实现原理:
- 定义状态栏的布局文件。
- 定义广播接收状态信息更新到界面。
实现思路:
思路1:
- 使用BaseActivity,将状态栏做成公共的布局文件,然后使用include包含进来。
- 所有应用的Activity都继承BaseActivity进行编写代码
- 在BaseActivity中定义状态栏项的广播接收者,进行接收状态的更新。
思路2:
- 定义一个StatusBarService,在应用启动时将此服务开启
- StatusBarService启动时使用WindowManager类将状态栏布局加载进来。
- 同思路1.3
思路3:
- 整个应用使用OneActivity+Fragment架构
- 将状态栏布局写在Activity中,Fragment负责实现应用本身的功能。
- 同思路1.3
综合以上思路应用采用“思路2”,所以下面只会写思路2的实现。原因有以下几点:
- 因为项目已经开展很久,已有很多Activity所以未采用“思路3”,修改代码量太大。
- “思路1”虽然可以实现需求,但是考虑效率问题,每次打开一个Activity都要去创建状态栏,注册状态栏信息更新的广播,又因为项目中状态信息更新频率在1Hz,所以也未采用此思路。
思路2的实现:
- 定义状态栏项自定义控件StatusIconView
- 定义状态栏的服务StatusBarService。在此服务中实现所有状态栏的功能。
- 需要添加此权限<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
下面就贴代码了:
/**
* @ClassName: StatusIconView
* @Description: TODO 状态栏图标
* @author Canney Chen
* @date 2014年10月22日 下午2:59:54
*
*/
public class StatusIconView extends LinearLayout {
//图标
private ImageView mIcon;
//图标对应的值
private TextView mText;
public StatusIconView(Context context) {
super(context);
}
public StatusIconView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public StatusIconView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.StatusIconView);
int icon = a.getResourceId(R.styleable.StatusIconView_icon, 0);
a.recycle();
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.status_icon_view, this);
mIcon = (ImageView) findViewById(R.id.icon);
mIcon.setImageResource(icon);mText = (TextView) findViewById(R.id.title);
}
public final TextView getTextView(){
return mText;
}
public final void setIcon(int resId) {
mIcon.setImageResource(resId);
}
public final void setText(int resId) {
mText.setText(resId);
}
public final void setText(CharSequence text) {
mText.setText(text);
}
public final ImageView getIconView(){
return mIcon;
}
}
<!-- status_icon_view文件-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="@+id/icon"
style="@style/status_bar_icon" />
<TextView
android:id="@+id/title"
style="@style/status_bar_text" />
</LinearLayout>
<pre name="code" class="java"><pre name="code" class="java"><pre name="code" class="java">/**
* 状态栏
* @author Canney Chen
*
*/
public class StatusBarService extends Service{
private WindowManager wm=null;
private WindowManager.LayoutParams statusBarParams = new WindowManager.LayoutParams();
private RelativeLayout statusBarLayout=null;
private StatusBarViewHolder statusBarViewHolder = new StatusBarViewHolder();
@Override
public void onCreate() {
super.onCreate();
createStatusView();
registerReceiver();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
/* 手机电池电量显示 */
BroadcastReceiver phoneBatteryReceiver = new BroadcastReceiver(){
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)){
int level = intent.getIntExtra("level", 0);
int scale = intent.getIntExtra("scale", 100);
int curPower = (level * 100 / scale); displayBattery(getPhoneBatteryIndexAndImages(curPower), statusBarViewHolder.phoneBatteryIcon);
}
};
};
private void createStatusView(){
Context context = getApplicationContext();
statusBarLayout = new MoveLayout(context);
statusBarLayout.setGravity(Gravity.CENTER_VERTICAL);
statusBarLayout.setLayoutParams(new android.view.ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT));
wm=(WindowManager)getApplicationContext().getSystemService(WINDOW_SERVICE);
((LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE)).inflate(R.layout.status_bar, statusBarLayout);
findStatusBarViews();
wm.addView(statusBarLayout, getStatusViewParams());
}
private WindowManager.LayoutParams getStatusViewParams(){
statusBarParams.type = LayoutParams.TYPE_PHONE;
statusBarParams.format = PixelFormat.TRANSPARENT;
statusBarParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE
| LayoutParams.FLAG_ALT_FOCUSABLE_IM;
statusBarParams.gravity = Gravity.LEFT | Gravity.BOTTOM;
statusBarParams.x = 0;
statusBarParams.y = 0;statusBarParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
statusBarParams.height = (int) getResources().getDimension(
R.dimen.status_bar_height);
return statusBarParams;
}
private void findStatusBarViews() {statusBarViewHolder.phoneBatteryIcon = (StatusIconView)statusBarLayout.findViewById(R.id.phone_battery_icon);
}
@SuppressLint("NewApi")
private void displayBattery(int[] battery, StatusIconView icon){
icon.getTextView().setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(batteryFlagRes[battery[0]]), null, null, null);
icon.setText("" + battery[1]);
icon.setIcon(battery[2]);
}
/**
* @Title: getPhoneBatteryIndexAndImages
* @Description: TODO 手机电量图标及显示文字的索引
* @param battery
* @return
* @return int[] Arr[0] = 0手机电池标识,Arr[1]电量,Arr[2]电量对应的图片id
* @author Canney Chen
*/
private int[] getPhoneBatteryIndexAndImages(int battery){
return new int[]{2, battery, getBatteryImage(battery)};
}
private int getBatteryImage(int battery) {
int resId;
if(battery > 0 && battery <= 10){
resId = R.drawable.status_battery0;
}else if(battery > 10 && battery <= 40){
resId = R.drawable.status_battery1;
}else if(battery > 40 && battery <= 60){
resId = R.drawable.status_battery2;
}else if(battery > 60 && battery <= 80){
resId = R.drawable.status_battery3;
}else if(battery > 80 && battery <= 100){resId = R.drawable.status_battery4;
}else{
resId = R.drawable.status_battery0;
}
return resId;
}/**
* 注册状态栏更新信息的广播
*/
private void registerReceiver() {
registerReceiver(phoneBatteryReceiver , new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
/**
* 状态栏的所有图标
*/
private class StatusBarViewHolder{
StatusIconView phoneBatteryIcon;
}
@Override
public void onDestroy(){
unregisterReceiver();
wm.removeView(statusBarLayout);
wm.removeView(positionLayout);
super.onDestroy();
}
private void unregisterReceiver(){
unregisterReceiver(phoneBatteryReceiver);
}
注意:
以上自定义的状态栏如果显示在ActionBar的顶部和系统状态栏保持一致可能会影响应用美观,全如果放样Activity界面的底部,则会出现,当在Activity中输入内容时,弹出了软键盘,自定义的状态栏会遮挡住键盘上的内容