4

I have TextView and ImageView in one LinearLayout. I want to drag first LinearLayout to second LinearLayout in such a manner when I drop the first linear to second LinearLayout, its TextView and ImageView should come in first LinearLayout and vice versa. I have done the R&D where I have found to drag and drop layout from first to second but the second layout is not coming in the first layout.

The problem is the layouts are not getting an exchange. I am able to drag and drop from first to second but unable to do first to second.

Below is my fragment :

public class MoreDestinationFragment extends Fragment implements View.OnClickListener, View.OnTouchListener, View.OnDragListener {

    private OnFragmentInteractionListener mListener;
    private LinearLayout llNews;

    public MoreDestinationFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_more_destination, container, false);

        llNews = view.findViewById(R.id.ll_new);

        llNews.setOnClickListener(this);
        llNews.setOnTouchListener(this);
        llNews.setOnDragListener(this);

        return view;
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.ll_new:
                Navigation.findNavController(view).navigate(R.id.action_moreDestinationFragment_to_newsDestinationFragment);
                break;

    }

    @Override
    public boolean onDrag(View layoutview, DragEvent dragevent) {
        int action = dragevent.getAction();
        switch (action) {
            case DragEvent.ACTION_DRAG_STARTED:
                Log.d("xxxxxxx", "Drag event started");
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                Log.d("xxxxxxx", "Drag event entered into " + layoutview.toString());
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                Log.d("xxxxxxx", "Drag event exited from " + layoutview.toString());
                break;
            case DragEvent.ACTION_DROP:
                Log.d("xxxxxxx", "Dropped");
                View view = (View) dragevent.getLocalState();
                ViewGroup owner = (ViewGroup) view.getParent();
                owner.removeView(view);
                LinearLayout container = (LinearLayout) layoutview;
                container.addView(view);
                view.setVisibility(View.VISIBLE);
                break;
            case DragEvent.ACTION_DRAG_ENDED:
                Log.d("xxxxxxx", "Drag ended");
                break;
            default:
                break;
        }
        return true;
    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
            View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
            view.startDrag(null, shadowBuilder, view, 0);
            view.setVisibility(View.INVISIBLE);
            return true;
        } else {
            return false;
        }
    }

    public interface OnFragmentInteractionListener {
        void onFragmentInteraction(Uri uri);
    }
}

Please help me out and please advice the solution. Thanks.

Menu
  • 677
  • 1
  • 12
  • 30

1 Answers1

0

You can do this with RecyclerView with GridLayoutManager instead of several LinearLayout's as below:

Steps:

Add below dependencies into gradle app module

// RecyclerView
implementation 'androidx.recyclerview:recyclerview:1.0.0'

// CardView
implementation 'androidx.cardview:cardview:1.0.0'

Main Layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/recyclerview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

</androidx.recyclerview.widget.RecyclerView>

List item layout (of the RecyclerView)

<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:layout_marginBottom="4dp"
    android:clickable="true"
    android:elevation="4dp"
    android:focusable="true"
    android:foreground="?android:attr/selectableItemBackground"
    card_view:cardCornerRadius="10dp"
    card_view:cardUseCompatPadding="true"
    tools:ignore="UnusedAttribute">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="4dp">

        <ImageView
            android:id="@+id/imThumbnail"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_gravity="center"
            tools:background="@drawable/ic_android_black_24dp" />

        <TextView
            android:id="@+id/tvTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            tools:text="Android" />

    </LinearLayout>

</androidx.cardview.widget.CardView>

Model class for items to be populated in RecyclerView

public class Item {

   private String mTitle;
    private int mThumbnail;

    public String getTitle() {
        return mTitle;
    }

    public Item(String title, int thumbnail) {
        this.mTitle = title;
        mThumbnail = thumbnail;
    }

    public void setTitle(String title) {
        this.mTitle = title;
    }

    public int getThumbnail() {
        return mThumbnail;
    }

    public void setThumbnail(int thumbnail) {
        mThumbnail = thumbnail;
    }

}

RecyclerView Adapter

public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {

    List<Item> mItems;

    public Adapter(ArrayList items) {
        mItems = items;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.bindViews(mItems.get(position));
    }

    @Override
    public int getItemCount() {
        return mItems.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder {
        TextView mTitle;
        ImageView mThumbnail;

        ViewHolder(@NonNull View itemView) {
            super(itemView);
            mTitle = itemView.findViewById(R.id.tvTitle);
            mThumbnail = itemView.findViewById(R.id.imThumbnail);
        }

        void bindViews(Item item) {
            mTitle.setText(item.getTitle());
            mThumbnail.setImageResource(item.getThumbnail());
        }
    }
}

And finally the main behavior

utilize the ItemTouchHelper class drag functionality and attach it to the RecyclerView using attachToRecyclerView() method

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private ArrayList<Item> mItems;
    private Adapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        populateItems();

        mAdapter = new Adapter(mItems);

        RecyclerView recyclerView = findViewById(R.id.recyclerview);
        recyclerView.setLayoutManager(new GridLayoutManager(this, 4));
        recyclerView.setAdapter(mAdapter);


        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
                ItemTouchHelper.UP |
                        ItemTouchHelper.DOWN |
                        ItemTouchHelper.LEFT |
                        ItemTouchHelper.RIGHT,
                0) {
            @Override
            public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
                moveItem(viewHolder.getAdapterPosition(), target.getAdapterPosition());
                return false;
            }

            @Override
            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {

            }
        });

        itemTouchHelper.attachToRecyclerView(recyclerView);

    }

    private void populateItems() {
        mItems = new ArrayList<>();
        mItems.add(new Item("Android", R.drawable.ic_android_black_24dp));
        mItems.add(new Item("Archive", R.drawable.ic_archive_black_24dp));
        mItems.add(new Item("Alarm", R.drawable.ic_access_alarm_black_24dp));
        mItems.add(new Item("Block", R.drawable.ic_block_black_24dp));
        mItems.add(new Item("CAll", R.drawable.ic_call_black_24dp));
        mItems.add(new Item("Android", R.drawable.ic_android_black_24dp));
        mItems.add(new Item("Archive", R.drawable.ic_archive_black_24dp));
        mItems.add(new Item("Alarm", R.drawable.ic_access_alarm_black_24dp));
        mItems.add(new Item("Block", R.drawable.ic_block_black_24dp));
        mItems.add(new Item("CAll", R.drawable.ic_call_black_24dp));
    }

    private void moveItem(int oldPos, int newPos) {
        Item temp = mItems.get(oldPos);
        mItems.set(oldPos, mItems.get(newPos));
        mItems.set(newPos, temp);
        mAdapter.notifyItemMoved(oldPos, newPos);
    }

}

And here the result

wish that satisfy your needs

Zain
  • 37,492
  • 7
  • 60
  • 84