如何绑定点(自定义形状)和触摸事件Android[英] how to bound set of points (custom shape) and touch event on it android

本文是小编为大家收集整理的关于如何绑定点(自定义形状)和触摸事件Android的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我能够使用此链接 现在我的问题是如何将这些点绑定为形状/区域.意味着当用户触摸我的有限点的区域时,我想根据此移动对象(形状).上面的彩色位图的链接返回点(它删除了透明的零件),只有彩色零件点作为数组返回. 这就是我的代码:

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));
}

推荐答案

i使用多边形类检测旋转位图的触摸.它主要基于此站点的信息和代码 http://alienryryderflex.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;
}


}

您可以添加此构造函数以帮助您将点数组转换为多边形对象.

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);
}

现在,如果您的形状奇怪,则应该能够准确检测使用是否触及它.我已经多次使用过这种方法.

其他推荐答案

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

,如果是这样,那么您可以跳过所有路径剪辑内容,因为您发布的链接只是这样做是为了克服效率低下.

其他推荐答案

有点复杂,所以我不会提供完整的来源,但我会给您一个想法.

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

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

搜索算法最终应处于O(log(n)),创建形状结构应为O(n*log(n))

本文地址:https://www.itbaoku.cn/post/102652.html

问题描述

i am able to get my bitmap set of points (as an array) using this link now my question is how can i bound these points as shape/region. Means when user touched on area of my bounded points, i want to move objects(shape) according to that. Above link return points of colored bitmap (it remove transparent part), only colored part points are return as an array. This is what my code :

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));
}

推荐答案

I use a Polygon class to detect touches on rotated bitmaps. It's based mostly on information and code from this site http://alienryderflex.com/polygon/. This should work with your code.

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;
}


}

You could add this constructor to help you convert a Point array to a Polygon object.

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;
    }
}

You might be able to use it in your MyShape class with this method.

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

Now if you have an odd shape you should be able to detect exactly if the use touches it. I have used this method many times.

其他推荐答案

Are you looking for a way to tell whether a touch event falls on the non-transparent portion of your drawn bitmap? If so, why don't you just map the touch coordinate to the proper pixel on the bitmap and test the color?

And if that's the case, then you can skip all the path clipping stuff, since the link you posted was only doing that to overcome emulator inefficiencies.

其他推荐答案

It's a bit complicated so I am not going to provide the full source but I will give you an idea.

You need to transfer your shape in to a triangles collection, then on touch find the nearest point of your shape and check if your are inside this point triangle.

For searching and sorting points you can use red-black-red tree structure.

The search algorithm eventually should be at O(log(N)) and creating shape structure should be O(N*Log(N))