自定义方向盘控件,有个BUG,大佬们能否帮忙看下

自渡96 2020-08-31 09:13:59
我使用了这个帖子的自定义方向盘
https://www.cnblogs.com/zhujiabin/p/10076828.html
然后可以正常使用,只是移动到最左(右/上/下)边的时候,紫色图(circle1)会显示不全。被切割掉一部分,该怎么处理呢?
如图
...全文
1840 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
自渡96 2020-09-02
  • 打赏
  • 举报
回复
引用 8 楼 自渡96 的回复:
[quote=引用 7 楼 消逝de年华 的回复:][quote=引用 6 楼 自渡96 的回复:][quote=引用 4 楼 消逝de年华 的回复:]这个需要修改两个地方,一个绘制大小,还有一个是触摸的时候,首先开始的是我用那个代码,绘制不出来中间的小圆,我将getWidth()直接换成了width,修改后的代码如下:
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED ? 100 : MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED ? 100 : MeasureSpec.getSize(heightMeasureSpec);
        if (width > height) {
            width = height;
        } else {
            height = width;
        }
        this.mainRadius = (width - 100) / 2;
        this.secondRadius = mainRadius / 5 * 2;
        setMeasuredDimension(width, height);
        this.centerX = width / 2;
        this.centerY = height / 2;
        this.xPosition = centerX;
        this.yPosition = centerY;
       //用于记录实际真正的背景圆的半径,实际上就是 mDestRect.width()/2
        this.realRadius = width / 2 - secondRadius;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Bitmap bm;
        Paint BackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        BackgroundPaint.setFilterBitmap(true);
        BackgroundPaint.setDither(true);

        Paint circlePaint = new Paint();
        circlePaint.setColor(Color.parseColor("#d81e06"));
        circlePaint.setStyle(Paint.Style.FILL);
        if (!isClicked) {
            bm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.circle1)).getBitmap();
        } else {
            bm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.circle)).getBitmap();
        }
        Rect mSrcRect = new Rect(0, 0, bm.getWidth(), bm.getHeight());
        //View 总宽度   width
        //绘制需要总宽度 2*mainRadius+2*secondRadius
        //所以  绘制背景色的时候需要往内至少margin secondRadius宽度
        Rect mDestRect = new Rect(secondRadius, secondRadius, getWidth() - secondRadius, getHeight() - secondRadius);
        canvas.drawBitmap(bm, mSrcRect, mDestRect, BackgroundPaint);
        canvas.drawCircle(this.xPosition, this.yPosition, secondRadius, circlePaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        isClicked = true;
        this.xPosition = (int) event.getX();
        this.yPosition = (int) event.getY();
        double cR = Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
        Log.e("onTouchEvent", "realRadius=" + realRadius + "\nmainRadius=" + mainRadius);
        if (cR > realRadius) {
//            double Yrate = (this.yPosition - this.centerY) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            double Xrate = (this.xPosition - this.centerX) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            this.yPosition = (int) (mainRadius * Yrate) + this.centerY;
//            this.xPosition = (int) (mainRadius * Xrate) + this.centerX;
            this.xPosition = (int) ((xPosition - centerX) * realRadius / cR) + this.centerX;
            this.yPosition = (int) ((yPosition - centerY) * realRadius / cR) + this.centerY;
        }
        if (this.myWheelMoveListener != null) {
            this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition);
        }
        invalidate();

        if (event.getAction() == 1) {
            isClicked = false;
            this.yPosition = this.centerY;
            this.xPosition = this.centerX;
            if (this.myWheelMoveListener != null) {
                this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition);
            }
            invalidate();
        }
        return true;
    }
