Posts Tagged 'drag-drop'

Drag-Drop for Android GridView (V4)

About a year and a half ago, I built an example Android app that allows you to drag images from one spot in a GridView to another. I have had several requests to show how the drag-drop framework used in that example could be adapted to the current Android support (V4+) for drag-drop operations. I have done that work and I am making the source code available in this post.

The sample app works the same as the one described in “Drag-Drop for An Android GridView“. There is a grid displayed on the screen. An “Add Image” button allows you to add images to the screen. Those images can be dragged onto the grid. Any images in the grid can be dragged around. There is also a trash can icon on the screen. Images can be dragged there to remove them from the screen. The image below shows what the app looks like on a Nexus 7 tablet.

drag-griview-v4-05

How It Works

Usually, I do an extensive write-up to explain how my demo apps work. However, this time, I am starting with a very short description in this section and posting the source code. I will add a another longer post in the coming months.

If you read my earlier article about dragging views onto a GridView, you know that the drag-drop framework I use originates with the Android Launcher code for API 8. With a combination of interface classes for DragSource, DropTarget, a DragLayer, and DragController,  the Launcher defined a useful framework for handling drag-drop operations. How I adapted those classes from the Launcher code is described in my earlier blog post. In the newer version of my GridView demo app, I have modified the classes a little bit.

DragActivity – This is the main activity of the demo app. It sets up a grid of images, defines a listener for drag events, and connects it to the views displayed on the screen.

DragSource – A drag source is a view where drag operations start. There is a DragSource interface class that defines the methods that a view must implement to be a source.

DropTarget – A drop target is a view that accepts dragged objects. An interface class describes the methods every DropTarget must implement.

DragController – This object is the controller that does most of the work to support dragging and dropping. It receives the drag events and interacts with DragSource and DropTarget objects. It also sends information back to the activity that created it. That activity is expected to implement the DragDropPresenter interface.

DragDropPresenter – This interface defines the set of methods an activity must support in order to work with a DragController.

ImageCell – An ImageCell is a subclass of ImageView. It is used to display an image on the grid. Since objects can be moved from one spot on the grid to another, an ImageCell is both a DragSource and a DropTarget.

ImageCellAdpater – The object that is used by the GridView to place ImageCell objects on the grid.

DeleteZone – This object is a DropTarget. It allows objects to be dragged onto it for disposal. It is used to implement the trash can that you see on the screen.

In this object model, here is how an object moves on the screen. The user touches a view on the screen. The view touched signals an event, onClick, to its listener, which is the DragActivity. The activity passes the event on to its DragController object. If the view is a DragSource, the controller initiates a drag operation by asking the source for its ClipData and the view to display as the drag shadow. It then has the view start sending drag events (via a call to v.startDrag). As the user moves the view around on the screen, all the events associated with drag-drop are sent to the DragController. The DragController makes everything happen from there. When the shadow view is over a drop target, the view, if it is accepting dropped objects, is informed (via method calls to onDragEnter and onDragExit) so it can provide visual feedback to the user that a potential drop spot has been found. If the user releases the object over a drop target, the target object is informed (via onDrop) so it can perform the operation. There are also method calls made back to the DragActivity so it knows when dragging begins, when it ends, and whether it was successful.

When you study the code for DragController, you will find that there are a lot of conditions being checked. That’s because of the DragController working with two kinds of views (sources, targets) and because of the way I wanted the GridView to work. You can only put one image in a cell. The cell must be empty to accept an image. If you drag an object and drop it somewhere that does not accept drops, it goes back to the cell it started in.

Source Code

You can download the source code for this demo from  the Wglxy.com website. Click here: download zip file from wglxy.com. The zip is attached at the bottom of that page. After you import the project into Eclipse, it’s a good idea to use the Project – Clean menu item to rebuild the project.

This demo app was compiled with Android 4.2 (API 17). It works in all API levels from API 11 on up.

