1

I have a ListFragment that has a custom adapter so that I could have a text view and an image view on each row. When dragging this row to my canvas (a separate fragment), it shows the whole row as the drag shadow (default behavior). I want to drag only the icon/image to the canvas. My code sample below produces the original drag shadow (whole row from list view) with the desired image drawn behind the cell (a bit stretched because of the bounds setting code). Pretty picture here.

According to the View.DragShadowBuilder documentation, you can discard the view that is passed into the constructor and draw your own view. Problem I have with that approach is that the canvas/view size is set and I'm new to graphics. I've been unsuccessful in my attempts to resize and/or clear the canvas and draw my own drawable/bitmap on it. I tried coloring over the canvas with something like canvas.drawColor(Color.BLACK), but that just makes the background black but still behind the original cell.

Another possibility mentioned in the documentation is passing in any view that is in scope. To that end, I created an image view and added a bitmap to it. When I drag, I get an empty drag shadow. Debugging tells me that the height and width of the image view are 0 (and therefore the view and canvas end up being 0 in the drag shadow builder). However, if I ask for the height and width of the drawable, it gives me the expected dimensions. Do I need to do something to make the image view update it's size after adding the bitmap?

Which approach is preferred? Do you have a working example of either approach?

Class

public class IconListFragment extends ListFragment
{
    ...
    private void startDraggingItem( View view, int position )
    {
        Log.d( TAG, "Dragging item." );

        // I'd like to use the custom imageview instead of the current view
        ImageView image = new ImageView( getActivity() );
        image.setImageBitmap( getIconBitmap( position ) );
        // Problem: Shows empty drag shadow (debugging shows that the height and width are 0)
        // The drawable is present and has the right dimensions
        // view.startDrag( data, new FlowchartDragShadowBuilder( image, position ), null, ZERO );

        // Start the drag
        // Problem: Shows both images
        view.startDrag( data, new FlowchartDragShadowBuilder( view, position ), null, ZERO );
    }

    private class FlowchartDragShadowBuilder extends View.DragShadowBuilder
    {
        private Drawable shadow;
        int position;

        public FlowchartDragShadowBuilder( View view, int pos )
        {
            super( view );
            Log.d( TAG, "Building shadow." );
            shadow = getIconDrawable( pos );
            shadow.setCallback( view );
            position = pos;
            shadow.setBounds( ZERO, ZERO, view.getWidth(), view.getHeight() );
        }

        @Override
        public void onDrawShadow( Canvas canvas )
        {
            super.onDrawShadow( canvas );

            Log.d( TAG, "Drawing shadow." );
            shadow.draw( canvas );
            getView().draw( canvas );
        }
    }

    ...
colabug
  • 2,602
  • 2
  • 22
  • 28
  • If I get a handle to the ImageView like this: `ImageView image = (ImageView) getActivity().findViewById( R.id.icon_image );` and set the bitmap `image.setImageBitmap( getIconBitmap( position ) );` it draws the desired shadow. However, the side effect of this is that the image at the top of the list changes each time I drag. I'm confused why creating an ImageView programmatically and setting the bitmap would have different results than recalling a image view from xml. This leads me back to the question: When/how is the sizing/resizing of the ImageView accomplished after adding a bitmap? – colabug Sep 18 '11 at 20:51
  • Someone on Twitter pointed me to setting the adjust view bounds on the image view `image.setAdjustViewBounds( true );`, but that didn't seem to have an effect either. – colabug Sep 18 '11 at 20:54
  • Thats what I have pointed out in my answer. A view will not be drawn anywhere until its added to a parent layout. Also depends on how you retrieve the shadow bitmap, do you call `getDrawingCache` on the view? or do it differently? – Ron Sep 19 '11 at 03:14

2 Answers2

1

Not sure what you're doing in getIconBitmap() but maybe that function isn't working.

I use a new imageview:

shadowbm = Bitmap.createBitmap(thisbutton.getWidth(), thisbutton.getHeight(), Bitmap.Config.ARGB_8888);
Canvas m = new Canvas(shadowbm);
thisbutton.draw(m);
thisbutton.setVisibility(View.GONE);
shadow.setImageBitmap(shadowbm);

shadow.setX(thisbutton.getLeft());
shadow.setY(thisbutton.getTop());
shadow.setVisibility(View.VISIBLE);

As long as you can draw onto the new canvas you can make any shadow you want. Just remember to call destroy() on the bitmap to free up the memory.

Li_W
  • 759
  • 1
  • 5
  • 15
  • Thanks for the quick response. I think the function `getIconBitmap()` returns the right bitmap since it has expected width & height (confirmed via debugger). I'm having trouble translating your code sample into working code for my example. Is your code in the `onDrawShadow()` function? What type is `shadow` - an `ImageView`? What are you doing with the invisible button? – colabug Sep 18 '11 at 17:17
  • I don't use any of the `startDrag()` functions. Just override the `onTouchEvent` code. So the code above goes into `ACTION_DOWN` to create the shadow and hide the original (thisbutton). `shadow` is an imageview. `ACTION_MOVE` will reposition the shadow. `ACTION_UP` will position the original, and then destroy the shadow. Sorry this is a little bit more complicated than expected but I have not had much luck with androids drag mechanics. – Li_W Sep 20 '11 at 19:26
0

Try enabling the drawing cache. The problem may be because it is not added to any layout.

ImageView image = new ImageView( getActivity() );
image.setDrawingCacheEnabled(true);
image.setImageBitmap( getIconBitmap( position ) );
image.buildDrawingCache();

Then start dragging it. Hope it helps.

Update

In onDrawShadow() get the view bitmap by calling getdrawingCache() method on the imageview

    @Override
    public void onDrawShadow( Canvas canvas )
    {
        super.onDrawShadow( canvas );

        Log.d( TAG, "Drawing shadow." );
        shadow.draw( canvas );
        /* get the bitmap by calling getDrawingCache() on view.*/
        canvas.drawBitmap(getView().getDrawingCache(), left, top, null/*paint*/);
    }
Ron
  • 24,175
  • 8
  • 56
  • 97
  • Thanks for the suggestion, but unfortunately it didn't change the blank shadow problem (with the second approach) and the image view still reports size of 0. – colabug Sep 18 '11 at 20:46
  • The imageView will not get its size unless its added to any layout. Try my updated answer. should work this time. – Ron Sep 19 '11 at 03:44
  • I ripped this out since I couldn't get it to work. I was trying to reuse the HoneyComb Gallery list view, but now I rethinking how I want it to look. – colabug Oct 04 '11 at 17:20