onTouchEvent里面计算方法都一样的,关键是要判断的是否超过了realRadius,以及用realRadius换算,按博主的算法将mainRadius换成realRadius应该也是可以的。 你可以将代码复制进去运行下,不知道是不是你要的效果
能再问个问题吗? 我想计算那个紫色的球的圆心的旋转角度(范围0-360) 像这样子b点可以在圆上任意位置 [/quote] 我一般没怎么看论坛,这个其实就是一个数学问题,如果是求手指所在的点与ay直线的夹角的话,设圆的半径为r,那么用向量来求吧,向量ay=(0,-r),向量ab=(xp-cx,xy-cy),然后求这两个向量的夹角,具体怎么求可以百度下,这个我直接贴上我写的测试代码吧,实际情况是X1为0是可以去掉,这里为了方便阅读写上过程

   @Override
    public boolean onTouchEvent(MotionEvent event) {
        isClicked = true;
        this.xPosition = (int) event.getX();
        this.yPosition = (int) event.getY();
        double cR = Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
        Log.e("onTouchEvent", "realRadius=" + realRadius + "\nmainRadius=" + mainRadius);
        if (cR > realRadius) {
//            double Yrate = (this.yPosition - this.centerY) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            double Xrate = (this.xPosition - this.centerX) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            this.yPosition = (int) (mainRadius * Yrate) + this.centerY;
//            this.xPosition = (int) (mainRadius * Xrate) + this.centerX;
            this.xPosition = (int) ((xPosition - centerX) * realRadius / cR) + this.centerX;
            this.yPosition = (int) ((yPosition - centerY) * realRadius / cR) + this.centerY;
        }

        // 向量1的坐标:(x1,y1),向量2的坐标:(x2,y2); 则
        double x1=0;
        double y1=-realRadius;
        double x2=xPosition-centerX;
        double y2=yPosition-centerY;
        double value = (x1 * x2 + y1 * y2) / (Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2)); // 余弦值
        double angle = Math.toDegrees(Math.acos(value));   // 角度
        //上面ange算的是夹角,所以是不会超过180度的,实际情况要区分处理下
        if(x2<0){
            angle=360-angle;
        }

        if (this.myWheelMoveListener != null) {
            this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition,angle);
        }
        invalidate();

        if (event.getAction() == 1) {
            isClicked = false;
            this.yPosition = this.centerY;
            this.xPosition = this.centerX;
            if (this.myWheelMoveListener != null) {
                this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition,angle);
            }
            invalidate();
        }
        return true;
    }
[/quote] 可以用,太感谢了,能最后再问一个问题吗? 我在这把原来的画出来的紫色的圆想改成图片,我这么写了,部分机型没问题,部分机型有些偏差(紫色的圆的中心点和外面那个圆的中心点不重合),我不知道是为什么

Rect mSrcRect = new Rect(0, 0, bm.getWidth(), bm.getHeight());
        //View 总宽度   width
        //绘制需要总宽度 2*mainRadius+2*secondRadius
        //所以  绘制背景色的时候需要往内至少margin secondRadius宽度
        Rect mDestRect = new Rect(secondRadius, secondRadius, getWidth()- secondRadius, getHeight()- secondRadius);
        canvas.drawBitmap(bm, mSrcRect, mDestRect, BackgroundPaint);
        bm = ((BitmapDrawable) getResources().getDrawable(R.drawable.joy_stick_handle)).getBitmap();
        canvas.drawBitmap(bm, this.xPosition - secondRadius/2, this.yPosition - secondRadius/2, null);
[/quote] 而且这么写用来替换的图太小了,这个图的半径应该要是secondRadius,不知道该怎么设置,drawBitmap这个方式实在没看懂
自渡96 2020-09-02
  • 打赏
  • 举报
