博客
关于我
第13章 CustomView控件高级属性
阅读量:674 次
发布时间:2019-03-16

本文共 7071 字,大约阅读时间需要 23 分钟。

GestureDetector 手势识别技术与 WindowManager 悬浮窗口开发

在 Android 开发中,手势识别和悬浮窗口功能是开发者常用的功能。下面将详细介绍 GestureDetector 手势检测及其实现技巧以及 WindowManager 及其应用方法。

1. GestureDetector 手势检测

GestureDetector(手势检测器)是 Android 提供的一种强大手势识别工具,能够识别多种常见手势,如单击、双击、长按、滑动等。通过借助 GestureDetectorела sighnalしの手势事件,可以实现丰富的交互效果。

手势检测器的基本结构

  • 手势监听接口:GestureDetector 启用了 GestureDetector.OnGestureListener 接口,该接口包含多个回调方法:

    • onDown(MotionEvent e):用户按下屏幕触发。
    • onShowPress(MotionEvent e):长按或拖动触发。
    • onSingleTapUp(MotionEvent e):快速单击后释放触发。
    • onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY):屏幕拖动触发。
    • onLongPress(MotionEvent e):长按触发。
    • onFling(MotionEvent el, MotionEvent e2, float velocityX, float velocityY):快速滑动触发。
  • 手势触发顺序

    • 按下 → 显示长按 → 滑动 → 长按
    • 快速单击 → 快速单击后确认
  • 滑动和拖动的区别

    • 滑动是快速移动并松开。
    • 拖动是按住并慢慢移动。
  • 示例实现

    class MainActivity : Activity(), View.OnTouchListener {    private lateinit var mGestureDetector: GestureDetector    private val myGestureListener = object : GestureDetector.OnGestureListener {        override fun onDown(e: MotionEvent?): Boolean {            // 进行单击、双击逻辑判断            return false        }        // override other methods...    }    override fun onTouch(v: View, event: MotionEvent): Boolean {        return mGestureDetector.onTouchEvent(event)    }    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)        // 给控件设置触摸事件拦截        findViewById(R.id.myView).setOnTouchListener(this)        mGestureDetector = GestureDetector(this, myGestureListener)    }}
  • 滑动方向识别

    class SimpleGestureListener : GestureDetector.SimpleOnGestureListener {    val FLING_MIN_DISTANCE = 100    val FLING_MIN_VELOCITY = 200    override fun onFling(el: MotionEvent?, e2: MotionEvent?,                       velocityX: Float, velocityY: Float): Boolean {        val distanceX = e2!!.getX() - el!!.getX()        val distanceY = e2!!.getY() - el!!.getY()        if (distanceX > FLING_MIN_DISTANCE) {            // 判断左滑与右滑方向            Log.d("TAG", "左滑事件发生")        }        return true    }}
  • 2. WindowManager 悬浮窗口开发

    WindowManager 是用于管理窗口的核心工具,常用于创建悬浮窗口或调整现有窗口的布局属性。

    WindowManager 的基础知识

  • 窗口属性设置

    • 类型:Window默认类型为 ActivityWindow,最常见的是应用程序窗口。
    • 布局参数:包含窗口的尺寸、位置、格式等。
    • 标志位:如 FLAG_NOT_FOCUSABLE(不接收输入事件)、 FLAG_NOT_TOUCH_MODAL(阻止其他窗口的触摸事件)。
  • 权限声明:创建系统层级的窗口需要添加权限:

  • 动态获取窗口管理器

    WindowManager windowManager = getSystemService(WINDOW_SERVICE);
  • 悬浮窗口的实现步骤

  • 创建悬浮窗口

    // 获取窗口管理器WindowManager defaultManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);// 定义窗口属性WindowManager.LayoutParams params = new WindowManager.LayoutParams(    WindowManager.LayoutParams.WRAP_CONTENT, // 宽度    WindowManager.LayoutParams.WRAP_CONTENT, // 高度    WindowManager.LayoutParams.TYPE_PHONE, // 窗口类型    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | // 阻止当前窗口接收其他窗口的触摸事件      WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); // 不接收焦点事件// 创建或者获取目标视图View targetView = new ImageView(this); // 或者获取已有视图// 设置视图属性(如背景、大小等)targetView.setBackgroundResource(R.drawable.default_drawable);// 添加悬浮窗口defaultManager.addView(targetView, params);
  • 控制悬浮窗口的位置

    // 在 onTouchεφ event 中更新位置@Overridepublic boolean onTouch(View v, MotionEvent event) {    // 检查是否是 MOVE事件    if (event.getAction() == MotionEvent.ACTION_MOVE) {        // 更新窗口属性        params.x = (int) event.getRawX();        params.y = (int) event.getRawY();        // 更新窗口布局        windowManager.updateViewLayout(targetView, params);    }    return false; // 返回true则会触发点击事件}
  • 关闭或移除窗口

    @Overrideprotected void onDestroy() {    try {        windowManager.removeView(targetView);    } catch (IllegalArgumentException e) {        e.printStackTrace();    }    super.onDestroy();}
  • 示例代码

    以下是一个完整的悬浮窗口创建与控制示例:

    public class FloatingWindowActivity extends Activity implements View.OnTouchListener {    private WindowManager windowManager;    private Button addBtn, rmvBtn;    private ImageView floatingView;    private WindowManager.LayoutParams params;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.floating_window);        addBtn = (Button) findViewById(R.id.add_btn);        rmvBtn = (Button) findViewById(R.id.rmv_btn);        floatingView = (ImageView) findViewById(R.id.floating_view);        addBtn.setOnClickListener(this);        rmvBtn.setOnClickListener(this);        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);        // 检查是否需要添加权限(手动申请)        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {            requestOverlayPermission();        }        addFloatingView();    }    private void addFloatingView() {        params = new WindowManager.LayoutParams(            WindowManager.LayoutParams.WRAP_CONTENT,            WindowManager.LayoutParams.WRAP_CONTENT,            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,            PixelFormat.TRANSPARENT        );        params.gravity = Gravity.TOP | Gravity.LEFT;        params.x = 0;        params.y = 50;        floatingView.setBackgroundResource(R.drawable.ic_bullet);        windowManager.addView(floatingView, params);    }    private void requestOverlayPermission() {        if (CheckPermission.isPermissionGranted(            this,            Settings.ACTION_MANAGE_OVERLAY_PERMISSION,            100        )) {            initView();        }    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        if (requestCode == 100 && resultCode == Activity.RESULT_OK) {            addFloatingView();        }    }    @Override    public boolean onTouch(View v, MotionEvent event) {        int rawX = (int) event.getRawX();        int rawY = (int) event.getRawY();        if (event.action == MotionEvent.ACTION_MOVE) {            params.x = rawX;            params.y = rawY;            windowManager.updateViewLayout(floatingView, params);        }        return true; // 返回true会触发onClick事件    }    @Override    public void onClick(View v) {        if (v == addBtn) {            addFloatingView();        } else if (v == rmvBtn) {            windowManager.removeView(floatingView);        }    }    @Override    protected void onDestroy() {        try {            windowManager.removeView(floatingView);        } catch (IllegalArgumentException e) {            e.printStackTrace();        }        super.onDestroy();    }}

    关键权限管理

  • 动态权限申请 (适用于 API >= 23):

    private void requestOverlayPermission() {    if (ContextCompat.checkSelfPermission(this, Manifest.permission.SYSTEM_ALERT_WINDOW)        != PackageManager.PERMISSION_GRANTED) {        ActivityCompat.requestPermissions(this, arrayOfString(Manifest.permission.SYSTEM_ALERT_WINDOW), 100);    }}
  • 权限检查方法

    private val CheckPermission = object : PermissionChecker() {}
  • 总结

    GestureDetector 是 Android 开发中强大的手势识别工具,可以通过实现相关回调方法识别多种手势,如单击、双击、滑动、长按等。WindowManager 是实现悬浮窗口的核心工具,适用于在不同窗口层级中添加、更新和移除视图内容。

    通过合理使用这些工具,可以在应用程序中实现丰富的手势交互和悬浮窗口功能。这两种技术在开发中有着广泛的应用场景,值得开发者深入了解和实践。

    转载地址:http://wsmqz.baihongyu.com/

    你可能感兴趣的文章
    Object.assign用法
    查看>>
    Object.create
    查看>>
    Object.keys()的详解和用法
    查看>>
    objectForKey与valueForKey在NSDictionary中的差异
    查看>>
    Objective - C 小谈:消息机制的原理与使用
    查看>>
    OBJECTIVE C (XCODE) 绘图功能简介(转载)
    查看>>
    Objective-C ---JSON 解析 和 KVC
    查看>>
    Objective-C 编码规范
    查看>>
    Objective-Cfor循环实现Factorial阶乘算法 (附完整源码)
    查看>>
    Objective-C——判断对象等同性
    查看>>
    objective-c中的内存管理
    查看>>
    Objective-C之成魔之路【7-类、对象和方法】
    查看>>
    Objective-C享元模式(Flyweight)
    查看>>
    Objective-C以递归的方式实现二叉搜索树算法(附完整源码)
    查看>>
    Objective-C内存管理教程和原理剖析(三)
    查看>>
    Objective-C实现 Greedy Best First Search最佳优先搜索算法(附完整源码)
    查看>>
    Objective-C实现 jugglerSequence杂耍者序列算法 (附完整源码)
    查看>>
    Objective-C实现 lattice path格子路径算法(附完整源码)
    查看>>
    Objective-C实现1000 位斐波那契数算法(附完整源码)
    查看>>
    Objective-C实现2 个数字之间的算术几何平均值算法(附完整源码)
    查看>>