Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to position canvas in View.DragShadowBuilder.onProvideShadowMetrics

I have a requirement where a draggable view needs the shadow to be initially placed directly on top of the view - that is, it covers the entire view rather than relating to the touch point.

I've been trying all sorts to get this working with my subclass of View.DragShadowBuilder but with no luck. I hoped using drawRect would allow me to specify the rectangle points so that it would be drawn in the same rectangle as my view, but this results in no canvas being drawn.

However, just using canvas.drawColor(Color.CYAN) draws the rectangle, but relative to the touch point.

Here is my attempt using drawRect:

    private class VideoDragShadowBuilder extends View.DragShadowBuilder {

    public VideoDragShadowBuilder(View v) {
        super(v);
    }

    @Override
    public void onProvideShadowMetrics (Point size, Point touch) {
        int width, height;

        width = getView().getWidth();
        height = getView().getHeight();

        size.set(width, height);
        touch.set(width / 2, height / 2);
    }

    @Override
    public void onDrawShadow(Canvas canvas) {
        //canvas.drawColor(Color.CYAN);

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setAlpha(45);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.CYAN);

        canvas.drawRect(getView().getLeft(), getView().getTop(), getView().getRight(), getView().getBottom(), paint);
    }
}

Here, the blue rectangle is slightly misaligned with the view underneath because of where I touched - I want it to totally cover the view regardless of where the user touches.

enter image description here

like image 729
Karen Forde Avatar asked Sep 29 '22 23:09

Karen Forde


2 Answers

Here's the solution I ended up with using @pskink's suggestions. I didn't have to use drawRect at all, the key was setting the touch point which I previously didn't have as I wasn't using onTouchEvent. Adding this for anyone who might have the same problem.

private Point lastTouch;

public DraggableFrameLayout(Context context, AttributeSet attrs) {
    super(context, attrs);

    dragListener = new View.OnLongClickListener() {

        @Override
        public boolean onLongClick(View v) {
            View.DragShadowBuilder videoShadow = new DragShadowBuilder(v);
            v.startDrag(draggableData, videoShadow, null, 0);
            return true;
        }
    };
}

@Override
public boolean onTouchEvent (MotionEvent ev)    {
    lastTouch = new Point((int) ev.getX(), (int) ev.getY()) ;
    return super.onTouchEvent(ev);
}

private class DragShadowBuilder extends View.DragShadowBuilder {

    public VideoDragShadowBuilder(View v) {
        super(v);
    }

    @Override
    public void onProvideShadowMetrics (Point size, Point touch) {
        super.onProvideShadowMetrics(size, touch);

        // The touch point must be set in order for the canvas to properly fit the view
        if (lastTouch != null) {
            touch.set(lastTouch.x, lastTouch.y);
        }
    }

    @Override
    public void onDrawShadow(Canvas canvas) {
        super.onDrawShadow(canvas);
        canvas.drawColor(Color.CYAN);
    }
}   
like image 118
Karen Forde Avatar answered Oct 28 '22 08:10

Karen Forde


public void drawRect (float left, float top, float right, float bottom, Paint paint) Added in API level 1

Draw the specified Rect using the specified paint. The rectangle will be filled or framed based on the Style in the paint. Parameters left The left side of the rectangle to be drawn top The top side of the rectangle to be drawn right The right side of the rectangle to be drawn bottom The bottom side of the rectangle to be drawn paint The paint used to draw the rect

Taken from here.

if you want to call drawRect with x1, y1, x2, y2, you should not pass x2 and y2 as point coordinates. However, the difference between the end point and the start point yields the desired result, so you should pass x2 - x1 instead of x2 and y2 - y1 instead of y2.

Reason: right is not a coordinate, but the wideness, bottom is not a coordinate, but a height.

like image 36
Lajos Arpad Avatar answered Oct 28 '22 09:10

Lajos Arpad