回复
引用 7 楼 消逝de年华 的回复:
[quote=引用 6 楼 自渡96 的回复:][quote=引用 4 楼 消逝de年华 的回复:]这个需要修改两个地方,一个绘制大小,还有一个是触摸的时候,首先开始的是我用那个代码,绘制不出来中间的小圆,我将getWidth()直接换成了width,修改后的代码如下:
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED ? 100 : MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED ? 100 : MeasureSpec.getSize(heightMeasureSpec);
        if (width > height) {
            width = height;
        } else {
            height = width;
        }
        this.mainRadius = (width - 100) / 2;
        this.secondRadius = mainRadius / 5 * 2;
        setMeasuredDimension(width, height);
        this.centerX = width / 2;
        this.centerY = height / 2;
        this.xPosition = centerX;
        this.yPosition = centerY;
       //用于记录实际真正的背景圆的半径,实际上就是 mDestRect.width()/2
        this.realRadius = width / 2 - secondRadius;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Bitmap bm;
        Paint BackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        BackgroundPaint.setFilterBitmap(true);
        BackgroundPaint.setDither(true);

        Paint circlePaint = new Paint();
        circlePaint.setColor(Color.parseColor("#d81e06"));
        circlePaint.setStyle(Paint.Style.FILL);
        if (!isClicked) {
            bm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.circle1)).getBitmap();
        } else {
            bm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.circle)).getBitmap();
        }
        Rect mSrcRect = new Rect(0, 0, bm.getWidth(), bm.getHeight());
        //View 总宽度   width
        //绘制需要总宽度 2*mainRadius+2*secondRadius
        //所以  绘制背景色的时候需要往内至少margin secondRadius宽度
        Rect mDestRect = new Rect(secondRadius, secondRadius, getWidth() - secondRadius, getHeight() - secondRadius);
        canvas.drawBitmap(bm, mSrcRect, mDestRect, BackgroundPaint);
        canvas.drawCircle(this.xPosition, this.yPosition, secondRadius, circlePaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        isClicked = true;
        this.xPosition = (int) event.getX();
        this.yPosition = (int) event.getY();
        double cR = Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
        Log.e("onTouchEvent", "realRadius=" + realRadius + "\nmainRadius=" + mainRadius);
        if (cR > realRadius) {
//            double Yrate = (this.yPosition - this.centerY) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            double Xrate = (this.xPosition - this.centerX) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            this.yPosition = (int) (mainRadius * Yrate) + this.centerY;
//            this.xPosition = (int) (mainRadius * Xrate) + this.centerX;
            this.xPosition = (int) ((xPosition - centerX) * realRadius / cR) + this.centerX;
            this.yPosition = (int) ((yPosition - centerY) * realRadius / cR) + this.centerY;
        }
        if (this.myWheelMoveListener != null) {
            this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition);
        }
        invalidate();

        if (event.getAction() == 1) {
            isClicked = false;
            this.yPosition = this.centerY;
            this.xPosition = this.centerX;
            if (this.myWheelMoveListener != null) {
                this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition);
            }
            invalidate();
        }
        return true;
    }
onTouchEvent里面计算方法都一样的,关键是要判断的是否超过了realRadius,以及用realRadius换算,按博主的算法将mainRadius换成realRadius应该也是可以的。 你可以将代码复制进去运行下,不知道是不是你要的效果
能再问个问题吗? 我想计算那个紫色的球的圆心的旋转角度(范围0-360) 像这样子b点可以在圆上任意位置 [/quote] 我一般没怎么看论坛,这个其实就是一个数学问题,如果是求手指所在的点与ay直线的夹角的话,设圆的半径为r,那么用向量来求吧,向量ay=(0,-r),向量ab=(xp-cx,xy-cy),然后求这两个向量的夹角,具体怎么求可以百度下,这个我直接贴上我写的测试代码吧,实际情况是X1为0是可以去掉,这里为了方便阅读写上过程

   @Override
    public boolean onTouchEvent(MotionEvent event) {
        isClicked = true;
        this.xPosition = (int) event.getX();
        this.yPosition = (int) event.getY();
        double cR = Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
        Log.e("onTouchEvent", "realRadius=" + realRadius + "\nmainRadius=" + mainRadius);
        if (cR > realRadius) {
//            double Yrate = (this.yPosition - this.centerY) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            double Xrate = (this.xPosition - this.centerX) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            this.yPosition = (int) (mainRadius * Yrate) + this.centerY;
//            this.xPosition = (int) (mainRadius * Xrate) + this.centerX;
            this.xPosition = (int) ((xPosition - centerX) * realRadius / cR) + this.centerX;
            this.yPosition = (int) ((yPosition - centerY) * realRadius / cR) + this.centerY;
        }

        // 向量1的坐标:(x1,y1),向量2的坐标:(x2,y2); 则
        double x1=0;
        double y1=-realRadius;
        double x2=xPosition-centerX;
        double y2=yPosition-centerY;
        double value = (x1 * x2 + y1 * y2) / (Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2)); // 余弦值
        double angle = Math.toDegrees(Math.acos(value));   // 角度
        //上面ange算的是夹角,所以是不会超过180度的,实际情况要区分处理下
        if(x2<0){
            angle=360-angle;
        }

        if (this.myWheelMoveListener != null) {
            this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition,angle);
        }
        invalidate();

        if (event.getAction() == 1) {
            isClicked = false;
            this.yPosition = this.centerY;
            this.xPosition = this.centerX;
            if (this.myWheelMoveListener != null) {
                this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition,angle);
            }
            invalidate();
        }
        return true;
    }