Potential Improvements

This sample app is an adaptation of the drag-drop framework from my earlier sample apps. The first of these (Moving Views In Android – Drag-Drop) goes back to January 2011. That one is the result of studying the Android Launcher code from API Level 8. I simplified the drag-drop framework a bit, but basically maintained its set of classes (DragSource, DropTarget, DragController, etc.).So the current example is a continuation of that framework. As described in the earlier section, you see that it has basically the same classes and interfaces.

It did not take much work to adapt to the Android drag-drop framework, which was introduced in API 11. However, it’s not clear to me that having a set of interface classes and defining View subclasses (e.g. ImageCell) is the easiest way to support drag-drop. In fact, there is a note to that effect in the “Drag and Drop” article. It says “You will probably want to use the listener in most cases. When you design UIs, you usually don’t subclass View classes …”. What I intend to try in the next month or so is another variation of this GridView example. In it, I will support dragging onto the grid, using only a listener. It will be interesting to see if that approach turns out to be easier.

Improved Drag-Drop for an Android GridView

(March 4, 2013 Updsate: This example has been revised for Android V4, See Drag-Drop for GridView V4.)

I have an improved version of my tutorial app described in “Drag-Drop for an Android GridView“. It allows a drag-drop sequence to be initiated from any touch event. The earlier version required the user to do a long click (press) before dragging would start.

There are two download locations for this demo application: (1) download from Wglxy.com; (2) download from Google Docs; It was built with API level 8. Be sure to do a “Clean” rebuild in Eclipse.

Changes

This example application, like other ones I have done related to drag-drop, was based on the Android Launcher code. The Launcher required a long click (press) before an icon on the home screen could be dragged. Several people asked how to make it work on just a regular click. I finally got around to doing that.

To do this, all I had to do was make the activity implement View.onTouchListener. The handler  checks for the ACTION_DOWN event that indicates that the user touched the screen. If it sees that, it starts a drag operation.

public boolean onTouch (View v, MotionEvent ev)
{
 // If we are configured to start only on a long click,
 // we are not going to handle any events here.
 if (mLongClickStartsDrag) return false;
 boolean handledHere = false;
 final int action = ev.getAction();
 // In the situation where a long click is not needed
 // to initiate a drag, simply start on the down event.
 if (action == MotionEvent.ACTION_DOWN) {
    handledHere = startDrag (v);
 }

 return handledHere;
}

There is no right answer for the question: what starts a drag operation? It’s really your choice: long click or one touch. So what I did in the demo application is put a new variable into the DragActivity class. It indicates whether you want long clicks to be the only way to start a drag-drop operation.

private boolean mLongClickStartsDrag = false;
    // If true, it takes a long click to start the drag operation.
    // Otherwise, any touch event starts a drag.

So you can try out both ways of starting a drag-drop operation. Just change the value of the variable from false to true.

References

Input Events - describes the different types of input events for views: click events, touch events, etc.

Discussion about the touch events - the end of the note has a succinct statement about the differences

Drag-Drop for an Android GridView

(March 4, 2013 Updsate: This example has been revised for Android V4, See Drag-Drop for GridView V4.)


It’s time for another tutorial on drag-drop in Android. I have written several other articles on this topic (Part 1, Part 2, Part 3), but the last one was back in February. I have learned quite a bit since then.

This time I built a demo that allows you to add images dynamically to the screen and then drag them onto a GridView. You can then move the images around in the GridView or move them to the trash. The figures below show you what it looks like.

Figure 1 – Touching the “Add Image” button places an image below the 3 x 3 grid.

FIgure 2 – Touching the image for a second or two starts the drag-drop sequence. As you move over regions on the grid, the background color changes to green, indicating that the object can be dropped there.

Figure 3 – Image moves to cell when you remove your finger from the screen.

Figure 4 – A second image on its way to the middle cell in the grid.

 

Figure 5 – Three images on the grid.

