不管是桌面小球,悬浮歌词,还是实时监控窗口等等,这些在我这里统统都叫做悬浮窗,虽然长相不同,但实质一样。我认为这些都是配饰,就像美女带的眼镜,耳环,更或者刺青等等,有了这些美女才更美,那有人就会辩驳了说“清水出芙蓉,天然去雕饰”。我只能这么回答你,人能达到这个境界的寥寥无几,更何况物乎。
不再闲扯,言归正传。
首先要把一个View贴在窗口上,当然我们必须能够管理这个窗口,就像看门的老大爷的通知栏一样,你没有管理权限,即使你贴上了小广告,大爷照样把你的给扯掉。就这么道理,所以
mWindowManager = (WindowManager) this.getSystemService(WINDOW_SERVICE);
我们必须能够管理窗口。
然后就是我们怎么去贴
mLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
LayoutParams.TYPE_SYSTEM_ERROR, LayoutParams.FLAG_NOT_FOCUSABLE,PixelFormat.TRANSPARENT);
mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
去设置我们要贴的大小,位置,透明度等等。
接着是怎么贴
private void refreshView() {
if (isViewAdd) {
mWindowManager.updateViewLayout(mView, mLayoutParams);
} else {
mWindowManager.addView(mView, mLayoutParams);
isViewAdd = true;
}
}
如果已经贴上了我们就只要更新就ok了,如果没有贴上,那只能贴了。
最后是贴什么了
mView = LayoutInflater.from(getApplicationContext()).inflate(R.layout.floating, null);
这就是我们要贴的了,至于floating这个布局里面是什么,就是你需要什么写什么了,什么都行,说白了就是你随便扯淡了,想咋扯咋扯了。如果你有想象力可以作出很美丽的雕饰。
举个例子,我们要想做一个控制音乐的悬浮控制板,我们的布局里面就可以定义三个ImageView,一个上一曲,一个播放与暂停,一个下一曲
mPre = (ImageView)mView.findViewById(R.id.pre);
mStartStop = (ImageView)mView.findViewById(R.id.start_stop);
mNext = (ImageView)mView.findViewById(R.id.next);
mNext.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == MotionEvent.ACTION_DOWN){
mNext.setBackgroundColor(0xff0000ff);
mContext.sendBroadcast(new Intent("com.android.music.musicservicecommand.next"));
}else if(event.getAction() == MotionEvent.ACTION_UP){
mNext.setBackgroundColor(0x88000000);
}
return true;
}
});
然后我们点击的时候去完成我们的任务就行了,就这么简单,但是这样的窗口也只能显示出来,没啥意义,所以首先,我们要让他动起来
mView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchStartX = event.getX();
mTouchStartY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
refreshView((int)(event.getRawX() - mTouchStartX), (int)(event.getRawY() - mTouchStartY));
break;
case MotionEvent.ACTION_UP:
mTouchStartX = 0;
mTouchStartY = 0;
break;
}
return false;
}
});
这就是我们拖动的代码了,当然里面的refreshView我们也贴出来
private void refreshView(int x, int y) {
if (statusBarHeight == 0) {
View rootView = mView.getRootView();
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
statusBarHeight = r.top;
}
mLayoutParams.x = x;
mLayoutParams.y = y - statusBarHeight;
refreshView();
}
当然了,我们不能把悬浮窗拖到状态栏上去了。
这样的悬浮窗口,在每个界面都有的,我们要是只想在桌面显示,怎么办呢?这个也简单。我们只要知道啥时候是桌面就行了,然后
private void showView(){
if(isEnd){
mView.setVisibility(View.GONE);
}else{
if(isShowAll){
mView.setVisibility(View.VISIBLE);
}else{
if(isCurLauncher){
mView.setVisibility(View.VISIBLE);
}else{
mView.setVisibility(View.GONE);
}
}
}
}
我们只管去隐藏和显现我们的悬浮窗就行了。那我们怎么判断是在桌面呢?办法有很多中,如果你是做方案设计的,那就简单了,直接在进入桌面的activity是做一个标记,然后检测到这个标记更改了,就如更新悬浮窗口就行了;如果你是做单独的apk的,那也有办法
class CheckTopActivityTast extends AsyncTask<Object, Object, String> {
@Override
protected String doInBackground(Object... arg0) {
// TODO Auto-generated method stub
String top_activity = null;
boolean islauncher = false;
while (true) {
top_activity = getTopActivityClassName();
if(top_activity.contains("launcher")){
islauncher = true;
}else{
islauncher = false;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(isCurLauncher == islauncher){
continue;
}else{
isCurLauncher = islauncher;
Message msg = new Message();
msg.what = 1111;
mHandler.sendMessage(msg);
}
}
}
}
private synchronized String getTopActivityClassName(){
ActivityManager mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasksInfo = mActivityManager.getRunningTasks(1);
if(null!=tasksInfo&&tasksInfo.size() > 0){
return tasksInfo.get(0).topActivity.getClassName();
}
return "";
}
就去启一个线程,一直观察top activity顶层活动了,如果是桌面Launcher,更新就是了,也就这么简单。当然了,我们这些都是在服务中进行的,这样悬浮窗才是悬浮窗。
完整代码http://download.csdn.net/detail/zhiyuan263287/6861095
悬浮窗也就这么点事儿,接下来就是一个人创造力的事情了,你有多大想象力,就能作出多么美妙的设计。