[/quote] 可以用,太感谢了,能最后再问一个问题吗? 我在这把原来的画出来的紫色的圆想改成图片,我这么写了,部分机型没问题,部分机型有些偏差(紫色的圆的中心点和外面那个圆的中心点不重合),我不知道是为什么

Rect mSrcRect = new Rect(0, 0, bm.getWidth(), bm.getHeight());
        //View 总宽度   width
        //绘制需要总宽度 2*mainRadius+2*secondRadius
        //所以  绘制背景色的时候需要往内至少margin secondRadius宽度
        Rect mDestRect = new Rect(secondRadius, secondRadius, getWidth()- secondRadius, getHeight()- secondRadius);
        canvas.drawBitmap(bm, mSrcRect, mDestRect, BackgroundPaint);
        bm = ((BitmapDrawable) getResources().getDrawable(R.drawable.joy_stick_handle)).getBitmap();
        canvas.drawBitmap(bm, this.xPosition - secondRadius/2, this.yPosition - secondRadius/2, null);
消逝de年华 2020-09-02
  • 打赏
  • 举报
回复
另外建议不要在onDraw里面初始化new对象,因为onDraw调用的很频繁,建议使用全局变量,在onDraw里面更新对应的值
消逝de年华 2020-09-02
  • 打赏
  • 举报
回复
不是很理解你说的问题,首先用来替换的图片小的问题,在替换之前,自己手动绘制的那个圆的小了吗,如果没有的话,你可以按照绘制圆的参数去设置绘制图片参数,采用博主demo中绘制图片的方法转换。
 canvas.drawCircle(this.xPosition, this.yPosition, secondRadius, circlePaint);
这个是他之前绘制圆的情况,不知道在这种情况有没有出现圆小了和这个圆的中心没有与背景圆的中心重合的问题,如果没有的话,那么继续下面的。 将上面的圆替换成你需要的图片

         Bitmap yourBm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.test)).getBitmap();
        Rect secondRect= new Rect(this.xPosition-secondRadius,this.yPosition-secondRadius,this.xPosition+secondRadius,this.yPosition+secondRadius);
        canvas.drawBitmap(yourBm, null,secondRect,circlePaint);

如果是在demo的圆的那个地方就有问题了,那就要具体在看了,后面有问题的话你加我qq或者微信吧,631298455
自渡96 2020-09-01
  • 打赏
  • 举报
