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

 更新时间:2013年06月03日 17:22:42   作者:  
用到的就是WindowManager以及WindowManager.LayoutParams,对这个LayoutParams做文章,当设置为属性后,然后,创建一个View,将这个View添加到WindowManager中就行
一、前言:
我手机从来不装这些东西,不过,有次看到同事的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时,创建一个线程,来完成释放后,向上运动的动画过程等;

相关文章

  • Android studio 解决logcat无过滤工具栏的操作

    Android studio 解决logcat无过滤工具栏的操作

    这篇文章主要介绍了Android studio 解决logcat无过滤工具栏的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-04-04
  • Android 实现左滑出现删除选项

    Android 实现左滑出现删除选项

    滑动删除的部分主要包含两个部分, 一个是内容区域(用于放置正常显示的view),另一个是操作区域(用于放置删除按钮)。下面通过本文给大家介绍Android 实现左滑出现删除选项,需要的朋友可以参考下
    2017-06-06
  • Kotlin四大组件中的broadcast广播

    Kotlin四大组件中的broadcast广播

    Android开发的四大组件分别是:活动(activity),用于表现功能;服务(service),后台运行服务,不提供界面呈现;广播接受者(Broadcast Receive),勇于接收广播;内容提供者(Content Provider),支持多个应用中存储和读取数据,相当于数据库,本篇着重介绍广播组件
    2022-12-12
  • Android仿微信支付密码弹出层功能

    Android仿微信支付密码弹出层功能

    最近项目中使用到了支付密码功能,感觉这类界面应该是比较常用的,涉及支付密码的输入的一般都会用到吧,所以单独地把这部分抽取出来,有需要的朋友可以拿去用用
    2017-04-04
  • Android Studio给各种控件加边框的操作方法

    Android Studio给各种控件加边框的操作方法

    这篇文章主要介绍了Android Studio给各种控件加边框的操作方法,本文通过图文实例相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • Android 获取drawable目录图片 并存入指定文件的步骤详解

    Android 获取drawable目录图片 并存入指定文件的步骤详解

    这篇文章主要介绍了Android 获取drawable目录图片 并存入指定文件,本文分步骤通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • 深入Android中BroadcastReceiver的两种注册方式(静态和动态)详解

    深入Android中BroadcastReceiver的两种注册方式(静态和动态)详解

    这篇文章主要介绍了深入Android中BroadcastReceiver的两种注册方式(静态和动态)详解,具有一定的参考价值,有需要的可以了解一下。
    2016-12-12
  • Flutter中渐变色的使用案例分享

    Flutter中渐变色的使用案例分享

    在日常的开发中,UI为了让界面更加吸引人往往会在界面上用到大量的渐变色,本文将通过几个案例更好的去了解Flutter中渐变色的使用,需要的可以参考一下
    2023-06-06
  • Flutter实现底部导航栏效果

    Flutter实现底部导航栏效果

    这篇文章主要为大家详细介绍了Flutter实现底部导航栏效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • Android Bitmap的加载与缓存

    Android Bitmap的加载与缓存

    这篇文章主要介绍了Android Bitmap的加载与缓存的相关资料,需要的朋友可以参考下
    2018-03-03

最新评论