Figure 6 – Images can be dragged to a trashcan to remove them from the screen.

Only one image can be in each cell, but the images can be dragged from one cell to another.

How It Works

I have already written extensively about the drag-drop framework in earlier blog articles. I refer you to them for full descriptions: (1) Moving Views in Android – Part 2, Drag and Drop; (2) Moving Views in Android – Part 3, Drop Zones. The first one tells the story of how I modified  the classes and interfaces I found in the Android Launcher to get to a demo program. In the second one, I developed the notion of DropZone as a place on the screen where objects could be dropped. So, given those two notes, I’ll just cover the some of the major differences and improvements.

The first thing that’s different about my latest demo app is that it demonstrates dragging and dropping within one of the standard ViewGroup subclasses: GridView. The earlier work used the deprecated class AbsoluteLayout. At the time, I felt a little bad about the decision to use AbsoluteLayout, but I was eager to achieve my goal of moving views around on the screen and there was a lot to deal with to pare the Android Launcher classes down to a demo program so I used AbsoluteLayout.

Modifying my past demo programs to support dragging to a GridView was not much work at all. The drag-drop framework gave me the object vocabulary. I just had to find how to apply it to a commonly used layout. In this case, I chose to use a FrameLayout as the outermost layout with a GridView nested within it. So I started with DragLayer as a subclass of FrameLayout. The views in the cells of the GridView would have to implement the DropTarget interface if they were to allow objects to be dragged onto them. I also decided that they would implement the DragSource interface so objects could be dragged from one cell to another. Rather than start with views already on the screen, as I had done in the Part 2 demo, I thought I’d make the whole thing dynamic. Images would get added when the user clicks an Add Image button. So that meant there would be one more DragSource object added to the screen with each click.

I ended up with only a few new classes in this demo app. One of them is the ImageCell class, which as I said above, implements both the DragSource and DropTarget interfaces. The other new class is a DeleteZone class, which I used to implement the trashcan that you see on the screen.

With that as background, here’s what’s involved with a drag-drop operation.

  • The user presses on an image on the screen.
  • The view receives that as a “long click” event and passes that to an event  handler via a call to onLongClick.
    (Note: If you do not want long click to be the way to start a drag, see the newer version of this demo.) 
  • The DragActivity object has already set itself up as a listener for long clicks for all the draggable views on the screen. So its onLongClick method is called.
  • Code in onLongClick arranges to start handling of a drag-drop operation by calling a DragController.
    A DragController is an object that handles all of the touch events on behalf of a DragLayer object.
  • The DragLayer, as a subclass of ViewGroup, has an implementation of onInterceptTouchEvent, thus ensuring that all touch events from any of its child views go through it. This is important because this is how the one object, the DragController, gets to work across the view boundary of any single child. (Be sure to read the description of onInterceptTouchEvent in class ViewGroup. As they say, it is a complicated interaction.)
  • When a DragController starts the drag, it gets a bitmap it can display and uses it to create a DragView. The bitmap is built from the view that fielded the original long click event. So what you see moving on the screen is not the actual view, but something that looks like the view.
  • As long as the user continues touching the screen, all the touch events go to the DragLayer, which passes them along to the DragController. The DragController tracks the movement and moves the DragView to keep up.
  • During this time, any ImageCell (DropTarget) objects that are located at that spot on the screen are called with the onDragEnter, onDragExit methods defined by the DropTarget.
  • When the user stops touching the screen, the DragController checks to see if there is a ImageCell (DropTarget) present and if that target is willing to accept a dropped view (via a call to acceptDrop).
  • If the target accepts the drop, the DragController calls the ImageCell onDrop method and also calls the method onDropCompleted of ImageCell where  the drag started, in order to to let it know that the drop completed. (I know that sounds a bit confusing but there are two methods, one for the DropTarget interface and the other for the DragSource interface. ImageCells have both.)