回复
引用 4 楼 消逝de年华 的回复:
这个需要修改两个地方,一个绘制大小,还有一个是触摸的时候,首先开始的是我用那个代码,绘制不出来中间的小圆,我将getWidth()直接换成了width,修改后的代码如下:
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED ? 100 : MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED ? 100 : MeasureSpec.getSize(heightMeasureSpec);
        if (width > height) {
            width = height;
        } else {
            height = width;
        }
        this.mainRadius = (width - 100) / 2;
        this.secondRadius = mainRadius / 5 * 2;
        setMeasuredDimension(width, height);
        this.centerX = width / 2;
        this.centerY = height / 2;
        this.xPosition = centerX;
        this.yPosition = centerY;
       //用于记录实际真正的背景圆的半径,实际上就是 mDestRect.width()/2
        this.realRadius = width / 2 - secondRadius;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Bitmap bm;
        Paint BackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        BackgroundPaint.setFilterBitmap(true);
        BackgroundPaint.setDither(true);

        Paint circlePaint = new Paint();
        circlePaint.setColor(Color.parseColor("#d81e06"));
        circlePaint.setStyle(Paint.Style.FILL);
        if (!isClicked) {
            bm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.circle1)).getBitmap();
        } else {
            bm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.circle)).getBitmap();
        }
        Rect mSrcRect = new Rect(0, 0, bm.getWidth(), bm.getHeight());
        //View 总宽度   width
        //绘制需要总宽度 2*mainRadius+2*secondRadius
        //所以  绘制背景色的时候需要往内至少margin secondRadius宽度
        Rect mDestRect = new Rect(secondRadius, secondRadius, getWidth() - secondRadius, getHeight() - secondRadius);
        canvas.drawBitmap(bm, mSrcRect, mDestRect, BackgroundPaint);
        canvas.drawCircle(this.xPosition, this.yPosition, secondRadius, circlePaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        isClicked = true;
        this.xPosition = (int) event.getX();
        this.yPosition = (int) event.getY();
        double cR = Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
        Log.e("onTouchEvent", "realRadius=" + realRadius + "\nmainRadius=" + mainRadius);
        if (cR > realRadius) {
//            double Yrate = (this.yPosition - this.centerY) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            double Xrate = (this.xPosition - this.centerX) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            this.yPosition = (int) (mainRadius * Yrate) + this.centerY;
//            this.xPosition = (int) (mainRadius * Xrate) + this.centerX;
            this.xPosition = (int) ((xPosition - centerX) * realRadius / cR) + this.centerX;
            this.yPosition = (int) ((yPosition - centerY) * realRadius / cR) + this.centerY;
        }
        if (this.myWheelMoveListener != null) {
            this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition);
        }
        invalidate();

        if (event.getAction() == 1) {
            isClicked = false;
            this.yPosition = this.centerY;
            this.xPosition = this.centerX;
            if (this.myWheelMoveListener != null) {
                this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition);
            }
            invalidate();
        }
        return true;
    }
onTouchEvent里面计算方法都一样的,关键是要判断的是否超过了realRadius,以及用realRadius换算,按博主的算法将mainRadius换成realRadius应该也是可以的。 你可以将代码复制进去运行下,不知道是不是你要的效果
能再问个问题吗? 我想计算那个紫色的球的圆心的旋转角度(范围0-360) 像这样子b点可以在圆上任意位置
消逝de年华 2020-09-01
  • 打赏
  • 举报
回复
引用 6 楼 自渡96 的回复:
[quote=引用 4 楼 消逝de年华 的回复:]这个需要修改两个地方,一个绘制大小,还有一个是触摸的时候,首先开始的是我用那个代码,绘制不出来中间的小圆,我将getWidth()直接换成了width,修改后的代码如下:
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED ? 100 : MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED ? 100 : MeasureSpec.getSize(heightMeasureSpec);
        if (width > height) {
            width = height;
        } else {
            height = width;
        }
        this.mainRadius = (width - 100) / 2;
        this.secondRadius = mainRadius / 5 * 2;
        setMeasuredDimension(width, height);
        this.centerX = width / 2;
        this.centerY = height / 2;
        this.xPosition = centerX;
        this.yPosition = centerY;
       //用于记录实际真正的背景圆的半径,实际上就是 mDestRect.width()/2
        this.realRadius = width / 2 - secondRadius;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Bitmap bm;
        Paint BackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        BackgroundPaint.setFilterBitmap(true);
        BackgroundPaint.setDither(true);

        Paint circlePaint = new Paint();
        circlePaint.setColor(Color.parseColor("#d81e06"));
        circlePaint.setStyle(Paint.Style.FILL);
        if (!isClicked) {
            bm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.circle1)).getBitmap();
        } else {
            bm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.circle)).getBitmap();
        }
        Rect mSrcRect = new Rect(0, 0, bm.getWidth(), bm.getHeight());
        //View 总宽度   width
        //绘制需要总宽度 2*mainRadius+2*secondRadius
        //所以  绘制背景色的时候需要往内至少margin secondRadius宽度
        Rect mDestRect = new Rect(secondRadius, secondRadius, getWidth() - secondRadius, getHeight() - secondRadius);
        canvas.drawBitmap(bm, mSrcRect, mDestRect, BackgroundPaint);
        canvas.drawCircle(this.xPosition, this.yPosition, secondRadius, circlePaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        isClicked = true;
        this.xPosition = (int) event.getX();
        this.yPosition = (int) event.getY();
        double cR = Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
        Log.e("onTouchEvent", "realRadius=" + realRadius + "\nmainRadius=" + mainRadius);
        if (cR > realRadius) {
//            double Yrate = (this.yPosition - this.centerY) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            double Xrate = (this.xPosition - this.centerX) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            this.yPosition = (int) (mainRadius * Yrate) + this.centerY;
//            this.xPosition = (int) (mainRadius * Xrate) + this.centerX;
            this.xPosition = (int) ((xPosition - centerX) * realRadius / cR) + this.centerX;
            this.yPosition = (int) ((yPosition - centerY) * realRadius / cR) + this.centerY;
        }
        if (this.myWheelMoveListener != null) {
            this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition);
        }
        invalidate();

        if (event.getAction() == 1) {
            isClicked = false;
            this.yPosition = this.centerY;
            this.xPosition = this.centerX;
            if (this.myWheelMoveListener != null) {
                this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition);
            }
            invalidate();
        }
        return true;
    }
