如何在它上绑定点集(自定义形状)和触摸事件

时间:2012-01-02 10:29:47

标签: android canvas bitmap

我可以使用this link 获取我的位图点集(作为数组) 现在我的问题是如何将这些点绑定为形状/区域。意味着当用户触摸我的有界点的区域时,我想根据它移动对象(形状)。上面的彩色位图的链接返回点(它删除透明部分),只有彩色的部分点作为数组返回。 这就是我的代码:

1)CustomSahpe.java

public class CustomShape {
private final Context context;

Bitmap bitmap;
int width, height;
int[] pixels;
private final ArrayList<Point> points = new ArrayList<Point>();
public CustomShape(Context context) {
    // TODO Auto-generated constructor stub
    // super(context);
    this.context = context;
    bitmap = BitmapFactory.decodeResource(context.getResources(),
            R.drawable.ic_menu_balloon);
    width = bitmap.getWidth();
    height = bitmap.getHeight();
    pixels = new int[width * height];
    bitmap.getPixels(pixels, 0, width, 0, 0, width, height);        
    getActualBitmap();
}

public ArrayList<Point> getPoints(){
    return points;
}

public void getActualBitmap() {
    for (int x = 0; x < width; x+=2) {
        int firstY = -1, lastY = -1;
        for (int y = 0; y < height; y+=2) {
            boolean transparent = (pixels[y * width + x] == Color.TRANSPARENT);
            if (!transparent) {
                if (firstY == -1) {
                    firstY = y;
                }
                lastY = y;
            }
        }
        if (firstY != -1) {
            points.add(new Point(x, firstY));
            points.add(new Point(x, lastY));
        }
    }
}

}

2)MyShapre.java

class MyShape{
    CustomShape customShape ;
    Point points[];
    private int x, y;
    Path path = new Path();
    public MyShape(Context context) {           
        customShape = new CustomShape(ScaleTestActivity.this);
        points = new Point[customShape.getPoints().size()];
        for(int i=0;i<customShape.getPoints().size();i++){
            points[i] = new Point();
            points[i] = customShape.getPoints().get(i); 
        }
    }
    public Path getPath(){
        return path;
    }

    public void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        for(int i =0 ;i<points.length;i++){             
            Point point = new Point(points[i].x + getX(), points[i].y + getY());
            path.lineTo(points[i].x, points[i].y);
            canvas.drawPoint(point.x,point.y,paint);
        }
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getX() {
        return x;
    }
    public void setY(int y) {
        this.y = y;
    }
    public int getY() {
        return y;
    }       
}

}

3)MainPanel.java

    class MainPanel extends View{
        Context context;
        MyShape myShape;
        boolean flag = false;
        public MainPanel(Context context) {         
            super(context);
            this.context = context;
            myShape = new MyShape(context);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawColor(Color.RED);
            myShape.onDraw(canvas);
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            // TODO Auto-generated method stub          
            int x,y;
            x = (int)event.getX();
            y = (int)event.getY();
            Point point = new Point(x, y);

            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                myShape.setX(x);
                myShape.setY(y);
                RectF rectF = new RectF();
                Path path = myShape.getPath();
                path.computeBounds(rectF, true);
                Region region = new Region();

                region.setPath(path, new Region((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom));

                if(region.contains(x,y)){
                    flag = true;
                    Log.i("System out","onDown");
                }
                break;
            case MotionEvent.ACTION_MOVE:               
                Log.i("System out","onMove : "+flag);
                if(flag){
                    myShape.setX(x);
                    myShape.setY(y);
                    Log.i("System out","onMove");
                }
                break;
            case MotionEvent.ACTION_UP:
//              myShape.setX(x);
//              myShape.setY(y);
                flag = false;
                Log.i("System out","onUp");
                break;
            default:
                break;
            }
            invalidate();
            return true;
        }
    }

4)ScaleTestActivity.java

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);      
    setContentView(new MainPanel(this));
}

3 个答案:

答案 0 :(得分:5)

我使用Polygon类来检测旋转位图上的触摸。它主要基于此网站http://alienryderflex.com/polygon/的信息和代码。这应该适用于您的代码。

public class Polygon {

// Polygon coodinates.
private final int[] polyY, polyX;

// Number of sides in the polygon.
private final int polySides;

/**
 * Default constructor.
 * @param px Polygon y coods.
 * @param py Polygon x coods.
 * @param ps Polygon sides count.
 */
public Polygon( final int[] px, final int[] py, final int ps ) {
    polyX = px;
    polyY = py;
    polySides = ps;
}

/**
 * Checks if the Polygon contains a point.
 * @see "http://alienryderflex.com/polygon/"
 * @param x Point horizontal pos.
 * @param y Point vertical pos.
 * @return Point is in Poly flag.
 */
public boolean contains( final float x, final float y ) {

    boolean oddTransitions = false;
    for( int i = 0, j = polySides -1; i < polySides; j = i++ ) {
        if( ( polyY[ i ] < y && polyY[ j ] >= y ) || ( polyY[ j ] < y && polyY[ i ] >= y ) ) {
            if( polyX[ i ] + ( y - polyY[ i ] ) / ( polyY[ j ] - polyY[ i ] ) * ( polyX[ j ] - polyX[ i ] ) < x ) {
                oddTransitions = !oddTransitions;          
            }
        }
    }
    return oddTransitions;
}


}

您可以添加此构造函数以帮助您将Point数组转换为Polygon对象。

public Polygon(Point[] points){
    polySides = points.length;
    polyY = new int[polySides];
    polyX = new int[polySides];

    for(int i = 0; i < polySides; i++){
        polyY[i] = points[i].y;
        polyX[i] = points[i].x;
    }
}

您可以使用此方法在MyShape类中使用它。

 public boolean isTouched(final float X, final float Y){
   final Polygon p = new Polygon(points);
      return p.contains(X, Y);
}

现在,如果你有一个奇怪的形状,你应该能够准确地检测到它是否触及它。我多次使用过这种方法。

答案 1 :(得分:2)

您是否正在寻找一种方法来判断触摸事件是否落在您绘制的位图的非透明部分?如果是这样,为什么不将触摸坐标映射到位图上的正确像素并测试颜色?

如果是这种情况,那么你可以跳过所有的路径剪辑内容,因为你发布的链接只是为了克服模拟器的低效率。

答案 2 :(得分:1)

这有点复杂,所以我不打算提供完整的资料,但我会给你一个想法。

您需要将形状转移到三角形集合中,然后在触摸时找到形状的最近点并检查您是否在此点三角形内。

对于搜索和排序点,您可以使用red-black-red tree结构。

搜索算法最终应该在O(log(N))并且创建形状结构应该是O(N * Log(N))