可以处理Android上不规则形状的事件吗?

时间:2011-04-09 20:41:38

标签: android events drawable shapes

据我所知(现在很少),Android中的所有视图都有方形或矩形形状。这几乎一直很好,直到你想要 - 我真正想要的 - 创建可以处理事件的非方形形状。

我的目标是将一个圆圈分成3个120°的部分。圆的每个部分应该像按钮一样。问题是,如果我们查看一个圆圈的3个并将它们放在一个严格包含它们的方框中,它们会相互重叠:不知道用户想要点击哪个...

我尝试使用自定义视图,其中我绘制了我的部分,但事件在视图的所有表面上都会触发。

非常欢迎任何建议或指示。

谢谢,保罗

3 个答案:

答案 0 :(得分:2)

我认为处理此问题的方法是覆盖每个控件上的onTouch,对触摸坐标执行自己的几何检查,如果它位于自定义区域return false之外,它将通过事件另一种观点。否则返回调用方法的超级版本。我不是百分百肯定所以有人请你纠正我,如果我错了,但值得一试。

答案 1 :(得分:2)

我不知道你是否可以明确地创建这些形状,但肯定会有一种方法在自定义视图中使用它。但这很难。

首先,您需要通过设置OnTouch,更多here来挂钩OnTouchListener事件。最简单的方法是仅对ACTION_UP的{​​{1}}操作做出反应,可通过MotionEvent访问here上的详细信息。在MotionEvent.getAction()中,您可以获得X和Y坐标,其中事件通过MotionEventgetX()发生。

现在开始数学...你现在必须计算点击发生的部分。要做到这一点,你需要自定义视图的大小(以像素为单位)及其位置(左上角),我恐怕现在无法告诉你相应的方法......你必须把它们挖出来......假设圆的中心始终位于视图的中心,圆圈完全延伸到视图边界,您现在可以计算扇区。

让我们分别调用事件X和Y坐标getY()eventX,让eventYcenterX成为圆心坐标以及centerY圆圈半径。

首先检查是否在圆圈中发生事件,然后计算角度:

radius

最后,int deltaX = eventX - centerX; int deltaY = eventY - centerY; if (Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)) > radius) { // out of circle! } // offset for radiant, depending on quadrant double offset = 0; if (deltaX > 0 && deltaY < 0) { // top right -> nothing to do } else if (deltaX > 0 && deltaY > 0) { // bottom right -> add 90 degrees offset = Math.PI/2; } else if (deltaX < 0 && deltaY > 0) { // bottom left -> add 180 degrees offset = Math.PI; } else if (deltaX < 0 && deltaY < 0) { // top left -> add 270 degrees offset = Math.PI * 3/2; } //now calculate angle double angle = Math.asin(deltaY / deltaX); double total = angle + offset; 应为顺时针角度,您可以根据您的部分检查辐射中的点击次数;)如果出现问题,请纠正我^^

答案 2 :(得分:2)

首先,非常感谢您提供的有助于我实现目标的所有建议。

由于无法在形状上触发事件,因此在包含形状的视图上使用onTouch()是可行的方法。

以下,您需要运行它。


首先,自定义视图Zones.java:

package com.vector;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

public class Zones extends View {
    RectF rectf = new RectF(0, 0, 300, 300);
    Paint paint = new Paint();
    Canvas canvas = null;
    Integer zone = 0;

    // important: do not forget to add AttributeSet, it is necessary to have this
    // view called from an xml view file
    public Zones(Context context, AttributeSet attributeset) {
        super(context, attributeset);
        this.setBackgroundColor(0xFF207CA1);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        // set layout of the view
        layout(0, 0, 300, 300);

        // expose canvas at view level
        this.canvas = canvas;

        // check for zone 1 to 3
        if(zone >= 1 && zone <= 3)
        {
            drawTouchZones(zone);
        }
    }

    protected void drawTouchZones(Integer zone)
    {
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(2);
        paint.setColor(Color.WHITE);
        paint.setAlpha(75);

        Path path = new Path();

        if(zone == 1) {
            path.moveTo(150,150);
            path.lineTo(150,0);
            path.arcTo(rectf, 270, 120);
            path.close();
        } else if(zone == 2) {
            path.moveTo(150,150);
            path.arcTo(rectf, 30, 120);
            path.lineTo(150,150);
            path.close();
        } else if(zone == 3) {
            path.moveTo(150,0);
            path.lineTo(150,150);
            path.arcTo(rectf, 150, 120);
            path.close();
        }

        canvas.drawPath(path, paint);       
    }
}

二,主要活动,Design.java:

package com.vector;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class Design extends Activity {
    /** Called when the activity is first created. */
    private Zones v;
    protected Integer zone = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {
            // get our custom view
            setContentView(R.layout.main);
            v = (Zones) findViewById(R.id.zone);

            // add onClick Listener
            v.setOnClickListener(new View.OnClickListener() {
                public void onClick(View view) {
                    Log.i("zone clicked", "" + zone);

                    // tell to our view which zone has been clicked
                    v.zone = zone;

                    // invalidate to call onDraw method of the custom view and draw the zone
                    v.invalidate();
                }
            });

            v.setOnTouchListener(new View.OnTouchListener() {

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    zone = getZone(event);
                    return false;
                }
            });
        }
        catch(Exception e)
        {
            Log.e("e", e.getMessage());
        }
    }

    // detect clicked zone through MotionEvent
    public int getZone(MotionEvent e)
    {
        Float x = e.getX();
        Float y = e.getY();

        // 0:00 to 4:00
        if((x > 150 && x < 300 && y < 150) ||
           (x > 150 && x < 300 && y > 150 && (x - 150) / (y - 150) > 1.5))
        {
            return 1;
        }
        // 4:00 to 8:00
        else if((x >= 150 && x < 300 & y > 150 && (x - 150) / (y - 150) < 1.5) ||
                (x > 0 && x < 150 && y > 150 && (150 - x) / (y - 150) < 1.5))
        {

            return 2;
        }
        // 8:00 to 0:00
        else
        {
            return 3;
        }       
    }
}

...和主xml视图(嵌入我们的自定义类视图)main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <com.vector.Zones android:id="@+id/zone" android:layout_height="wrap_content" android:layout_width="wrap_content">
    </com.vector.Zones>
</LinearLayout>

任何评论都表示赞赏! 保罗:)