onTouchEvent里面计算方法都一样的,关键是要判断的是否超过了realRadius,以及用realRadius换算,按博主的算法将mainRadius换成realRadius应该也是可以的。 你可以将代码复制进去运行下,不知道是不是你要的效果
能再问个问题吗? 我想计算那个紫色的球的圆心的旋转角度(范围0-360) 像这样子b点可以在圆上任意位置 [/quote] 我一般没怎么看论坛,这个其实就是一个数学问题,如果是求手指所在的点与ay直线的夹角的话,设圆的半径为r,那么用向量来求吧,向量ay=(0,-r),向量ab=(xp-cx,xy-cy),然后求这两个向量的夹角,具体怎么求可以百度下,这个我直接贴上我写的测试代码吧,实际情况是X1为0是可以去掉,这里为了方便阅读写上过程

   @Override
    public boolean onTouchEvent(MotionEvent event) {
        isClicked = true;
        this.xPosition = (int) event.getX();
        this.yPosition = (int) event.getY();
        double cR = Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
        Log.e("onTouchEvent", "realRadius=" + realRadius + "\nmainRadius=" + mainRadius);
        if (cR > realRadius) {
//            double Yrate = (this.yPosition - this.centerY) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            double Xrate = (this.xPosition - this.centerX) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            this.yPosition = (int) (mainRadius * Yrate) + this.centerY;
//            this.xPosition = (int) (mainRadius * Xrate) + this.centerX;
            this.xPosition = (int) ((xPosition - centerX) * realRadius / cR) + this.centerX;
            this.yPosition = (int) ((yPosition - centerY) * realRadius / cR) + this.centerY;
        }

        // 向量1的坐标:(x1,y1),向量2的坐标:(x2,y2); 则
        double x1=0;
        double y1=-realRadius;
        double x2=xPosition-centerX;
        double y2=yPosition-centerY;
        double value = (x1 * x2 + y1 * y2) / (Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2)); // 余弦值
        double angle = Math.toDegrees(Math.acos(value));   // 角度
        //上面ange算的是夹角,所以是不会超过180度的,实际情况要区分处理下
        if(x2<0){
            angle=360-angle;
        }

        if (this.myWheelMoveListener != null) {
            this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition,angle);
        }
        invalidate();

        if (event.getAction() == 1) {
            isClicked = false;
            this.yPosition = this.centerY;
            this.xPosition = this.centerX;
            if (this.myWheelMoveListener != null) {
                this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition,angle);
            }
            invalidate();
        }
        return true;
    }
ink_s 2020-08-31
  • 打赏
  • 举报