That’s the basic flow. In this demo, the ImageCell class is where most of the interesting code is. Let’s look more closely at that class and a few of its code segments. (Note: Link to full source code is at the end of this article.)

/**
 * This subclass of ImageView is used to display an image on a GridView.
 * An ImageCell knows which cell on the grid it is showing and which
 * grid it is attached to. Cell numbers are from 0 to NumCells-1.
 * It also knows if it is empty.
 *
 * Image cells are places where images can be dragged from and dropped onto.
 * This class implements both the DragSource and DropTarget interfaces.
 */

public class ImageCell extends ImageView
    implements DragSource, DropTarget

Two methods take care of changing the color of the cell as objects are dragged over it.

public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
        DragView dragView, Object dragInfo) {
    int bg = mEmpty ? R.color.cell_empty_hover : R.color.cell_filled_hover;
    setBackgroundResource (bg);
}

public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
        DragView dragView, Object dragInfo) {
    int bg = mEmpty ? R.color.cell_empty : R.color.cell_filled;
    setBackgroundResource (bg);
}

The onDrop method is responsible for filling the cell up with the dragged object. It grabs the drawable from the object being dragged and sets its own drawable to be the same thing.

public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
        DragView dragView, Object dragInfo) {
    // Mark the cell so it is no longer empty.
    mEmpty = false;
    int bg = mEmpty ? R.color.cell_empty : R.color.cell_filled;
    setBackgroundResource (bg);

    // The view being dragged does not actually change its parent 
    // and switch over to the ImageCell.
    // What we do is copy the drawable from the source view.
    ImageView sourceView = (ImageView) source;
    Drawable d = sourceView.getDrawable ();
    if (d != null) {
       this.setImageDrawable (d);
    }
}

In its role as a DragSource, an ImageCell, the one where the drag started, also gets its onDropCompleted called. In that method, the cell clears itself and sets it drawable to empty, thus erasing the previous contents.

public void onDropCompleted (View target, boolean success)
{
    // If the drop succeeds, the image has moved elsewhere.
    // So clear the image cell.
    if (success) {
       mEmpty = true;
       if (mCellNumber >= 0) {
          int bg = mEmpty ? R.color.cell_empty : R.color.cell_filled;
          setBackgroundResource (bg);
          setImageDrawable (null);
       } else {
         // For convenience, we use a free-standing ImageCell to
         // take the image added when the Add Image button is clicked.
         setImageResource (0);
       }
    }
}

For this to work, the DragLayer has to be set up correctly with the right DropTarget objects. The earlier demo programs defined all the DropTargets ahead of time in the layout xml file for the main activity. For this demo, the drop targets are not known ahead of time. They are ImageCell objects in a GridView. Those are allocated dynamically by an ImageCellAdapter in the onCreate method of DragActivity. It’s not particularly easy to get the elements on a GridView except by iterating through the child views of the GridView after they are all present on the screen. Since the DragLayer used by DragActivity is set up as a DragListener of the DragController, there is a perfect spot to set up all the drop targets that are found in the GridView.

public void onDragStart(DragSource source, Object info, int dragAction)
{
    // We are starting a drag.
    // Build up a list of DropTargets from the child views of the GridView.
    // Tell the drag controller about them.

    if (mGridView != null) {
       int numVisibleChildren = mGridView.getChildCount();
       for ( int i = 0; i < numVisibleChildren; i++ ) {
           DropTarget view = (DropTarget) mGridView.getChildAt (i);
           mDragController.addDropTarget (view);
       }
    }

    // Always add the delete_zone so there is a place to get rid of views.
    // Find the delete_zone and add it as a drop target.
    // That gives the user a place to drag views to get them off the screen.
    View v = findViewById (R.id.delete_zone_view);
    if (v != null) {
       DeleteZone dz = (DeleteZone) v;
       mDragController.addDropTarget (dz);
    }
}

All of the drop targets of the DragController are reset in the onDragEnd method.

Next Time

