如何使用android中的拖放框架从一个LinearLayout切换到另一个LinearLayout

Posted

技术标签:

【中文标题】如何使用android中的拖放框架从一个LinearLayout切换到另一个LinearLayout【英文标题】:How to swap from one LinearLayout to another LinearLayout using drag and drop framework in android 【发布时间】:2020-01-07 07:36:36 【问题描述】:

TextViewImageView 合二为一 LinearLayout。我想以这样的方式将第一个LinearLayout 拖到第二个LinearLayout,当我将第一个线性拖放到第二个LinearLayout 时,它的TextViewImageView 应该首先出现LinearLayout,反之亦然。我已经完成了研发,我发现将布局从第一个拖放到第二个,但第二个布局没有出现在第一个布局中。

问题是布局没有得到交换。我可以从第一个拖放到第二个,但不能从第一个拖放到第二个。

下面是我的片段:

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);
    

请帮帮我,请提供解决方案。谢谢。

【问题讨论】:

Why don't you use RecyclerView with ItemTouchHelper @NileshRathod 我不知道它对我有什么帮助:( 查看上述评论中的链接或在谷歌中搜索ItemTouchHelper @NileshRathod 在ItemTouchHelper 的帮助下,我们可以进行拖放和滑动或关闭,但不能交换视图,反之亦然。 是的,这是可能的,但您已经为该功能创建了逻辑 【参考方案1】:

您可以使用RecyclerViewGridLayoutManager 来代替 几个LinearLayout如下:

步骤:

将以下依赖项添加到 gradle 应用模块中

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

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

主布局:

<?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_
    android:layout_
    tools:context=".MainActivity">

</androidx.recyclerview.widget.RecyclerView>

列表项布局(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_
    android:layout_
    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_
        android:layout_
        android:orientation="vertical"
        android:padding="4dp">

        <ImageView
            android:id="@+id/imThumbnail"
            android:layout_
            android:layout_
            android:layout_gravity="center"
            tools:background="@drawable/ic_android_black_24dp" />

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

    </LinearLayout>

</androidx.cardview.widget.CardView>

要在 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 适配器

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());
        
    

最后是主要行为

利用ItemTouchHelper 类拖动功能并使用attachToRecyclerView() 方法将其附加到RecyclerView

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);
    


结果在这里

希望能满足你的需求

【讨论】:

以上是关于如何使用android中的拖放框架从一个LinearLayout切换到另一个LinearLayout的主要内容,如果未能解决你的问题,请参考以下文章

Android中的拖放+自定义绘图

android 2.2 中的拖放布局

如何仅在android中限制沿y轴的拖放?

如何使用 iOS11 的拖放 API 获取正在拖动的单元格的框架或中心

如何正确模拟硒中的拖放

如何模拟酶测试用例中的拖放?