Search code examples
androidxamarinxamarin.androidandroid-custom-view

Get Touch Coordinates Relative To A Custom ImageView


I implemented custom ImageView. Because my image is large I'm using ScrollView and HorizontalScrollView to scrolling image. I want to draw circle in onTouch event, but its not work in all cases. When I scroll image and fire touch event the x,y coordinates apply to current visible sector of image ( in top right corner its e.g. 0x0, but when I scroll somwhere and in visible top corner it will be 0x0 too), but circle is drawing according to image size. Another problem is that app could be used on various screen size. I know that it xamarin c# but in native Android it should be the same. Anyone knows how to draw/get coordinates properly?

public class DrawViewInside : ImageView
{

    public static Bitmap bitmapInside;
    private Paint paint = new Paint();
    private Point point = new Point();

    private Canvas mCanvas;
    private static Bitmap mutableBitmap;
    private Context mContext;
    public static Bitmap b;
    public void SetCarId(int id)
    {
        carId = id;
    }
    public DrawViewInside(Context context, IAttributeSet attrs) : base(context, attrs)
    {
        mContext = context;
        setDefault(drawable);
    }

    public void SetBitmap(int drawableId)
    {
        setDefault(drawableId);
        Invalidate();
    }


    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        base.OnMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = MeasureSpec.GetSize(widthMeasureSpec);
        int height = width;

        var metrics = Resources.DisplayMetrics;
        if (b != null)
        {
            SetMeasuredDimension(b.Width, b.Height);
        }

    }


    public async void setDefault(int drawableId)
    {


            BitmapFactory.Options options = await GetBitmapOptionsOfImage(drawableId);
            paint.Color = Color.Red;
            paint.StrokeWidth = 15;
            paint.SetStyle(Paint.Style.Stroke);
            var metrics = Resources.DisplayMetrics;
            var widthInDp = ConvertPixelsToDp(metrics.WidthPixels);
            var heightInDp = ConvertPixelsToDp(metrics.HeightPixels);

            b = BitmapFactory.DecodeResource(Resources, drawableId);esources, drawableId);
            mutableBitmap = b.Copy(Bitmap.Config.Argb8888, true);
            mCanvas = new Canvas(mutableBitmap);
            mCanvas.Save();

    }


    protected override void OnDraw(Canvas canvas)
    {
        DrawCircle(canvas);


    }
    private void DrawCircle(Canvas canvas)
    {
        if (mCanvas == null)
        {
            setDefault(drawable);
        }
        else
        {
            mCanvas.Restore();
            mCanvas.DrawCircle(point.x, point.y, 10, paint);
            mCanvas.Save();
            canvas.DrawBitmap(mutableBitmap, 0, 0, paint);
            bitmapInside = mutableBitmap;
        }


    }

    public override bool OnTouchEvent(MotionEvent e)
    {
        switch (e.Action)
        {
            case MotionEventActions.Down:

                break;

            case MotionEventActions.Up:
                        Activity act = (Activity)mContext;

                        float viewX = e.RawX - this.Left;
                        float viewY = e.RawY - this.Top;
                        point.x = viewX;// e.RawX;
                        point.y = viewY;// e.RawY;

                    break;
                }
        Invalidate();
        return true;

    }

}
public class Point
{
    public float x, y;
}

Solution

  • I found solution. Just replace

                       float viewX = e.RawX - this.Left;
                        float viewY = e.RawY - this.Top;
                        point.x = viewX;// e.RawX;
                        point.y = viewY;// e.RawY;
    

    with

                           float viewX = e.RawX;// - this.Left;
                            float viewY = e.RawY;// - this.Top;
                            int[] viewCoords = new int[2];
                            this.GetLocationOnScreen(viewCoords);
                            point.x = viewX - viewCoords[0];// e.RawX;
                            point.y = viewY - viewCoords[1];// e.RawY;