68220

How to drag and drop an image from a Recycler view and place it outside of it into another layout

Question:

I have a horizontal Recylcer view which holds a list of items. Each item has a text view and image view to represent the item (e.g an image of a square and the text "Square" above the image). The recylcer view is inside of it's own relative layout positioned at the top of the screen. What I need to do is drag an image from the recycler view and drop it outside of it into another layout that is below this one. However, the image that is dragged from the recycler view must not be removed, but instead a copy of the image should be placed into the outside layout. The image must also be dropped in the exact position in the layout where the user releases their finger. Is there any way to achieve this?

An example of this could be like in a game, where the user has a list of objects to drag and drop into the game world.

Here's an example to illustrate what I mean:

<img alt="example" class="b-lazy" data-src="https://i.stack.imgur.com/ydz3C.png" data-original="https://i.stack.imgur.com/ydz3C.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" />

Adapter class for Recycler View:

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> { private List<ListItems> listItems; private Context context; public RecyclerAdapter(List<ListItems> listItems, Context context) { this.listItems = listItems; this.context = context; } @Override public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.layout_recycler_view_row_one, parent, false); ViewHolder vh = new ViewHolder(v); return vh; } @Override public void onBindViewHolder(RecyclerAdapter.ViewHolder holder, int position) { ListItems listItems = listItems.get(position); holder.textView.setText(listItems.getItemName()); holder.imageView.setImageResource(listItems.getImageDrawable()); } @Override public int getItemCount() { return listItems.size(); } public class ViewHolder extends RecyclerView.ViewHolder { public ImageView imageView; public TextView textView; public ViewHolder(View itemView) { super(itemView); imageView = (ImageView) itemView.findViewById(R.id.item_image_view); textView = (TextView) itemView.findViewById(R.id.item_name_text_view); } }

MainActivity.class:

public class MainActivity extends AppCompatActivity { RelativeLayout relativeLayoutMiddle; private RecyclerView recyclerView; private RecyclerView.LayoutManager layoutManager; private RecyclerView.Adapter adapter; private List<ListItems> listItems; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listItems = new ArrayList<>(); for (int i = 0; i < 4; i++) { if(i==0) { ListItems listItems = new ListItems("Square", R.drawable.square); listItems.add(listItems); } else if(i==1) { ListItems listItems = new ListItems("Circle", R.drawable.circle); listItems.add(listItems); } else if(i==2) { ListItems listItems = new ListItems("Rectangle", R.drawable.rectangle); listItems.add(listItems); } else if(i==3) { ListItems listItems = new ListItems("Triangle", R.drawable.triangle); listItems.add(listItems); } } recyclerView = (RecyclerView) findViewById(R.id.recycler_view); recyclerView.setHasFixedSize(true); layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); recyclerView.setLayoutManager(layoutManager); adapter = new RecyclerAdapter(listItems, this); recyclerView.setAdapter(adapter); relativeLayoutMiddle = (RelativeLayout) findViewById(R.id.relativeLayoutMiddle);

Answer1:

This can basically be accomplished in just a few lines of code using the <a href="https://developer.android.com/guide/topics/ui/drag-drop.html" rel="nofollow">Android drag and drop api</a>.

<ol><li>Call <a href="https://developer.android.com/reference/android/view/View.html#startDragAndDrop(android.content.ClipData,%20android.view.View.DragShadowBuilder,%20java.lang.Object,%20int)" rel="nofollow">View.startDragAndDrop</a></li> <li>Attach a <a href="https://developer.android.com/reference/android/view/View.OnDragListener.html" rel="nofollow">View.OnDragListener</a> to your drop container</li> <li>Wait for <a href="https://developer.android.com/reference/android/view/DragEvent.html#ACTION_DROP" rel="nofollow">DragEvent.ACTION_DROP</a> and then inflate and position your shape</li> </ol>

In your RecyclerView.Adapter, attach a View.OnLongClickListener and then call View.startDragAndDrop. Something like:

