【问题标题】:Android contains method on arcs not working properlyAndroid包含弧上的方法无法正常工作
【发布时间】:2016-02-15 16:49:47
【问题描述】:

我有自定义视图控件,如下所示:

在我的活动中,我希望能够通过在绿色弧上拖动这个视图来在屏幕上移动它(左或右无关紧要)。

还希望能够检测是否点击了顶部的黄色弧线、中间的圆弧或底部的弧线。

我无法检测水龙头在哪个区域。这是我在活动中使用的代码:

float dX, dY;
final MyCustomView myCustomView = (MyCustomView)findViewById(R.id.test);
final Boolean[] movable = {false};

myCustomView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {

                switch (event.getActionMasked()) {

                    case MotionEvent.ACTION_DOWN:
                        movable[0] = false;

                        dX = view.getX() - event.getRawX();
                        dY = view.getY() - event.getRawY();

                        int x = (int) event.getX();
                        int y = (int) event.getY();

                        if (myCustomView.leftArcRegion.contains(x,y) || myCustomView.rightArcRegion.contains(x,y)){
                            movable[0] = true;
                        } else if (myCustomView.topArcRegion.contains(x,y)){
                            //todo: do something if top arc area is selected
                        } else if (myCustomView.midRoundedBitmapRegion.contains(x,y)){
                            //todo: do something if mid bitmap area is selected
                        } else if (myCustomView.bottomArcRegion.contains(x,y)){
                            //todo: do something if bottom arc area is selected
                        }
                    break;

                    case MotionEvent.ACTION_MOVE:
                        if (movable[0]) {
                            view.animate()
                                    .x(event.getRawX() + dX)
                                    .y(event.getRawY() + dY)
                                    .setDuration(0)
                                    .start();
                        }
                        break;

                    case MotionEvent.ACTION_UP:
                    case MotionEvent.ACTION_CANCEL:


                        break;
                    default:
                        return false;
                }
                return true;
            }
        });

这些是我的自定义视图控件中的公共字段:

public Region topArcRegion;
private Path topArc;

//topArc is my top arc path
RectF rectFTop = new RectF();
topArc.computeBounds(rectFTop, true);
topArcRegion = new Region();
topArcRegion.setPath(topArc, new Region((int) rectFTop.left, (int) rectFTop.top, 
   (int) rectFTop.right, (int) rectFTop.bottom));

但在使用此“包含”方法检查时,这些区域似乎使用矩形,而不是弧形。因此,我没有得到预期的结果。

那么,为了应用我的应用程序逻辑,我如何检测初始点击(顶部弧、底部弧、侧弧或中间位图)的位置?

【问题讨论】:

    标签: java android android-layout android-graphics


    【解决方案1】:

    由于您只希望检测弧段内的触摸,因此它不应该太复杂。

    每个弧段都定义为两个同心圆之间以及起点和终点角度之间的空间。所以你真正想做的就是做一个小三角来确定从圆心到你的接触点的距离以及从圆心到你的接触点的角度。

    float x = touchevent.getX();
    float y = touchevent.getY();
    
    // Transform relative to arc centers
    x -= circle1.x;
    y -= circle1.y;
    
    double dist = Math.sqrt(x*x + y*y);
    double angle = Math.atan2(y,x) * 180 / Math.PI;
    
    // Given an arc segment defined by circle1, circle2, angle1, angle2:
    boolean touch = dist > circle1.radius && dist < circle2.radius &&
                    angle > angle1 && angle < angle2;
    

    您可能需要根据角度 1 > 角度 2 或反之亦然进行一些调整。如果有任何角度有可能与零度角相交,那就有点棘手了。


    Meta:为清楚起见,我使用sqrt() 来计算距离,但您可以通过跳过sqrt() 并比较距离² 来优化此代码:

    double dist2 = x*x + y*y;
    if (dist2 > circle1.radius * circle1.radius &&
        dist2 < circle2.radius * circle2.radius &&
        ...
    

    另一个编辑:计算三角函数可能很昂贵;肯定比计算距离贵得多²。

    为了优化,您应该在使用三角函数之前检查圆半径的距离:

    boolean touch = dist > circle1.radius && dist < circle2.radius;
    if (touch) {
        // This is only a *possible* touch, check the angles now
        double angle = Math.atan2(y,x) * 180 / Math.PI;
        touch = angle > angle1 && angle < angle2;
    }
    

    【讨论】:

    • 像魅力一样工作! :) 谢谢!
    猜你喜欢
    • 1970-01-01
    • 2019-04-01
    • 2016-10-03
    • 2017-06-12
    • 2019-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多