Overall, I think this demo worked out well. I wanted to address many of the comments that I had received from the earlier articles. People wanted to see an alternative for use of the deprecated AbsoluteLayout class, and they wanted to see an example that did not have as many limitations on where you could drag objects.

One thing that I still want to do is adapt this demo to the drag-drop framework described on the Android developers’ website: Dragging and Dropping. It looks like the DragLayer, DragController, DragSource, and DropTarget classes will work nicely with that. Look for more on that in a later article.

Source Code For This Demo

The source code for this demo application is available in two places:  (1) download from Wglxy.com. (2) download from Google Docs.  If you find that the app does not build in Eclipse, be sure to do a clean build by using the “Clean” item on the Project menu.

This demo app was built on a MacBook running Eclipse Galileo and Android 2.2_r3. The app has been tested in the Android emulator and on an LG Optimus phone.

There is also an improved version of this example application. It allows you to drag objects immediately. You do not have to wait for a long click. (In fact, those changes have been incorporated into this example too.) 

Moving Views In Android – Part 3, Drop Zones

DragViewV2 at startI have come to the end of my work on drag-drop in Android. I now understand how views can be placed on the screen and moved by touching them. I also worked out how you can have different drop behavior for different areas of the screen. In my example, I called those areas DropZones. As you drag views around the screen, the drop zones light up to indicate that they are places where you can drop objects.

The figures  show what the app looks like at various points. Figure 1 is what it looks like when it launches. There are two red drop zones and one orange drop zone. There are two images initially visible. Figure 2 shows the menu where you can add other objects and enable and disable the orange drop zone. The other two show the background color changes in the drop zones as you move over them. Green means the drop will be accepted. White means it will not.

DragViewV2 menu

Figures 2-4

How It Works

The classes in this app are derived from the Android Launcher application. In an earlier note (see “Moving Views In Android – Part 2“), I had written up how the Android Launcher app supports moveable views using the touch interface. The Launcher object model includes objects like DragLayer, DragSource, DragController, and DropTarget. The one object I did not explore fully was the DropTarget. That’s what this note (Part 3) is about.

Here’s how DropTargets figure into the Android Launcher. In the Launcher, when you start dragging an icon, check out what happens at the bottom of the screen. You should see that a Trash icon appears. If you drag an icon over that icon, you will see a change in the color of the view being dragged. The red color gives you a good indication that something will happen if you drop the icon there. Since it is a trash icon, you know that it means the icon being dragged will be removed from the workspace. In code, what’s going on is that the Trash view implements the DropTarget interface.

The DropTarget interface defines the following methods:

 boolean acceptDrop (DragSource source, int x, int y, int xOffset,
             int yOffset,DragView dragView, Object dragInfo);
  Rect estimateDropLocation (DragSource source, int x, int y, int xOffset,
             int yOffset,DragView dragView, Object dragInfo, Rect recycle);
  void onDragEnter (DragSource source, int x, int y, int xOffset,
             int yOffset,DragView dragView, Object dragInfo);
  void onDragOver (DragSource source, int x, int y, int xOffset,
             int yOffset,DragView dragView, Object dragInfo);
  void onDragExit (DragSource source, int x, int y, int xOffset,
             int yOffset,DragView dragView, Object dragInfo);
  void onDrop (DragSource source, int x, int y, int xOffset,
             int yOffset,DragView dragView, Object dragInfo);

acceptDrop is there so the drop target has a way to tell the DragController that it is willing to accept a dropped object. The other methods are there so the drop target knows what’s going on during the move of the object. Each time you enter the area defined by the drop target view, onDragEnter is called. Each time you leave, onDragExit is called. That makes those the perfect spot to provide the user with feedback by highlighting the view or the drop target itself. In the Launcher, the view turns red when over a drop target. In my example, the background color changes.

