如何获取imageview中触摸的位图像素的位置

时间:2013-07-16 11:21:20

标签: java android imageview ontouchlistener

有很多这样的问题。我已经完成了它们但却无法正常工作。

我的活动

public class MainActivity extends Activity {

private static final String    TAG = "GT:MA";
private ImageView imageView;
Bitmap original;

@Override
protected void onCreate(Bundle savedInstanceState) {
    Log.i(TAG, "in onCreate method");
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    imageView = (ImageView) this.findViewById(R.id.image);

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inScaled = false;
    int resId = getResources().getIdentifier("beerl", "drawable", "com.sivaprasadvarma.grabtouch");
    original = BitmapFactory.decodeResource(getResources(), resId, options);
    Log.i(TAG, "original size after decoding: "
            + String.valueOf(original.getWidth()) + " / "
            + String.valueOf(original.getHeight()));

    imageView.setImageBitmap(original);
    imageView.setOnTouchListener(myOnTouchSelectingListener);
}


// I've implemented diff methods in answers here
// http://stackoverflow.com/questions/4933612/how-to-convert-coordinates-of-the-image-view-to-the-coordinates-of-the-bitmap
OnTouchListener myOnTouchSelectingListener = 
        new OnTouchListener() {

            @Override
            public boolean onTouch(View view, MotionEvent event) {
                    Log.i(TAG, "---------------------");                    

                    // 1st method
                    float eventX = event.getX();
                    float eventY = event.getY();
                    float[] eventXY = new float[] {eventX, eventY};

                    Log.i(TAG, "1: touched position: "  + String.valueOf(eventX) + " / " 
                            + String.valueOf(eventY));


                    //2nd method
                    Matrix invertMatrix = new Matrix();
                    ((ImageView)view).getImageMatrix().invert(invertMatrix);
                    invertMatrix.mapPoints(eventXY);
                    int x = Integer.valueOf((int)eventXY[0]);
                    int y = Integer.valueOf((int)eventXY[1]);

                    Log.i(TAG,  "2: Inverted touch position by invMatrix: "
                            + String.valueOf(x) + " / " 
                            + String.valueOf(y));



                    Drawable imgDrawable = ((ImageView)view).getDrawable();
                    Bitmap bitmap = ((BitmapDrawable)imgDrawable).getBitmap();                      
                    // make sure they are of same size
                    Log.i(TAG, "from getter drawable size: "
                            + String.valueOf(bitmap.getWidth()) + " / " 
                            + String.valueOf(bitmap.getHeight()));                      
                    Log.i(TAG, "actual drawable size: "
                            + String.valueOf(original.getWidth()) + " / "
                            + String.valueOf(original.getHeight()));

                    //Limit x, y range within bitmap
                    if(x < 0){
                        x = 0;
                    }else if(x > bitmap.getWidth()-1){
                        x = bitmap.getWidth()-1;
                    }
                    if(y < 0){
                        y = 0;
                    }else if(y > bitmap.getHeight()-1){
                        y = bitmap.getHeight()-1;
                    }

                    // mapping them back to bitmap coordinates
                    Rect imageBounds = imgDrawable.getBounds();

                    //original height and width of the bitmap
                    int intrinsicHeight = imgDrawable.getIntrinsicHeight();
                    int intrinsicWidth = imgDrawable.getIntrinsicWidth();
                    Log.i(TAG, "intrinsic width / height: "
                            + String.valueOf(intrinsicWidth) + " / "
                            + String.valueOf(intrinsicHeight));

                    //height and width of the visible (scaled) image
                    int scaledHeight = imageBounds.height();
                    int scaledWidth = imageBounds.width();

                    //Find the ratio of the original image to the scaled image
                    //Should normally be equal unless a disproportionate scaling
                    float heightRatio = intrinsicHeight / scaledHeight;
                    float widthRatio = intrinsicWidth / scaledWidth;


                    // 3rd method
                    //get the distance from the left and top of the image bounds
                    int scaledImageOffsetX = Math.round(event.getX() - imageBounds.left);
                    int scaledImageOffsetY = Math.round(event.getY() - imageBounds.top);

                    //scale these distances according to the ratio of your scaling
                    //For example, if the original image is 1.5x the size of the scaled
                    //image, and your offset is (10, 20), your original image offset
                    //values should be (15, 30). 
                    int originalImageOffsetX = Math.round(scaledImageOffsetX * widthRatio);
                    int originalImageOffsetY = Math.round(scaledImageOffsetY * heightRatio);

                    Log.i(TAG,  "3: mapped position: "
                            + String.valueOf(originalImageOffsetX) + " / " 
                            + String.valueOf(originalImageOffsetY));

                    //4th method
                    int inv_scaledImageOffsetX = x - imageBounds.left;
                    int inv_scaledImageOffsetY = y - imageBounds.top;
                    int inv_originalImageOffsetX = Math.round(inv_scaledImageOffsetX * widthRatio);
                    int inv_originalImageOffsetY = Math.round(inv_scaledImageOffsetY * heightRatio);

                    Log.i(TAG,  "4: inv mapped position: "
                            + String.valueOf(inv_originalImageOffsetX) + " / " 
                            + String.valueOf(inv_originalImageOffsetY));



                    int touchedRGB = bitmap.getPixel(x, y);
                    int org_touchedRGB = original.getPixel(x, y);

                    // 5th method
                    float[] point_coords = getPointerCoords((ImageView)view, event);
                    Log.i(TAG,  "5: pointer coords position: "
                            + String.valueOf(Math.round(point_coords[0])) + " / " 
                            + String.valueOf(Math.round(point_coords[1])));


                    Log.i(TAG, "getter touched color: " + "#" + Integer.toHexString(touchedRGB));
                    Log.i(TAG, "original touched color: " + "#" + Integer.toHexString(org_touchedRGB));
                    Log.i(TAG, "---------------------");
                    return true;
            }
        };

