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>