@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { final View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.layout_recycler_view_row_one, parent, false); final ViewHolder holder = new ViewHolder(v); final View shape = holder.imageView; holder.itemView.setOnLongClickListener(v -> { final ListItems item = listItems.get(holder.getAdapterPosition()); final DragData state = new DragData(item, shape.getWidth(), shape.getHeight()); final DragShadowBuilder shadow = new DragShadowBuilder(shape); ViewCompat.startDragAndDrop(shape, null, shadow, state, 0); return true; }); return holder; }

public class DragData { public final ListItems item; public final int width; public final int height; public DragData(ListItems item, int width, int height) { this.item= item; this.width = width; this.height = height; } }

In your Activity or wherever you inflate your bottom container layout, call View.setOnDragListener and when DragEvent.ACTION_DROP is called we can inflate a copy of the View you called startDragAndDrop on. Something like:

@Override public boolean onDrag(View v, DragEvent event) { switch (event.getAction()) { case DragEvent.ACTION_DRAG_ENTERED: dropContainer.setBackgroundColor(GREEN); break; case DragEvent.ACTION_DRAG_EXITED: dropContainer.setBackgroundColor(RED); break; case DragEvent.ACTION_DRAG_ENDED: dropContainer.setBackgroundColor(WHITE); break; case DragEvent.ACTION_DROP: final float dropX = event.getX(); final float dropY = event.getY(); final DragData state = (DragData) event.getLocalState(); final ImageView shape = (ImageView) LayoutInflater.from(this).inflate( R.layout.view_shape, dropContainer, false); shape.setImageResource(state.item.getImageDrawable()); shape.setX(dropX - (float) state.width / 2); shape.setY(dropY - (float) state.height / 2); shape.getLayoutParams().width = state.width; shape.getLayoutParams().height = state.height; dropContainer.addView(shape); break; default: break; } return true; }

Results

<img alt="" class="b-lazy" data-src="https://i.imgur.com/PuvOhyL.gif" data-original="https://i.imgur.com/PuvOhyL.gif" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" />

Recommend

  • RecyclerView scrolling makes changes
  • Toggle Button positions in RecyclerView
  • Cannot call this method while RecyclerView is computing a layout or scrolling when try remove item f
  • RecyclerView onClickListener [duplicate]
  • Removing Item From Recyclerview When Time Expired
  • Android SimpleAdapter wrong data-item gets associated with a list row
  • HTML5 canvas drawImage not working on first click
  • Get byte[] from
  • How to Filter ListAdapter using getFilter() within a fragment
  • IndexSizeError on drawImage on IE and Edge
  • Toggle button in a list view loose their state when scrolled of screen in Android
  • SearchView wrong alignment
  • Android List Fragment with fixed Header
  • List view crashes when scrolling “The application may be doing too much work on its main thread.”
  • Listview with multiple strings
  • c# devexpress piechart series point color change
  • Variant from android-autofittextview library : scaling makes strange behaviour
  • SearchView WITHOUT ACTIONBAR [duplicate]
  • Activity overlaying. WindowManager.LayoutParams
  • How to Make a Spinner (In a Fragment) That Changes the App's Language?
  • Wrong row deleted from custom listview with spinner
  • Syntax error on tokens, AnnotationName expected instead - error on query
  • How to render a blob on a canvas element?
  • how to do an event when i swipe from fragment to the other
  • Possible to stop flickering java tooltip in heavyweight mode?
  • MySQL WHERE-condition in procedure ignored
  • sending/ receiving email in Java
  • Eraser for UIBezierPath
  • Rearranging Cells in UITableView Bug & Saving Changes
  • Suggestions to manage Login/Logout transitions
  • How get height of the a view with gone visibility and height defined as wrap_content in xml?
  • FormattedException instead of throw new Exception(string.Format(…)) in .NET
  • Exception on Android 4.0 `android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode)`
  • unknown Exception android
  • EntityFramework adding new object to nested object collection
  • Checking variable from a different class in C#
  • Sorting a 2D array using the second column C++
  • failed to connect to specific WiFi in android programmatically
  • java string with new operator and a literal
  • How can I use threading to 'tick' a timer to be accessed by other threads?