        private final float[] getPointerCoords(ImageView view, MotionEvent e)
        {
            final int index = e.getActionIndex();
            final float[] coords = new float[] { e.getX(index), e.getY(index) };
            Matrix matrix = new Matrix();
            view.getImageMatrix().invert(matrix);
            matrix.postTranslate(view.getScrollX(), view.getScrollY());
            matrix.mapPoints(coords);
            return coords;
        }



@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}
}

我的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center"
    android:orientation="horizontal" >  
     <ImageView
         android:id="@+id/image"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center"
         android:contentDescription="@string/descImage"
         android:src="@drawable/beerl" />
</LinearLayout>

基本上我已经实现了5种方法来获取活动中触摸像素的位置,我正在记录它们,我的布局中只有一个ImageView。我的图片大小是960x540。所以,当我在图像的大约中间触摸时,我应该得到 值接近480/270,但当我触摸靠近图像中间时,我会在日志中跟随

7-16 11:00:50.097: I/GT:MA(3273): ---------------------
07-16 11:00:50.097: I/GT:MA(3273): 1: touched position: 330.0 / 166.0
07-16 11:00:50.097: I/GT:MA(3273): 2: Inverted touch position by invMatrix: 330 / 166
07-16 11:00:50.097: I/GT:MA(3273): from getter drawable size: 960 / 540
07-16 11:00:50.097: I/GT:MA(3273): actual drawable size: 960 / 540
07-16 11:00:50.097: I/GT:MA(3273): intrinsic width / height: 640 / 360
07-16 11:00:50.097: I/GT:MA(3273): 3: mapped position: 330 / 166
07-16 11:00:50.097: I/GT:MA(3273): 4: inv mapped position: 330 / 166
07-16 11:00:50.097: I/GT:MA(3273): 5: pointer coords position: 330 / 166
07-16 11:00:50.097: I/GT:MA(3273): getter touched color: #ffcd7d27
07-16 11:00:50.097: I/GT:MA(3273): original touched color: #ffcd7d27
07-16 11:00:50.097: I/GT:MA(3273): ---------------------

当我点击图像右下角附近时,我在日志中得到以下内容

07-16 11:03:31.419: I/GT:MA(3273): ---------------------
07-16 11:03:31.419: I/GT:MA(3273): 1: touched position: 635.0 / 348.0
07-16 11:03:31.419: I/GT:MA(3273): 2: Inverted touch position by invMatrix: 635 / 348
07-16 11:03:31.419: I/GT:MA(3273): from getter drawable size: 960 / 540
07-16 11:03:31.419: I/GT:MA(3273): actual drawable size: 960 / 540
07-16 11:03:31.419: I/GT:MA(3273): intrinsic width / height: 640 / 360
07-16 11:03:31.419: I/GT:MA(3273): 3: mapped position: 635 / 348
07-16 11:03:31.419: I/GT:MA(3273): 4: inv mapped position: 635 / 348
07-16 11:03:31.429: I/GT:MA(3273): 5: pointer coords position: 635 / 348
07-16 11:03:31.429: I/GT:MA(3273): getter touched color: #ff242722
07-16 11:03:31.429: I/GT:MA(3273): original touched color: #ff242722
07-16 11:03:31.429: I/GT:MA(3273): ---------------------

整个项目是here [zip],以防你想要清楚地了解整个项目。

为什么intrinsicWidth和intrinsicHeight与BitmapDrawable的实际宽度和高度不同。看起来我得到了正确的值如果我们假设图像的大小为intrinsicWidth X intrinsicHeight。为什么会这样?如何获得所触摸像素的正确位图坐标。

0 个答案:

没有答案