本文共 7071 字,大约阅读时间需要 23 分钟。
在 Android 开发中,手势识别和悬浮窗口功能是开发者常用的功能。下面将详细介绍 GestureDetector 手势检测及其实现技巧以及 WindowManager 及其应用方法。
GestureDetector(手势检测器)是 Android 提供的一种强大手势识别工具,能够识别多种常见手势,如单击、双击、长按、滑动等。通过借助 GestureDetectorела sighnalしの手势事件,可以实现丰富的交互效果。
手势监听接口:GestureDetector 启用了 GestureDetector.OnGestureListener 接口,该接口包含多个回调方法:
手势触发顺序:
滑动和拖动的区别:
示例实现:
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 }}WindowManager 是用于管理窗口的核心工具,常用于创建悬浮窗口或调整现有窗口的布局属性。
窗口属性设置:
权限声明:创建系统层级的窗口需要添加权限:
动态获取窗口管理器:
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/