In my example, I added a new class, DropZone, to implement the interface. I set up onDragEnter and onDragExit to make changes in the background color so the user gets a sense of where the dragged object will land. As you run the app, be sure to note the difference between the two red areas on the screen and the orange area. The orange drop zone is set up initially so that it will not accept drops. Try dropping something there and you will see that the dragged object returns to its starting location. Then try again, after using the menu to enable the orange drop zone. Note that the enter color becomes green and that you can drop something there.

Source Code

The source code for this demo application is available in two places:  (1) download from Wglxy.com. (2) download from Google Docs.  If you find that the app does not build in Eclipse, be sure to do a clean build by using the “Clean” item on the Project menu.

This work was done on a MacBook running Eclipse Galileo and Android 2.2.

Moving Views In Android – Part 2, Drag and Drop

This is part 2 of my investigation into how to get views on an Android screen that a user can move by touching them and dragging them. For Moving Views in Android – Part 1, I had a couple of images positioned on the screen and got the images to move on the screen. It turns out that the views themselves were not moving, just the images within the bounds of the view. In the work that I describe here, I actually have the views moving. The key was to have a custom ViewGroup to coordinate drag and drop events for all views within the layout.

The figures below show what the app looks like in the emulator. Figure 1 shows the initial state of the app. Two images and a text view are in the upper left of the screen. The other figures show the views being dragged around the screen. Red highlighting indicates which view is moving.

Figures 1-2

Dragging an image

Figures 3-4:

Dragging the second image Moving the text view

The solution feels pretty good — and it should, considering it is derived from the Android Launcher code. I had searched a long time for good touch and drag-drop examples, and never found any that were as complete as what the Android developers had done. What I like is the good object model and the clear separation of responsibilities among the classes. More on that follows in the next section.

(For more on drag-drop, see “Drag-Drop for Android GridView V4“.) 

How It Works

The Launcher is the activity that manages the workspace you see on your Android phone. Besides being able to launch apps, it allows you to change the layout of icons on the screen. You touch an icon, wait for the feedback (vibration and the change in size of the icon) that you have touched a moveable icon, and then you reposition the icon on the screen.

I made a few simplifying assumptions as I built my example activity object.

  1. The example app allows you to move views, but only on a single screen. The Launcher allows you to place app icons on many screens that you get to by scrolling left and right.
  2. The example app supports only one place where you can drop views. The Launcher supports multiple DropTargets.
  3. The example app allows views to be dropped anywhere, even on top of another view. The Launcher maintains a grid of icons and icons can be dropped only in the grid.
  4. The Launcher has animation and scaling code that is used to show a bitmap of the view being moved. The example app simply shows the bitmap.

The following classes have been adapted for my example DragView application.

DragActivity – The Launcher class was turned into my DragActivity class. It is the main activity of the app.

DragLayer – implements a custom ViewGroup, which coordinates movement of views on the screen. The Launcher DragLayer is a subclass of FrameLayout. Mine is a subclass of MyAbsoluteLayout, which is a clone of the recently deprecated AbsoluteLayout class. AbsoluteLayouts allow views to be positioned to specific absolute x and y positions.

DragController – This object is the controller that does most of the work to support dragging and dropping.

DragSource – defines where a drag operation begins.

DropTarget – defines where an object can be dropped.

DragView – This is the view that you see moving around on the screen during a drag operation. It is not the actual view you want to move, but simply a bitmap that looks like the view.

In this object model, here is how an object moves on the screen. The user touches a view on the screen. The view touched signals an event, onLongClick, to its listener, which is the DragActivity. The activity turns it over to its DragController object. The controller initiates a drag operation by first getting a bitmap copy of the view, storing it in a DragView, and displaying it on the screen. As the user moves the view, the DragLayer fields all the touch events in its onTouchEvent method. It relays those events to the DragController. It watches for the end of the touch (ACTION_UP), but in the mean time, it handles the motion events by shifting the DragView to the new touch position. When the touch finally ends, the controller checks its set of DropTargets to see which one is active and if it will accept the view being dropped there. If it does, the controller calls the onDrop method of the target. In this application, the DragLayer also implements the DropTarget interface. So the onDrop call goes to the DragLayer and it takes the view being dragged and repositions it to the drop location.

