Android 之浮窗篇

本文详细介绍如何在Android应用中实现一个可拖动的悬浮窗口。包括创建浮窗的步骤、触摸移动逻辑、权限配置等关键信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android 之浮窗篇

所谓浮窗就是悬浮在屏幕上的一个小窗口,可以拖到,点击等。像360的那个所谓的加速球就是一个经典的浮窗。我们就是要做一个这样的东西。

 

1、创建浮窗,同理,也是要扩展某一个东西的,我们这里选择的是linearlayout。你也可以选择view,或者imageview等等。废话不多说,我直接把代码填出来把。

 

public class FloatWindowView extends LinearLayout {

 

    public FloatWindowView(Context context) {

super(context);

    }

 

    private float mTouchX;

    private float mTouchY;

    private float x;

    private float y;

    private float mStartX;

    private float mStartY;

    private OnClickListener mClickListener;

    private WindowManager windowManager = (WindowManager) getContext()

    .getApplicationContext().getSystemService("window");

 

    // 此windowManagerParams变量为获取的全局变量,用以保存悬浮窗口的属性

    private WindowManager.LayoutParams windowManagerParams = Constant.windowParams;

 

    @Override

    public boolean onTouchEvent(MotionEvent event) {

// 获取到状态栏的高度

Rect frame = new Rect();

 

getWindowVisibleDisplayFrame(frame);

 

int statusBarHeight = frame.top;

 

System.out.println("statusBarHeight:" + statusBarHeight);

 

// 获取相对屏幕的坐标,即以屏幕左上角为原点

x = event.getRawX();

 

// statusBarHeight是系统状态栏的高度

y = event.getRawY() - statusBarHeight;

 

Log.i("tag""currX" + x + "====currY" + y);

 

switch (event.getAction()) {

 

// 捕获手指触摸按下动作

case MotionEvent.ACTION_DOWN:

    // 获取相对View的坐标,即以此View左上角为原点

    mTouchX = event.getX();

    mTouchY = event.getY();

    mStartX = x;

    mStartY = y;

    Log.i("tag""startX" + mTouchX + "====startY" + mTouchY);

    break;

// 捕获手指触摸移动动作

case MotionEvent.ACTION_MOVE:

    updateViewPosition();

    break;

// 捕获手指触摸离开动作

case MotionEvent.ACTION_UP:

    updateViewPosition();

    mTouchX = mTouchY = 0;

    if ((x - mStartX) < 5 && (y - mStartY) < 5) {

if (mClickListener != null) {

    mClickListener.onClick(this);

}

    }

    break;

}

return true;

    }

 

    @Override

    public void setOnClickListener(OnClickListener l) {

this.mClickListener = l;

    }

 

    private void updateViewPosition() {

// 更新浮动窗口位置参数

windowManagerParams.x = (int) (x - mTouchX);

windowManagerParams.y = (int) (y - mTouchY);

windowManager.updateViewLayout(thiswindowManagerParams); // 刷新显示

    }

}

2、这里特别要注意Constant这个类,这是一个常量类

public class Constant {

 

    /**

     * 此windowManagerParams变量为获取的全局变量,用以保存悬浮窗口的属性

     */

    public static final WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams();

}

 

3、最后一步就是使用FloatWindowView这个类了。

这里需要声明三个变量。我就直接粘贴代码了。因为我把这个浮窗放在了service里面,所有你看到的是在service里面的创建浮窗的代码。

public class ScreenCaptureService extends Service {

 

    /**

     * 浮窗对象

     */

    private FloatWindowView floatWindow;

 

    /**

     * 窗口管理器

     */

    private WindowManager windowManager = null;

 

    /**

     * 窗口布局

     */

    private WindowManager.LayoutParams windowManagerParams = null;

 

    /**

     * 内部类对象,这个就不知道是一种什么设计模式了

     */

    private final IBinder baseBinder = new ScreenCaptureServiceBinder();

 

    /**

     * 内部类,这样的用法还是第一次见,他返回外部类,然后在与外部类绑定的Activity中使用外部类来操作相关的细节内容

     * 

     * @author jeck

     * 

     */

    public class ScreenCaptureServiceBinder extends Binder {

 

public ScreenCaptureService getService() {

    return ScreenCaptureService.this;

}

    }

 

    @Override

    public int onStartCommand(Intent intent, int flags, int startId) {

 

// 创建浮窗

crateFloatWindow();

 

return super.onStartCommand(intent, flags, startId);

    }

 

    @Override

    public IBinder onBind(Intent intent) {

return baseBinder;

    }

 

    @Override

    public void onCreate() {

super.onCreate();

    }

 

    @Override

    public void onDestroy() {

super.onDestroy();

stopSelf();

    }

 

    /**

     * 创建浮窗

     */

    private void crateFloatWindow() {

 

floatWindow = new FloatWindowView(getApplicationContext());

 

floatWindow.setOnClickListener(new OnClickListener() {

 

    @Override

    public void onClick(View v) {

 

// if (isStartCapture) {

//

// // 停止录制

// isStartCapture = false;

// captureState = 0;

//

// Toast.makeText(getApplicationContext(), "录制结束",

// Toast.LENGTH_LONG).show();

//

// } else {

//

// // 启动录屏进程

// // new ScreenCaptureTask().execute();

//

// // 开始录制

// isStartCapture = true;

// captureState = 1;

//

// Toast.makeText(getApplicationContext(), "开始录屏,再次点击停止录屏",

// Toast.LENGTH_LONG).show();

//

// }

 

    }

});

 

ImageView view = new ImageView(this);

 

// 为浮窗添加图片

view.setImageResource(R.drawable.float_window_icon);

 

// 这里简单的用自带的icon来做演示

floatWindow.addView(view);

 

windowManager = (WindowManager) getApplicationContext()

.getSystemService("window");

 

// 设置LayoutParams(全局变量)相关参数

windowManagerParams = Constant.windowParams;

// 设置window type

windowManagerParams.type = 2003;

// windowManagerParams.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明

// 设置Window flag

windowManagerParams.flags = 40;

windowManagerParams.format = 1;

 

// 调整悬浮窗口至左上角,便于调整坐标

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

 

// 以屏幕左上角为原点,设置x、y初始值

windowManagerParams.x = 100;

windowManagerParams.y = 100;

 

// 设置悬浮窗口长宽数据

windowManagerParams.width = 80;

windowManagerParams.height = 80;

 

// 显示myFloatView图像

windowManager.addView(floatWindowwindowManagerParams);

    }

}

4、最后一定要记得加权限,否则会报错的哟,这一点非常重要

 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值