Android实现类似360,QQ管家那样的悬浮窗
Android实现类似360,QQ管家那样的悬浮窗
发布时间:2016-12-28 来源:查字典编辑
摘要:一、前言:我手机从来不装这些东西,不过,有次看到同事的android手机上,有个QQ管家在桌面上浮着,同事拖动管家时,管家就变成一只鸟,桌面...

一、前言:

我手机从来不装这些东西,不过,有次看到同事的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时,创建一个线程,来完成释放后,向上运动的动画过程等;

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新安卓软件开发学习
热门安卓软件开发学习
编程开发子分类