The full source code is available below. A few code sections are worth noting now.

Each view that can be moved relays its onLongClick events to the DragActivity. The connection is made in the setupViews method of DragActivity.

private void setupViews() {
...
ImageView i1 = (ImageView) findViewById (R.id.Image1);
ImageView i2 = (ImageView) findViewById (R.id.Image2);
i1.setOnLongClickListener(this);
i2.setOnLongClickListener(this);
...
}

The onLongClick handler calls on the DragController to initiate the drag sequence.

public boolean onLongClick(View v) {
    trace ("onLongClick in view: " + v);
    // Let the DragController initiate a drag-drop sequence.
    // Use the dragInfo to pass along the object being dragged.
    Object dragInfo = v;
    mDragController.startDrag (v, mDragLayer, dragInfo, DragController.DRAG_ACTION_MOVE);
    return true;
}

While the drag is happening, the DragLayer passes all touch events to its DragController. The onTouchEvent method in DragController moves the DragView and its bitmap. That creates the appearance of the view moving on the screen. The move method in DragView uses updateViewLayout, which causes the layout for the screen to be redone, using whatever new x-y positions are in effect.

void move(int touchX, int touchY) {
        // This is what was done in the Launcher code.
        WindowManager.LayoutParams lp = mLayoutParams;
        lp.x = touchX - mRegistrationX;
        lp.y = touchY - mRegistrationY;
        mWindowManager.updateViewLayout(this, lp);
}

At the end of the drag, the onDrop method of DragLayer is called. It repositions the actual view. Note that it too calls to updateViewLayout. That is what causes the DragLayer view to recalculate its layout and redraw all its views.

public void onDrop (DragSource source,
         int x, int y, int xOffset, int yOffset,
        DragView dragView, Object dragInfo)
{
    View v = (View) dragInfo;
    int w = v.getWidth ();
    int h = v.getHeight ();
    int left = x - xOffset;
    int top = y - yOffset;
    DragLayer.LayoutParams lp = new DragLayer.LayoutParams (w, h, left, top);
    this.updateViewLayout(v, lp);
}

Potential Improvements

My adaptation is not quite as clean as it should be. Roughly speaking, in MVC (model-view-controller) terms, the DragActivity is the model, the DragLayer is the view, and the DragController is the controller. It’s not clear to me that I have stayed true to MVC in this example. I think the handlers for click and long click events might be better off in the controller.

This example uses a clone of the deprecated AbsoluteLayout class. Now that I understand the Launcher code better, I see that it might be better in a real application to have the DragLayer view determine exactly where views are allowed to be dropped. That would be similar to the way it was done in the Launcher app. Its Workspace class allows drops only at empty spaces in a grid. (Note: I did something for GridViews. See “Drag-Drop for an Android GridView“.) 

If you want to see an example where views are added dynamically to the DragLayer, see “Moving Views In Android – Part 3: Drop Zones“. It also shows how to give users more visual feedback as objects are being dragged around the screen.

Acknowledgements

Thanks go to the Android development team. With all the code being open source, it makes it easy for all of us to learn from their designs. A post in the Android Developers group about doing drag and drop without AbsoluteLayout pointed me in the right direction.

Source Code

The source code is available as an Eclipse project. it is available in two places:  (1) download from Wglxy.com. (2) download from Google Docs.  Do a “clean build” in Eclipse if it reports errors immediately after importing the project.

If you find that the app does not build in Eclipse, be sure to do a clean build by using the “Clean” item on the Project menu. 

This work was done on a MacBook running Eclipse Galileo and Android 2.2 (API 8).  



Follow

Get every new post delivered to your Inbox.

Join 72 other followers