回复
int width =MeasureSpec.getMode(widthMeasureSpec)==MeasureSpec.UNSPECIFIED?100:MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getMode(heightMeasureSpec)==MeasureSpec.UNSPECIFIED?100:MeasureSpec.getSize(heightMeasureSpec); if(width>height){//将自定义控件的区域限制为正方形 width=height; }else{ height=width; } 改成 if(width>height){//将自定义控件的区域限制为正方形 width=height; }else{ height=width; } width =width-50; height =height-50; 这样,50可以改成多少你自己算下
自渡96 2020-08-31
  • 打赏
  • 举报
回复
引用 4 楼 消逝de年华 的回复:
这个需要修改两个地方,一个绘制大小,还有一个是触摸的时候,首先开始的是我用那个代码,绘制不出来中间的小圆,我将getWidth()直接换成了width,修改后的代码如下:
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED ? 100 : MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED ? 100 : MeasureSpec.getSize(heightMeasureSpec);
        if (width > height) {
            width = height;
        } else {
            height = width;
        }
        this.mainRadius = (width - 100) / 2;
        this.secondRadius = mainRadius / 5 * 2;
        setMeasuredDimension(width, height);
        this.centerX = width / 2;
        this.centerY = height / 2;
        this.xPosition = centerX;
        this.yPosition = centerY;
       //用于记录实际真正的背景圆的半径,实际上就是 mDestRect.width()/2
        this.realRadius = width / 2 - secondRadius;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Bitmap bm;
        Paint BackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        BackgroundPaint.setFilterBitmap(true);
        BackgroundPaint.setDither(true);

        Paint circlePaint = new Paint();
        circlePaint.setColor(Color.parseColor("#d81e06"));
        circlePaint.setStyle(Paint.Style.FILL);
        if (!isClicked) {
            bm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.circle1)).getBitmap();
        } else {
            bm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.circle)).getBitmap();
        }
        Rect mSrcRect = new Rect(0, 0, bm.getWidth(), bm.getHeight());
        //View 总宽度   width
        //绘制需要总宽度 2*mainRadius+2*secondRadius
        //所以  绘制背景色的时候需要往内至少margin secondRadius宽度
        Rect mDestRect = new Rect(secondRadius, secondRadius, getWidth() - secondRadius, getHeight() - secondRadius);
        canvas.drawBitmap(bm, mSrcRect, mDestRect, BackgroundPaint);
        canvas.drawCircle(this.xPosition, this.yPosition, secondRadius, circlePaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        isClicked = true;
        this.xPosition = (int) event.getX();
        this.yPosition = (int) event.getY();
        double cR = Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
        Log.e("onTouchEvent", "realRadius=" + realRadius + "\nmainRadius=" + mainRadius);
        if (cR > realRadius) {
//            double Yrate = (this.yPosition - this.centerY) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            double Xrate = (this.xPosition - this.centerX) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            this.yPosition = (int) (mainRadius * Yrate) + this.centerY;
//            this.xPosition = (int) (mainRadius * Xrate) + this.centerX;
            this.xPosition = (int) ((xPosition - centerX) * realRadius / cR) + this.centerX;
            this.yPosition = (int) ((yPosition - centerY) * realRadius / cR) + this.centerY;
        }
        if (this.myWheelMoveListener != null) {
            this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition);
        }
        invalidate();

        if (event.getAction() == 1) {
            isClicked = false;
            this.yPosition = this.centerY;
            this.xPosition = this.centerX;
            if (this.myWheelMoveListener != null) {
                this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition);
            }
            invalidate();
        }
        return true;
    }
onTouchEvent里面计算方法都一样的,关键是要判断的是否超过了realRadius,以及用realRadius换算,按博主的算法将mainRadius换成realRadius应该也是可以的。 你可以将代码复制进去运行下,不知道是不是你要的效果
是的了,就是这样,谢谢
消逝de年华 2020-08-31
  • 打赏
  • 举报
