需求:

由于应用连接硬件,显示硬件工作的实时状态。一个应用只有一个Activity的可能性应该不大,除非你的应用架构是Activity+Fragment。所以需要实现一个自定义的状态栏。其实和系统自带的状态栏类似。

大海捞针,都没有找到解决办法,可能大家没有遇到这样的需求或者本人使用搜索引擎的水平太弱。

实现原理:

  1. 定义状态栏的布局文件。
  2. 定义广播接收状态信息更新到界面。

实现思路:

思路1:

  1. 使用BaseActivity,将状态栏做成公共的布局文件,然后使用include包含进来。
  2. 所有应用的Activity都继承BaseActivity进行编写代码
  3. 在BaseActivity中定义状态栏项的广播接收者,进行接收状态的更新。

思路2:


  1. 定义一个StatusBarService,在应用启动时将此服务开启
  2. StatusBarService启动时使用WindowManager类将状态栏布局加载进来。
  3. 同思路1.3

思路3:


  1. 整个应用使用OneActivity+Fragment架构
  2. 将状态栏布局写在Activity中,Fragment负责实现应用本身的功能。
  3. 同思路1.3

综合以上思路应用采用“思路2”,所以下面只会写思路2的实现。原因有以下几点:

  1. 因为项目已经开展很久,已有很多Activity所以未采用“思路3”,修改代码量太大。
  2. “思路1”虽然可以实现需求,但是考虑效率问题,每次打开一个Activity都要去创建状态栏,注册状态栏信息更新的广播,又因为项目中状态信息更新频率在1Hz,所以也未采用此思路。

思路2的实现:

  1. 定义状态栏项自定义控件StatusIconView
  2. 定义状态栏的服务StatusBarService。在此服务中实现所有状态栏的功能。
  3. 需要添加此权限<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中输入内容时,弹出了软键盘,自定义的状态栏会遮挡住键盘上的内容