在系统状态栏里添加一些开关,便于用户操作一些常用的操作,比如开关Wifi,开关蓝牙,开关数据通信等,这些都是在设置里可以控制 的,但是用户要点击多次之后才能到达要去的区域,这个对用户体验不佳。所以在状态栏里添加些控制按钮很有必要,一般一个页面放3到5个开关布局比较好看,但是要是想放多个多个开关,则可以通过布局画或者用组件。
左右滑动可以使用ViewFlipper组件来实现视图之间的切换,然后添加手势控制类即可。
我为了方便修改项目,把控制面板的代码单独的提取出来,放到一个类里控制。
首先添加布局,在SystemUI的status_bar_expanded.xml里添加自定义的类。
<com.android.systemui.statusbar.SwitchControlPanel
android:id="@+id/switch_control_panel"
android:layout_height="wrap_content"
android:layout_width="match_parent"/>
然后要去SystemUI的StatusBarService.java里初始化这个类,这样系统启动时候就会发现这个类,进而进行操作了。
SwitchControlPanel mPanel;
mPanel = (SwitchControlPanel)expanded.findViewById(R.id.switch_control_panel);
然后就可以操作SwitchControlPanel.java这个类了,这个是继承于LinearyLayout,所以要在里面添加布局,需要用到inflate这个类,因为不是在Activity里使用,所以这里就与众不同点。
package com.android.systemui.statusbar;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.OnGestureListener;
import android.view.View.OnTouchListener;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.view.animation.Animation.AnimationListener;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.ViewFlipper;
import android.widget.AdapterView.OnItemClickListener;
import com.android.systemui.R;
public class SwitchControlPanel extends LinearLayout implements OnItemClickListener, OnGestureListener, OnTouchListener,AnimationListener {
private ViewFlipper mFlipper;
GestureDetector mGestureDetector;
private int mCurrentLayoutState;
private static final int FLING_MIN_DISTANCE = 100;
private static final int FLING_MIN_VELOCITY = 200;
TextView wifiView;
LinearLayout wifiLayout;
private WifiManager mWifiManager;
private IntentFilter mWifiStateFilter;
public SwitchControlPanel(Context context) {
super(context);
}
public SwitchControlPanel(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.switch_control_panel, this);
Log.e("kingfly", "kingfly SwitchControlPanel enter");
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mFlipper=(ViewFlipper)findViewById(R.id.flipper);
mGestureDetector=new GestureDetector(this);
wifiLayout=(LinearLayout)mFlipper.findViewById(R.id.switch_wifi);
wifiView=(TextView)mFlipper.findViewById(R.id.switch_text_wifi);
wifiLayout.setOnClickListener(mChangeWifi);
wifiLayout.setOnTouchListener(mOnTouch);
wifiView.setOnTouchListener(mOnTouch);
mWifiManager = (WifiManager) this.getContext().getSystemService(Context.WIFI_SERVICE);
handleWifiStateChanged(mWifiManager.getWifiState());
mWifiStateFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
this.getContext().registerReceiver(mWifiReceiver, mWifiStateFilter);
mGestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
});
mFlipper.setOnTouchListener(this);
mCurrentLayoutState=0;
mFlipper.setLongClickable(true);
Log.e("kingfly", "kingfly onFinishInflate enter");
}
private View.OnClickListener mChangeWifi = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLED) {
mWifiManager.setWifiEnabled(true);
handleWifiStateChanged(mWifiManager.getWifiState());
} else if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
mWifiManager.setWifiEnabled(false);
handleWifiStateChanged(mWifiManager.getWifiState());
} else if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_UNKNOWN) {
mWifiManager.setWifiEnabled(true);
handleWifiStateChanged(mWifiManager.getWifiState());
}
}
};
private View.OnTouchListener mOnTouch=new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.e("kingfly", "kingfly View.onTouch");
mGestureDetector.onTouchEvent(event);
return false;
}
};
private void handleWifiStateChanged(int state) {
switch (state) {
case WifiManager.WIFI_STATE_ENABLING:
wifiView.setCompoundDrawablesWithIntrinsicBounds(null, getResources().getDrawable(R.drawable.stat_switch_wifi_off), null, getResources().getDrawable(R.drawable.stat_switch_ind_off));
wifiView.setText(R.string.switch_enabling);
break;
case WifiManager.WIFI_STATE_ENABLED:
wifiView.setCompoundDrawablesWithIntrinsicBounds(null, getResources().getDrawable(R.drawable.stat_switch_wifi_on), null, getResources().getDrawable(R.drawable.stat_switch_ind_on));
wifiView.setText(R.string.switch_wifi_summary);
break;
case WifiManager.WIFI_STATE_DISABLING:
wifiView.setCompoundDrawablesWithIntrinsicBounds(null, getResources().getDrawable(R.drawable.stat_switch_wifi_on), null, getResources().getDrawable(R.drawable.stat_switch_ind_on));
wifiView.setText(R.string.switch_closing);
break;
case WifiManager.WIFI_STATE_DISABLED:
wifiView.setCompoundDrawablesWithIntrinsicBounds(null, getResources().getDrawable(R.drawable.stat_switch_wifi_off), null, getResources().getDrawable(R.drawable.stat_switch_ind_off));
wifiView.setText(R.string.switch_wifi_summary);
break;
default:
wifiView.setCompoundDrawablesWithIntrinsicBounds(null, getResources().getDrawable(R.drawable.stat_switch_wifi_off), null, getResources().getDrawable(R.drawable.stat_switch_ind_off));
wifiView.setText(R.string.switch_wifi_summary);
}
}
private final BroadcastReceiver mWifiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
handleWifiStateChanged(intent.getIntExtra(
WifiManager.EXTRA_WIFI_STATE, mWifiManager
.getWifiState()));
}
}
};
protected Animation inFromRightAnimation() {
Animation inFromRight = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT, +1.0f,
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, 0.0f);
inFromRight.setDuration(500);
inFromRight.setInterpolator(new AccelerateInterpolator());
return inFromRight;
}
protected Animation outToLeftAnimation() {
Animation outtoLeft = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, -1.0f,
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, 0.0f);
outtoLeft.setDuration(500);
outtoLeft.setInterpolator(new AccelerateInterpolator());
return outtoLeft;
}
protected Animation inFromLeftAnimation() {
Animation inFromLeft = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT, -1.0f,
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, 0.0f);
inFromLeft.setDuration(500);
inFromLeft.setInterpolator(new AccelerateInterpolator());
return inFromLeft;
}
protected Animation outToRightAnimation() {
Animation outtoRight = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, +1.0f,
Animation.RELATIVE_TO_PARENT, 0.0f,
Animation.RELATIVE_TO_PARENT, 0.0f);
outtoRight.setDuration(500);
outtoRight.setInterpolator(new AccelerateInterpolator());
return outtoRight;
}
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
}
@Override
public boolean onDown(MotionEvent arg0) {
// TODO Auto-generated method stub
return true;
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
Log.e("kingfly", "kingfly e1 :"+e1.getX()+" e2 :"+e2.getX());
Log.e("kingfly", "Kingfly velocityX :"+velocityX+" velocityY :"+velocityY);
if (e1.getX() - e2.getX() > FLING_MIN_DISTANCE
&& Math.abs(velocityX) > FLING_MIN_VELOCITY) {
mFlipper.setInAnimation(inFromRightAnimation());
mFlipper.setOutAnimation(outToLeftAnimation());
mFlipper.showNext();
} else if (e2.getX() - e1.getX() > FLING_MIN_DISTANCE
&& Math.abs(velocityX) > FLING_MIN_VELOCITY) {
mFlipper.setInAnimation(inFromLeftAnimation());
mFlipper.setOutAnimation(outToRightAnimation());
mFlipper.showPrevious();
}
return false;
}
@Override
public void onLongPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.e("kingfly", "kingfly onTouch");
switch(event.getAction()){
case MotionEvent.ACTION_MOVE:
v.setAnimation(new Animation() {
});
break;
}
return mGestureDetector.onTouchEvent(event);
}
@Override
public void onAnimationEnd(Animation arg0) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animation arg0) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationStart(Animation arg0) {
// TODO Auto-generated method stub
}
}
里面引用的布局文件switch_control_panel.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/stat_switch_bg" >
<ViewFlipper
android:id="@+id/flipper"
android:layout_below="@+id/CockpitLayout"
android:layout_height="fill_parent"
android:layout_width="fill_parent">
<include android:id="@+id/firstlayout" layout="@layout/statusbarfirst"></include>
<include android:id="@+id/secondlayout" layout="@layout/statusbarsecond"></include>
</ViewFlipper>
</LinearLayout>
include里的两个都是布局文件,statusbarfirst.xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/switch_wifi"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:orientation="vertical">
<TextView
android:id="@+id/switch_text_wifi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
/>
</LinearLayout>
<ImageView
android:layout_width="2dip"
android:layout_height="match_parent"
android:background="@drawable/stat_switch_divider"
/>
<LinearLayout
android:id="@+id/switch_bluetooth"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:orientation="vertical">
<ImageView
android:id="@+id/switch_img_bluetooth"
android:layout_width="wrap_content"
android:layout_height="0dip"
android:layout_weight="1"
android:scaleType="center"
android:layout_gravity="center_horizontal"
android:background="@drawable/stat_switch_bluetooth_on"
/>
<TextView
android:id="@+id/switch_text_bluetooth"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/switch_bluetooth_summary"
/>
<ImageView
android:id="@+id/switch_ind_bluetooth"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:layout_marginLeft="6dip"
android:layout_marginRight="6dip"
android:background="@drawable/stat_switch_ind_on"
/>
</LinearLayout>
</LinearLayout>
还有就是onTouch(返回false就不会覆盖掉onClick()事件了,所以这样既可以滑动也可以点击。
其他的功能可以依照上面的代码继续添加,也可以直接用LinearLayout等布局画出来,不需要ViewFlipper,当然还要添加几个小点来提示用户有多少个视图,这样用户体验更加。