Android仿IOS AssistiveTouch(悬浮框的运用)
yama0823
8年前
<h2><strong>前言</strong></h2> <p>前面开源了一篇关于“MVP+RxJava+Retrofit+okhttp实现视频+新闻客户端”的项目阐述了 Android项目从零到上线的全过程 ,反响还不错。最近把以前做的一个 仿ios AssistiveTouch(悬浮框的运用) 的项目整理了一下。</p> <h2><strong>项目主要功能模块</strong></h2> <p style="text-align:center"><img src="https://simg.open-open.com/show/a482055c45ef064fafa1d2ef52fe29a4.png"></p> <p>主要功能</p> <p>如图所示:</p> <p>1、系统设置(回到主页、一键锁屏、手电筒)</p> <p>2、工具助手(自动抢红包、应用管理、小火箭垃圾清理)</p> <p>3、WindowManager悬浮框</p> <h2><strong>WindowManager悬浮框</strong></h2> <p>本文主要介绍WindowManager悬浮框的运用。浮动窗大家应该都不陌生,360、应用宝之类的小浮动窗口运用的就是WindowManager悬浮框。</p> <h2><strong>原理</strong></h2> <p>1、悬浮框的显示:通过getSystemService(Context.WINDOW_SERVICE)得到WindowManager,调用WindowManager的addview(View view, WindowManager.LayoutParams mLayoutParams)进行显示</p> <pre> <code class="language-java">//获取WindowManager wManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); mParams = new WindowManager.LayoutParams(); //适配小米、魅族等手机需要悬浮框权限的问题,可绕过授权 if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { wmParams.type = LayoutParams.TYPE_PHONE; } else { wmParams.type = LayoutParams.TYPE_TOAST; } // 支持透明 //mParams.format = PixelFormat.RGBA_8888; mParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 焦点 mParams.width = 490; //窗口的宽和高 mParams.height = 160; mParams.x = 0; //窗口位置的偏移量 mParams.y = 0; /** * 这里的flags也很关键 *代码实际是wmParams.flags |= FLAG_NOT_FOCUSABLE; * 40的由来是wmParams的默认属性(32)+ FLAG_NOT_FOCUSABLE(8) */ mParams.flags=40; //窗口的透明度mParams.alpha = 0.1f; myView = new MyView(this); wManager.addView(myView, mParams);//添加窗口</code></pre> <p>2、悬浮框的移动:监听view的OnTouchListener通过WindowManager的updateViewLayout(Context mContext, WindowManager.LayoutParams mLayoutParams)修改mLayoutParams的mLayoutParams.x和mLayoutParams.y从而更新浮动窗的位置</p> <pre> <code class="language-java">private OnTouchListener mTouchListener = new OnTouchListener() { float lastX, lastY; int paramX, paramY; public boolean onTouch(View v, MotionEvent event) { final int action = event.getAction(); float x = event.getRawX(); float y = event.getRawY(); if (mTag == 0) { mOldOffsetX = mViewEventMParams.x; // 偏移量 mOldOffsetY = mViewEventMParams.y; // 偏移量 } switch (action) { case MotionEvent.ACTION_DOWN: motionActionDownEvent(x, y); break; case MotionEvent.ACTION_MOVE: motionActionMoveEvent(x, y); break; case MotionEvent.ACTION_UP: motionActionUpEvent(x, y); break; default: break; } return true; } private void motionActionDownEvent(float x, float y) { lastX = x; lastY = y; paramX = mViewEventMParams.x; paramY = mViewEventMParams.y; } private void motionActionMoveEvent(float x, float y) { int dx = (int) (x - lastX); int dy = (int) (y - lastY); mViewEventMParams.x = paramX + dx; mViewEventMParams.y = paramY + dy; mTag = 1; // 更新悬浮窗位置 mWManager.updateViewLayout(mTouchView, mViewEventMParams); } private void motionActionUpEvent(float x, float y) { int newOffsetX = mViewEventMParams.x; int newOffsetY = mViewEventMParams.y; if (mOldOffsetX == newOffsetX && mOldOffsetY == newOffsetY) { updateSettingTableView(); mPopuWin = new PopupWindow(mSettingTable, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); mPopuWin.setTouchInterceptor(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { hideSettingTable(); return true; } return false; } }); mPopuWin.setBackgroundDrawable(new BitmapDrawable()); mPopuWin.setTouchable(true); mPopuWin.setFocusable(true); mPopuWin.setOutsideTouchable(true); mPopuWin.setContentView(mSettingTable); if (Math.abs(mOldOffsetX) > midX) { if (mOldOffsetX > 0) { mOldOffsetX = midX; } else { mOldOffsetX = -midX; } } if (Math.abs(mOldOffsetY) > midY) { if (mOldOffsetY > 0) { mOldOffsetY = midY; } else { mOldOffsetY = -midY; } } mPopuWin.setAnimationStyle(R.style.AnimationPreview); mPopuWin.setFocusable(true); mPopuWin.update(); mPopuWin.showAtLocation(mTouchView, Gravity.CENTER, -mOldOffsetX, -mOldOffsetY); // TODO mIconImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.transparent)); catchSettingTableDismiss(); } else { mTag = 0; } }};</code></pre> <p>3、悬浮框的删除:调用WindowManager的removeView(View view)</p> <h2><strong>自动抢红包</strong></h2> <p>原理就是根据关键字找到相应的View, 然后自动点击。主要是用到AccessibilityService这个辅助服务,基本可以满足自动抢红包的功能,但是有些逻辑需要优化,比如,拆完一个红包后,必须手动点击返回键,才能进行下一次自动抢红包。</p> <p> </p> <p> </p> <p> </p>