Reputation: 45
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:
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);
Upvotes: 3
Views: 3959
Reputation: 30794
This can basically be accomplished in just a few lines of code using the Android drag and drop api.
View.startDragAndDrop
View.OnDragListener
to your drop containerDragEvent.ACTION_DROP
and then inflate and position your shapeIn 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
Upvotes: 9