Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a custom drag shadow?

What I want to achieve:

I want to create a drag and drop functionality in Android. I'd like to use a specific layout (different from the dragged object itself) as a drag shadow.

What result I'm getting instead:

Neither of my approaches works as expected - I end up with no visible drag shadow at all (although the target does receive the drop).

What I tried:

I tried

  • inflating the drag_item layout in the activity, then passing it as an argument to the shadow builder's constructor

and

  • inflating the drag_item layout in the shadow builder's onDrawShadow method, then drawing it on the canvas

Layouts:

My activity layout:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:id="@+id/container"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              tools:context="com.example.app.DragDropTestActivity"
              tools:ignore="MergeRootFrame">
    <TextView
        android:id="@+id/tvReceiver"
        android:text="Drop here"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/btnDragged"
        android:layout_height="wrap_content"
        android:text="Drag me"
        android:layout_width="match_parent"/>
</LinearLayout>

The layout I want to use as a drag shadow:

dragged_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Dragged Item"/>
</LinearLayout>

Source code:

Here's the code with both approaches (represented by 1, BuilderOne and 2, BuilderTwo, respectively):

package com.example.app;

import android.graphics.Canvas;
import android.graphics.Point;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;

public class DragDropTestActivity extends ActionBarActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drag_drop_test);
        Button dragged = (Button) findViewById(R.id.btnDragged);

        dragged.setOnTouchListener(
            new View.OnTouchListener()
            {
                @Override
                public boolean onTouch(View v, MotionEvent event)
                {
                    if (event.getAction() != MotionEvent.ACTION_DOWN) {
                        return false;
                    }
                    LayoutInflater inflater = getLayoutInflater();

                    int approach = 1;    
                    // both approaches fail
                    switch (approach) {
                        case 1: {
                            View draggedItem = inflater.inflate(R.layout.dragged_item, null);
                            BuilderOne builder = new BuilderOne(draggedItem);
                            v.startDrag(null, builder, null, 0);
                            break;
                        }
                        case 2: {
                            BuilderTwo builder = new BuilderTwo(inflater, v);
                            v.startDrag(null, builder, null, 0);
                            break;
                        }
                    }

                    return true;
                }
            });
    }

My BuilderOne class:

    public static class BuilderOne extends View.DragShadowBuilder
    {
        public BuilderOne(View view)
        {
            super(view);
        }

        @Override
        public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint)
        {
            super.onProvideShadowMetrics(
                shadowSize,
                shadowTouchPoint);
        }
    }

And BuilderTwo class:

    public static class BuilderTwo extends View.DragShadowBuilder
    {
        final LayoutInflater inflater;

        public BuilderTwo(LayoutInflater inflater, View view)
        {
            super(view);
            this.inflater = inflater;
        }

        @Override
        public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint)
        {
            super.onProvideShadowMetrics(
                shadowSize,
                shadowTouchPoint);
        }

        @Override
        public void onDrawShadow(Canvas canvas)
        {
            final View draggedItem = inflater.inflate(R.layout.dragged_item, null);
            if (draggedItem != null) {
                draggedItem.draw(canvas);
            }
        }
    }
}

Question:

What do I do wrong?

Update:

Bounty added.

like image 794
Konrad Morawski Avatar asked Mar 08 '14 20:03

Konrad Morawski


People also ask

How to create shadows in AutoCAD?

To create shadows, we have to use the free transform tool by keeping the duplicate layer selected press Ctrl+t to bring the transform tool. With the tool, you can move the black portion anywhere you want.

How do I change a drop shadow to a realistic shadow?

The drop shadow needs to be stretched out, so it appears more realistic. The next step is changing that shadow into a realistic shadow. Change the drop shadow into a new layer. Now you can manipulate it on its own. Follow these steps to make this happen: On the layer containing your shadow. Right-click on the fx symbol that has now appeared.

How to make a shadow effect in SketchUp?

Shape Your Shadow 1 In the layer with your object, add a Drop Shadow Effect (fx icon). ... 2 Right-click on the fx symbol that has now appeared in your layer and select Create Layer. ... 3 Use the transform tools described above (skew, scale, and warp) to adjust the shadow to make sense in the image. ... More items...

How do you make a shadow stronger in Photoshop?

This shadow should be stronger near the base, and more diffused, lighter near the top. To do this, create a second shadow layer. Select your shadow layer and go to Layer>Duplicate Layer (Ctrl or ⌘J). You now have a copy. Click on the first shadow layer. Enter 90% into the Fill box found near the top of the layers window.


1 Answers

Kurty is correct in that you shouldn't need to subclass DragShadowBuilder in this case. My thought is that the view you're passing to the DragShadowBuilder doesn't actually exist in the layout, and therefore it doesn't render.

Rather than passing null as the second argument to inflater.inflate, try actually adding the inflated View to the hierarchy somewhere, and then passing it to a regular DragShadowBuilder:

View dragView = findViewById(R.id.dragged_item);
mDragShadowBuilder = new DragShadowBuilder(dragView);
v.startDrag(null, mDragShadowBuilder, null, 0);

EDIT

I'm aware that having the dragged_item view being rendered all the time isn't what you want, but if it works then at least we know where the problem is and can look for a solution to that instead!

like image 186
Matt Rowland Avatar answered Oct 24 '22 08:10

Matt Rowland