回复
这个需要修改两个地方,一个绘制大小,还有一个是触摸的时候,首先开始的是我用那个代码,绘制不出来中间的小圆,我将getWidth()直接换成了width,修改后的代码如下:
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED ? 100 : MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED ? 100 : MeasureSpec.getSize(heightMeasureSpec);
        if (width > height) {
            width = height;
        } else {
            height = width;
        }
        this.mainRadius = (width - 100) / 2;
        this.secondRadius = mainRadius / 5 * 2;
        setMeasuredDimension(width, height);
        this.centerX = width / 2;
        this.centerY = height / 2;
        this.xPosition = centerX;
        this.yPosition = centerY;
       //用于记录实际真正的背景圆的半径,实际上就是 mDestRect.width()/2
        this.realRadius = width / 2 - secondRadius;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Bitmap bm;
        Paint BackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        BackgroundPaint.setFilterBitmap(true);
        BackgroundPaint.setDither(true);

        Paint circlePaint = new Paint();
        circlePaint.setColor(Color.parseColor("#d81e06"));
        circlePaint.setStyle(Paint.Style.FILL);
        if (!isClicked) {
            bm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.circle1)).getBitmap();
        } else {
            bm = ((BitmapDrawable) getResources().getDrawable(R.mipmap.circle)).getBitmap();
        }
        Rect mSrcRect = new Rect(0, 0, bm.getWidth(), bm.getHeight());
        //View 总宽度   width
        //绘制需要总宽度 2*mainRadius+2*secondRadius
        //所以  绘制背景色的时候需要往内至少margin secondRadius宽度
        Rect mDestRect = new Rect(secondRadius, secondRadius, getWidth() - secondRadius, getHeight() - secondRadius);
        canvas.drawBitmap(bm, mSrcRect, mDestRect, BackgroundPaint);
        canvas.drawCircle(this.xPosition, this.yPosition, secondRadius, circlePaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        isClicked = true;
        this.xPosition = (int) event.getX();
        this.yPosition = (int) event.getY();
        double cR = Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
        Log.e("onTouchEvent", "realRadius=" + realRadius + "\nmainRadius=" + mainRadius);
        if (cR > realRadius) {
//            double Yrate = (this.yPosition - this.centerY) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            double Xrate = (this.xPosition - this.centerX) / Math.sqrt((this.xPosition - this.centerX) * (this.xPosition - this.centerX) + (this.yPosition - this.centerY) * (this.yPosition - this.centerY));
//            this.yPosition = (int) (mainRadius * Yrate) + this.centerY;
//            this.xPosition = (int) (mainRadius * Xrate) + this.centerX;
            this.xPosition = (int) ((xPosition - centerX) * realRadius / cR) + this.centerX;
            this.yPosition = (int) ((yPosition - centerY) * realRadius / cR) + this.centerY;
        }
        if (this.myWheelMoveListener != null) {
            this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition);
        }
        invalidate();

        if (event.getAction() == 1) {
            isClicked = false;
            this.yPosition = this.centerY;
            this.xPosition = this.centerX;
            if (this.myWheelMoveListener != null) {
                this.myWheelMoveListener.onValueChanged(this.xPosition, this.yPosition);
            }
            invalidate();
        }
        return true;
    }
onTouchEvent里面计算方法都一样的,关键是要判断的是否超过了realRadius,以及用realRadius换算,按博主的算法将mainRadius换成realRadius应该也是可以的。 你可以将代码复制进去运行下,不知道是不是你要的效果
闫文敬 2020-08-31
  • 打赏
  • 举报
回复
滑动控件超过了父控件的位置,所以显示不全,调整父控件大小或者重新计算大小
自渡96 2020-08-31
  • 打赏
  • 举报
回复
引用 1 楼 ink_s 的回复:
int width =MeasureSpec.getMode(widthMeasureSpec)==MeasureSpec.UNSPECIFIED?100:MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getMode(heightMeasureSpec)==MeasureSpec.UNSPECIFIED?100:MeasureSpec.getSize(heightMeasureSpec); if(width>height){//将自定义控件的区域限制为正方形 width=height; }else{ height=width; } 改成 if(width>height){//将自定义控件的区域限制为正方形 width=height; }else{ height=width; } width =width-50; height =height-50; 这样,50可以改成多少你自己算下
好像不行,我改了很多值都不行,图形还变形了

80,471

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