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

龙姗之恋

龙姗之恋

2016-02-19 09:31

给自己一点时间接受自己,爱自己,趁着下午茶的时间来学习图老师推荐的Android实现类似360,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时,创建一个线程,来完成释放后,向上运动的动画过程等;
展开更多 50%)
分享

猜你喜欢

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

编程语言 网络编程
Android实现类似360,QQ管家那样的悬浮窗

怎么关闭360好搜悬浮窗?好搜悬浮窗关闭步骤

手机软件
怎么关闭360好搜悬浮窗?好搜悬浮窗关闭步骤

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

360好搜悬浮窗怎么关闭?

手机软件 应用软件
360好搜悬浮窗怎么关闭?

360流量卫士怎么关闭悬浮窗

手机软件 应用软件
360流量卫士怎么关闭悬浮窗

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

360好搜如何开启悬浮窗?

手机软件
360好搜如何开启悬浮窗?

安卓系统管家怎么关闭桌面悬浮窗

手机软件 应用软件
安卓系统管家怎么关闭桌面悬浮窗

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

实现一个年、月、季度联动SELECT的javascript代码

实现一个年、月、季度联动SELECT的javascript代码

MySQL 错误处理例子[译]

MySQL 错误处理例子[译]
下拉加载更多内容 ↓