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.
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);
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With