文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何在android中制作一个方向轮盘详解

2024-04-02 19:55

关注

先上效果图

原理很简单,其实就是一个自定义的view

通过观察,很容易发现,我们自己的轮盘就两个view需要绘制,一个是外面的圆盘,一个就随手指移动的滑块;
外面的圆盘很好绘制,内部的滑块则需要采集手指的位置,根据手指的位置计算出滑块在大圆内的位置;
最后,我们做的UI不是单纯做一个UI吧,肯定还是要用于实际应用中去,所以要加一个通用性很好的回调.

计算滑块位置的原理:

已知大圆圆心坐标(cx,cy),大圆半径rout,小圆半径rinside,触摸点的坐标(px,py)
求小圆的圆心(ax,ay)?

作为经过九义的你我来说,这不就是一个简简单单的数学题嘛,很容易就求解出小圆的圆心位置了。
利用三角形相似:

通用性很好的接口:

滑块在圆中的位置,可以很好的用一个二位向量来表示,也可以用两个浮点的变量来表示;

这个接口就可以很好的表示了小圆在大圆的位置了,他们的取值范围是[-1,1]

小技巧:

为了小圆能始终在脱手后回到终点位置,我们设计了一个动画,当然,实际情况中有一种情况是,你移动到某个位置后,脱手后位置不能动,那你禁用这个动画即可。

代码部分

tips:代码部分的变量名与原理的变量名有出入


public class ControllerView extends View implements View.OnTouchListener {
  private Paint borderPaint = new Paint();//大圆的画笔
  private Paint fingerPaint = new Paint();//小圆的画笔
  private float radius = 160;//默认大圆的半径
  private float centerX = radius;//大圆中心点的位置cx
  private float centerY = radius;//大圆中心点的位置cy
  private float fingerX = centerX, fingerY = centerY;//小圆圆心的位置(ax,ay)
  private float lastX = fingerX, lastY = fingerY;//小圆自动回归中点动画中上一点的位置
  private float innerRadius = 30;//默认小圆半径
  private float radiusBorder = (radius - innerRadius);//大圆减去小圆的半径
  private ValueAnimator positionAnimator;//自动回中的动画
  private MoveListener moveListener;//移动回调的接口

  public ControllerView(Context context) {
    super(context);
    init(context, null, 0);
  }

  public ControllerView(Context context,
      @Nullable AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs, 0);
  }

  public ControllerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs, defStyleAttr);
  }

  //初始化
  private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    if (attrs != null) {
      TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ControllerView);
      int fingerColor = typedArray.getColor(R.styleable.ControllerView_fingerColor,
          Color.parseColor("#3fffffff"));
      int borderColor = typedArray.getColor(R.styleable.ControllerView_borderColor,
          Color.GRAY);
      radius = typedArray.getDimension(R.styleable.ControllerView_radius, 220);
      innerRadius = typedArray.getDimension(R.styleable.ControllerView_fingerSize, innerRadius);
      borderPaint.setColor(borderColor);
      fingerPaint.setColor(fingerColor);
      lastX = lastY = fingerX = fingerY = centerX = centerY = radius;
      radiusBorder = radius - innerRadius;
      typedArray.recycle();
    }
    setOnTouchListener(this);
    positionAnimator = ValueAnimator.ofFloat(1);
    positionAnimator.addUpdateListener(animation -> {
      Float aFloat = (Float) animation.getAnimatedValue();
      changeFingerPosition(lastX + (centerX - lastX) * aFloat, lastY + (centerY - lastY) * aFloat);
    });
  }

  @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(getActualSpec(widthMeasureSpec), getActualSpec(heightMeasureSpec));
  }


  //处理wrapcontent的测量
  //默认wrapcontent,没有做matchParent,指定大小的适配
  //view实际的大小是通过大圆半径确定的
  public int getActualSpec(int spec) {
    int mode = MeasureSpec.getMode(spec);
    int len = MeasureSpec.getSize(spec);
    switch (mode) {
      case MeasureSpec.AT_MOST:
        len = (int) (radius * 2);
        break;
    }
    return MeasureSpec.makeMeasureSpec(len, mode);
  }

  //绘制
  @Override protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawCircle(centerX, centerY, radius, borderPaint);
    canvas.drawCircle(fingerX, fingerY, innerRadius, fingerPaint);
  }

  @Override public boolean onTouch(View v, MotionEvent event) {
    float evx = event.getX(), evy = event.getY();
    float deltaX = evx - centerX, deltaY = evy - centerY;
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
        //圆外按压不生效
        if (deltaX * deltaX + deltaY * deltaY > radius * radius) {
          break;
        }
      case MotionEvent.ACTION_MOVE:
        //如果触摸点在圆外
        if (Math.abs(deltaX) > radiusBorder || Math.abs(deltaY) > radiusBorder) {
          float distance = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
          changeFingerPosition(centerX + (deltaX * radiusBorder / distance),
              centerY + (deltaY * radiusBorder / distance));
        } else { //如果触摸点在圆内
          changeFingerPosition(evx, evy);
        }
        positionAnimator.cancel();
        break;
      case MotionEvent.ACTION_UP:
        positionAnimator.setDuration(1000);
        positionAnimator.start();
        break;
    }
    return true;
  }

  
  private void changeFingerPosition(float fingerX, float fingerY) {
    this.fingerX = fingerX;
    this.fingerY = fingerY;
    if (moveListener != null) {
      float r = radius - innerRadius;
      if (r == 0) {
        invalidate();
        return;
      }
      moveListener.move((fingerX - centerX) / r, (fingerY - centerY) / r);
    }
    invalidate();
  }

  @Override protected void finalize() throws Throwable {
    super.finalize();
    positionAnimator.removeAllListeners();
  }

  public void setMoveListener(
      MoveListener moveListener) {
    this.moveListener = moveListener;
  }

  
  public interface MoveListener {
    void move(float dx, float dy);
  }
}

style.xml


<declare-styleable name="ControllerView">
  <attr name="fingerColor" format="color" />
  <attr name="borderColor" format="color" />
  <attr name="fingerSize" format="dimension" />
  <attr name="radius" format="dimension" />
</declare-styleable>

写在最后:

这个是一个智能小车的安卓控制端的一部分demo,到此这篇关于如何在android中制作一个方向轮盘的文章就介绍到这了,更多相关android制作方向轮盘内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