蹭一波热度:记微信跳一跳辅助线开发

蹭一波热度:记微信跳一跳辅助线开发

  • 场景
    前两天下午三点多时候,老板突然一个电话过来:“那个小甘啊,最近微信跳一跳小游戏很火啊,我们现在已经有了全自动脚本了,现在需要一个提升用户参与感的辅助工具,就是需要一条辅助线来帮助用户得到更高分,这个东西你来做一下,务必用最短的时间把它实现了。”唉,那么没办法只能开撸了。

  • 基本思路
    既然是辅助线,那么肯定是在所有窗口的前面,看到这个自然就想到了利用WindowManager来实现一个悬浮在所有窗口前面的Window,利用Service在后台不断更新小人头部的坐标,通过监听手指按下和弹起不断在Window中addView和removeView来绘制辅助线。Tips:监听手指在屏幕上的事件和不断寻找小人头部坐标是Native以前实现好的成熟方案=。=这里我并不会。

  • 编码实现
    1.Service关键代码
    创建没有事件的悬浮窗

private void createToucher() {
    //赋值WindowManager&LayoutParam.
    params = new WindowManager.LayoutParams();
    windowManager = (WindowManager) getApplication().getSystemService(Context.WINDOW_SERVICE);
    //设置type.系统提示型窗口,一般都在应用程序窗口之上.
    params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
    //设置效果为背景透明.
    params.format = PixelFormat.RGBA_8888;
    //设置flags.不可聚焦及不可使用按钮对悬浮窗进行操控.
    params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
        | WindowManager.LayoutParams.FLAG_FULLSCREEN
    ;

    //设置窗口初始停靠位置.
    params.gravity = Gravity.LEFT | Gravity.TOP;
    params.x = 0;
    params.y = 0;

    params.width = WindowManager.LayoutParams.WRAP_CONTENT;
    params.height = WindowManager.LayoutParams.WRAP_CONTENT;
  }

WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE这三个标记很重要,不加会拦截事件,导致其他窗口无法响应事件。

监听手指按下与弹起并绘制辅助线

 @Override
      public void onTouchDown() {   /*手指按下时开始画线*/
        try {
          if (point.x != -1 && point.y != -1) {
            lineView = new LineView(DrawLineService.this);
            lineView.start(point.x, point.y);
            windowManager.addView(lineView, params);
          }
        } catch (Exception ignored) {
        }
      }
      @Override
      public void onTouchUp() {
        try {   /*手指弹起时释放画线*/
          lineView.stop();
          windowManager.removeView(lineView);
        } catch (Exception ignored) {
        }
      }

2.辅助线的View

public class LineView extends View {

  private static final float SPEED_X = 0.60f / 1080f;
  private static final float SPEED_Y = 0.35f / 1920f;

  private float mx, my, incrementY, incrementX;
  private int mWidth;
  private int mHeight;

  private long startTime;
  private Timer mTimer = new Timer();
  TimerTask mTimerTask;
  Paint p;

  private float mHeadOffset;
  public static float gOffset = 1f;

  /*因为底层接口返回的是小人头部坐标 线需要从脚部开始划 所以需要调整*/
  private float mDefaultHeadOffset = 40f;  

  public LineView(Context context) {
    super(context);
    init();
  }

  private void init() {
    DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
    mWidth = displayMetrics.widthPixels;
    mHeight = displayMetrics.heightPixels;
    p = new Paint();
    p.setColor(Color.RED);
    p.setAntiAlias(true);
    p.setStrokeWidth(10.0f);
    mHeadOffset = ConvertUtils.dip2px(getContext(), mDefaultHeadOffset);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawLine(mx, my, incrementX, incrementY, p);// 斜线
  }


  /**
   * 手指按压住以后该方法执行,内部使用TimerTask完成直线绘制
   *
   * @param x 小人头部x坐标
   * @param y 小人头部y坐标
   */
  public void start(float x, float y) {
    startTime = System.currentTimeMillis();
    y += mHeadOffset;  /*小人脚部y坐标*/
    this.incrementX = x;
    this.incrementY = y;
    this.mx = x;
    this.my = y;
    if (isRight(mx)) {
      mTimerTask = new TimerTask() {
        @Override
        public void run() {
          float ellapsed = System.currentTimeMillis() - startTime;
          /**
           * tips:0.35和0.60是根据测试结果调出来的 需要根据实际情况优化
           */
          incrementY = my - ellapsed * SPEED_Y * mHeight * gOffset;   /* y / x = 0.58*/
          incrementX = mx - ellapsed * SPEED_X * mWidth * gOffset;
          postInvalidate();
        }
      };
    } else {
      mTimerTask = new TimerTask() {
        @Override
        public void run() {
          float ellapsed = System.currentTimeMillis() - startTime;
          incrementY = my - ellapsed * SPEED_Y * mHeight * gOffset;
          incrementX = mx + ellapsed * SPEED_X * mWidth * gOffset;
          postInvalidate();
        }
      };
    }
    /*每隔10ms绘制一次*/
    mTimer.schedule(mTimerTask, 0, 10);
  }

  /**
   * 手指松开时调用该方法,调用时停止画线
   */
  public void stop() {
    mTimerTask.cancel();
    mTimerTask = null;
  }

  /**
   * 判断当前小人在左边还是右边(根据左右来判断斜线往哪边画)
   * @return true 右边 false坐标
   */
  private boolean isRight(float x) {
    WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
    int width = wm.getDefaultDisplay().getWidth();
    if (x < width / 2) {
      return false; //left
    } else {
      return true;
    }
  }
}
  • 最后附上效果图

这里写图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值