您的位置:首页 > 移动开发 > Android开发

Android实现类似360,QQ管家那样的悬浮窗

2013-12-10 09:19 453 查看
一、前言: 

我手机从来不装这些东西,不过,有次看到同事的android手机上,有个QQ管家在桌面上浮着,同事拖动管家时,管家就变成一只鸟,桌面下方还有个弹弓,桌面顶部有只乌鸦,把管家也就是鸟拖动到弹弓那,然后,松手,鸟就飞出去。这个过程是动画过程,做的事,实际上是清楚内存。 

二:原理: 

其实,没什么原理,用到的就是WindowManager以及WindowManager.LayoutParams,对这个LayoutParams做文章,当设置为属性后,然后,创建一个View,将这个View添加到WindowManager中就行。 

复制代码 代码如下:

package com.chris.floats.window; 

import android.os.Bundle; 

import android.util.DisplayMetrics; 

import android.view.Gravity; 

import android.view.WindowManager; 

import android.app.Activity; 

import android.content.Context; 

public class MainActivity extends Activity { 

private static WindowManager mWindowMgr = null; 

private WindowManager.LayoutParams mWindowMgrParams = null; 

private static FloatsWindowView mFloatsWindowView = null; 

@Override 

protected void onCreate(Bundle savedInstanceState) { 

super.onCreate(savedInstanceState); 

setContentView(R.layout.activity_main); 



/* 

* 显示应用主界面时,去除悬浮层 

*/ 

@Override 

public void onWindowFocusChanged(boolean hasFocus) { 

if(hasFocus){ 

if(mFloatsWindowView != null){ 

mWindowMgr.removeView(mFloatsWindowView); 

mFloatsWindowView = null; 



}else{ 

getWindowLayout(); 





private void initParams(){ 

DisplayMetrics dm = getResources().getDisplayMetrics(); 

mWindowMgrParams.x = dm.widthPixels - 136; 

mWindowMgrParams.y = 300; 

mWindowMgrParams.width = 136; 

mWindowMgrParams.height = 136; 



private void getWindowLayout(){ 

if(mFloatsWindowView == null){ 

mWindowMgr = (WindowManager)getBaseContext().getSystemService(Context.WINDOW_SERVICE); 

mWindowMgrParams = new WindowManager.LayoutParams(); 

/* 

* 2003 在指悬浮在所有界面之上 

* (4.0+系统中,在下拉菜单下面,而在2.3中,在上拉菜单之上) 

*/ 

mWindowMgrParams.type = 2003; 

mWindowMgrParams.format = 1; 

/* 

* 代码实际是wmParams.flags |= FLAG_NOT_FOCUSABLE; 

* 40的由来是wmParams的默认属性(32)+ FLAG_NOT_FOCUSABLE(8) 

*/ 

mWindowMgrParams.flags = 40; 

mWindowMgrParams.gravity = Gravity.LEFT | Gravity.TOP; 

initParams(); 

mFloatsWindowView = new FloatsWindowView(this); 

mWindowMgr.addView(mFloatsWindowView, mWindowMgrParams); 







上面代码,主要在getWindowLayout函数中,最后两行就是创建一个View,并加入到WindowManager中。 

继承View的悬浮View: 

复制代码 代码如下:

package com.chris.floats.window; 

import android.content.Context; 

import android.content.Intent; 

import android.graphics.drawable.AnimationDrawable; 

import android.util.AttributeSet; 

import android.util.DisplayMetrics; 

import android.view.Gravity; 

import android.view.MotionEvent; 

import android.view.View; 

import android.view.ViewTreeObserver.OnPreDrawListener; 

import android.view.WindowManager; 

public class FloatsWindowView extends View { 

private Context mContext = null; 

private WindowManager mWindowMgr = null; 

private WindowManager.LayoutParams mWindowMgrParams = null; 

private AnimationDrawable mAnimationDrawable = null; 

private int iPosX = 0; 

private int iPosY = 0; 

private int iLastPosX = 0; 

private int iLastPosY = 0; 

private boolean bMoved = false; 

public FloatsWindowView(Context context) { 

this(context, null, 0); 



public FloatsWindowView(Context context, AttributeSet attrs) { 

this(context, attrs, 0); 



public FloatsWindowView(Context context, AttributeSet attrs, int defStyle) { 

super(context, attrs, defStyle); 

mContext = context; 

mWindowMgr = (WindowManager)getContext().getApplicationContext().getSystemService("window"); 

mWindowMgrParams = new WindowManager.LayoutParams(); 

initParams(); 

mAnimationDrawable = new AnimationDrawable(); 

for(int i = 0; i < 4; i++){ 

int id = getResources().getIdentifier("a"+ i, "drawable", mContext.getPackageName()); 

mAnimationDrawable.addFrame(getResources().getDrawable(id), 100); 



mAnimationDrawable.setOneShot(false); 

this.setBackgroundDrawable(mAnimationDrawable); 

OnPreDrawListener listener = new OnPreDrawListener(){ 

@Override 

public boolean onPreDraw() { 

mAnimationDrawable.start(); 

return true; 



}; 

this.getViewTreeObserver().addOnPreDrawListener(listener); 



private void initParams(){ 

DisplayMetrics dm = getResources().getDisplayMetrics(); 

mWindowMgrParams.x = dm.widthPixels - 136; 

mWindowMgrParams.y = 300; 

mWindowMgrParams.width = 136; 

mWindowMgrParams.height = 136; 



@Override 

public boolean onTouchEvent(MotionEvent event) { 

switch(event.getAction()){ 

case MotionEvent.ACTION_DOWN: 

iPosX = (int)event.getX(); 

iPosY = (int)event.getY(); 

bMoved = false; 

break; 

case MotionEvent.ACTION_MOVE: 

bMoved = true; 

iLastPosX = (int)event.getX(); 

iLastPosY = (int)event.getY(); 

updatePostion(iLastPosX - iPosX, iLastPosY - iPosY); 

break; 

case MotionEvent.ACTION_UP: 

if(!bMoved){ 

Intent it=new Intent(mContext, MainActivity.class); 

mContext.startActivity(it); 



break; 

default: 

break; 



return true; 



private void updatePostion(int x, int y){ 

mWindowMgrParams.type = 2003; 

mWindowMgrParams.format = 1; 

mWindowMgrParams.flags = 40; 

mWindowMgrParams.gravity = Gravity.LEFT | Gravity.TOP; 

mWindowMgrParams.x += x; 

mWindowMgrParams.y += y; 

mWindowMgr.updateViewLayout(this, mWindowMgrParams); 





之所以将updatePosition中的参数与Activity中设置一样,是为了确保在MOVE时,造成相对位置的不一样,而导致闪砾,大家要是不理解,可以实验下。

三、小结: 

这篇文章实现了简单的悬浮窗口动画效果,如果要想做成像360,QQ管家那样,还需要一些其它的操作: 

1. 比如启动一个后台服务来监控系统信息; 

2. ACTION_DOWN时,修改悬浮窗口上的图片; 

3. ACTION_MOVE时窗口跟随; 

4. ACTION_UP时,创建一个线程,来完成释放后,向上运动的动画过程等; 

详细出处参考:http://www.jb51.net/article/37817.htm
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: