如何拖放 recyclerView 元素?
Posted
技术标签:
【中文标题】如何拖放 recyclerView 元素?【英文标题】:How can I do drag and drop recyclerView elements? 【发布时间】:2017-11-12 03:21:09 【问题描述】:我在 android studio 上有一个项目,我想将 RecylerView 中的图像项拖放到我的 Activity 上的容器中...
在我的活动中,我有一个片段容器,它使用 RecyclerView 显示片段,并在 JSON 连接中显示动物部分,可以进行拖放以将图像移动到 Cointainer 以制作动物角色并将数据发送到我的数据库,我是怎么做的???
【问题讨论】:
这看起来像是一个是/否问题。 使用“ItemTouchHelper”检查这个***.com/questions/29901044/… 【参考方案1】:你必须实现ItemTouchHelper
,这是一个关于如何做的例子:
1- 添加您的回收站视图
<android.support.v7.widget.RecyclerView
android:id="@+id/note_recycler_view"
android:scrollbars="vertical"
android:layout_
android:layout_/>
2 - 添加模型类
public class Customer
private Long id;
private String name;
private String emailAddress;
private int imageId;
private String imagePath;
3 - 添加依赖项
compile 'de.hdodenhof:circleimageview:2.0.0'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.yqritc:recyclerview-flexibledivider:1.2.6'
compile 'com.google.code.gson:gson:2.3.1'
4 - 添加 Internet 权限
<uses-permission android:name="android.permission.INTERNET" />
5- 在您的活动中创建一个新的List
或Customer
并将客户添加到其中。
6- 创建一个名为 CustomerListAdapter 的新类
package com.okason.draganddrop;
import android.content.Context;
import android.graphics.Color;
import android.support.v4.view.MotionEventCompat;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.okason.draganddrop.listeners.OnCustomerListChangedListener;
import com.okason.draganddrop.listeners.OnStartDragListener;
import com.okason.draganddrop.utilities.ItemTouchHelperAdapter;
import com.okason.draganddrop.utilities.ItemTouchHelperViewHolder;
import com.squareup.picasso.Picasso;
import java.util.Collections;
import java.util.List;
/**
* Created by Valentine on 10/18/2015.
*/
public class CustomerListAdapter extends
RecyclerView.Adapter<CustomerListAdapter.ItemViewHolder>
implements ItemTouchHelperAdapter
private List<Customer> mCustomers;
private Context mContext;
private OnStartDragListener mDragStartListener;
private OnCustomerListChangedListener mListChangedListener;
public CustomerListAdapter(List<Customer> customers, Context context,
OnStartDragListener dragLlistener,
OnCustomerListChangedListener listChangedListener)
mCustomers = customers;
mContext = context;
mDragStartListener = dragLlistener;
mListChangedListener = listChangedListener;
@Override
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
View rowView = LayoutInflater.from
(parent.getContext()).inflate(R.layout.row_customer_list, parent, false);
ItemViewHolder viewHolder = new ItemViewHolder(rowView);
return viewHolder;
@Override
public void onBindViewHolder(final ItemViewHolder holder, int position)
final Customer selectedCustomer = mCustomers.get(position);
holder.customerName.setText(selectedCustomer.getName());
holder.customerEmail.setText(selectedCustomer.getEmailAddress());
Picasso.with(mContext)
.load(selectedCustomer.getImagePath())
.placeholder(R.drawable.profile_icon)
.into(holder.profileImage);
holder.handleView.setOnTouchListener(new View.OnTouchListener()
@Override
public boolean onTouch(View v, MotionEvent event)
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN)
mDragStartListener.onStartDrag(holder);
return false;
);
@Override
public int getItemCount()
return mCustomers.size();
@Override
public void onItemMove(int fromPosition, int toPosition)
Collections.swap(mCustomers, fromPosition, toPosition);
mListChangedListener.onNoteListChanged(mCustomers);
notifyItemMoved(fromPosition, toPosition);
@Override
public void onItemDismiss(int position)
public static class ItemViewHolder extends RecyclerView.ViewHolder implements
ItemTouchHelperViewHolder
public final TextView customerName, customerEmail;
public final ImageView handleView, profileImage;
public ItemViewHolder(View itemView)
super(itemView);
customerName = (TextView)itemView.findViewById(R.id.text_view_customer_name);
customerEmail = (TextView)itemView.findViewById(R.id.text_view_customer_email);
handleView = (ImageView)itemView.findViewById(R.id.handle);
profileImage = (ImageView)itemView.findViewById(R.id.image_view_customer_head_shot);
@Override
public void onItemSelected()
itemView.setBahttp://valokafor.com/wp-admin/post.php?post=1804&action=edit#ckgroundColor(Color.LTGRAY);
@Override
public void onItemClear()
itemView.setBackgroundColor(0);
7- 实施ItemTouchHelper
在您的实用程序包中,添加 ItemTouchHelperAdapter.java 并且下面是内容:
public interface ItemTouchHelperAdapter
/**
* Called when an item has been dragged far enough to trigger a move. This is called every time
* an item is shifted, and not at the end of a "drop" event.
*
* @param fromPosition The start position of the moved item.
* @param toPosition Then end position of the moved item.
*/
void onItemMove(int fromPosition, int toPosition);
/**
* Called when an item has been dismissed by a swipe.
*
* @param position The position of the item dismissed.
*/
void onItemDismiss(int position);
在你的实用程序包中,添加 ItemTouchHelperViewHolder.java 和下面是内容:
public interface ItemTouchHelperViewHolder
/**
* Implementations should update the item view to indicate it's active state.
*/
void onItemSelected();
/**
* state should be cleared.
*/
void onItemClear();
在您的实用程序包中,添加 SimpleItemTouchHelperCallback.java,这是内容:
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback
private final ItemTouchHelperAdapter mAdapter;
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter)
mAdapter = adapter;
@Override
public boolean isLongPressDragEnabled()
return true;
@Override
public boolean isItemViewSwipeEnabled()
return false;
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
@Override
public boolean onMove(RecyclerView recyclerView,
RecyclerView.ViewHolder source, RecyclerView.ViewHolder target)
mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
return true;
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int i)
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState)
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE)
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
itemViewHolder.onItemSelected();
super.onSelectedChanged(viewHolder, actionState);
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
super.clearView(recyclerView, viewHolder);
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
itemViewHolder.onItemClear();
添加一个名为 listener 的包并添加一个名为 OnStartDragListener.java 的接口,这是内容:
public interface OnCustomerListChangedListener
void onNoteListChanged(List<Customer> customers);
实现自定义行
private RecyclerView mRecyclerView;
private CustomerListAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private ItemTouchHelper mItemTouchHelper;
private List<Customer> mCustomers;
在onCreate方法之后,添加这个方法。然后可能在调用设置工具栏之后从 onCreate() 方法调用此方法。忽略错误警告一分钟。
private void setupRecyclerView()
mRecyclerView = (RecyclerView) `findViewById(R.id.note_recycler_view);`
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mCustomers = SampleData.addSampleCustomers();
//setup the adapter with empty list
mAdapter = new CustomerListAdapter(mCustomers, this, this, this);
ItemTouchHelper.Callback callback = new `SimpleItemTouchHelperCallback(mAdapter);`
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(mRecyclerView);
mRecyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(this)
.colorResId(R.color.colorPrimaryDark)
.size(2)
.build());
mRecyclerView.setAdapter(mAdapter);
更新您的 MainActivity 的签名以实现我们添加的两个侦听器,如下所示,并使用 Android Studio 快速修复来实现这些方法。
public class MainActivity extends AppCompatActivity
implements OnCustomerListChangedListener,
OnStartDragListener
这里是其中一种方法的实现,下一节我们将实现另一种。
@Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder)
mItemTouchHelper.startDrag(viewHolder);
此时,您的拖放列表应该可以工作了,我们现在想要记住重新组织后的列表项的位置。就像我在文章开头提到的那样,这是通过将列表项的 id 保存到 SharedPreference 来完成的,因此请继续将以下类成员添加到文件顶部。
private SharedPreferences mSharedPreferences;
private SharedPreferences.Editor mEditor;
public static final String LIST_OF_SORTED_DATA_ID = "json_list_sorted_data_id";
public final static String PREFERENCE_FILE = "preference_file";
并在 onCreate() 中像这样实例化 SharedPreference:
mSharedPreferences = this.getApplicationContext()
.getSharedPreferences(PREFERENCE_FILE, Context.MODE_PRIVATE);
mEditor = mSharedPreferences.edit();
然后继续实现另一个方法来监听列表何时发生变化,这里是该方法的实现:
@Override
public void onNoteListChanged(List<Customer> customers)
//after drag and drop operation, the new list of Customers is passed in here
//create a List of Long to hold the Ids of the
//Customers in the List
List<Long> listOfSortedCustomerId = new ArrayList<Long>();
for (Customer customer: customers)
listOfSortedCustomerId.add(customer.getId());
//convert the List of Longs to a JSON string
Gson gson = new Gson();
String jsonListOfSortedCustomerIds = gson.toJson(listOfSortedCustomerId);
//save to SharedPreference
mEditor.putString(LIST_OF_SORTED_DATA_ID, jsonListOfSortedCustomerIds).commit();
mEditor.commit();
然后,将此方法添加到您的 MainActivity.java:
private List<Customer> getSampleData()
//Get the sample data
List<Customer> customerList = SampleData.addSampleCustomers();
//create an empty array to hold the list of sorted Customers
List<Customer> sortedCustomers = new ArrayList<Customer>();
//get the JSON array of the ordered of sorted customers
String jsonListOfSortedCustomerId = mSharedPreferences.getString(LIST_OF_SORTED_DATA_ID, "");
//check for null
if (!jsonListOfSortedCustomerId.isEmpty())
//convert JSON array into a List<Long>
Gson gson = new Gson();
List<Long> listOfSortedCustomersId = gson.fromJson
(jsonListOfSortedCustomerId, new TypeToken<List<Long>>().getType());
//build sorted list
if (listOfSortedCustomersId != null && listOfSortedCustomersId.size() > 0)
for (Long id: listOfSortedCustomersId)
for (Customer customer: customerList)
if (customer.getId().equals(id))
sortedCustomers.add(customer);
customerList.remove(customer);
break;
//if there are still customers that were not in the sorted list
//maybe they were added after the last drag and drop
//add them to the sorted list
if (customerList.size() > 0)
sortedCustomers.addAll(customerList);
return sortedCustomers;
else
return customerList;
现在更新setupRecyclerView()
中您从中获取数据的行:
mCustomers = SampleData.addSampleCustomers();
到:
mCustomers = getSampleData();
Here is the source of my answer你可以找到更多关于每一步的信息和描述。
【讨论】:
这是边界线link-only answer。您应该在此处扩展您的答案以包含尽可能多的信息,并使用该链接仅供参考。 @Glory 我已经尝试过这个答案,但这不起作用它导致我在non-null exception
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) mDragStartListener.onStartDrag(holder);
以上是关于如何拖放 recyclerView 元素?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 AsyncTask 更新 RecyclerView 项目
Android:在 RecyclerView 中拖放项目时如何有效更新 SQLite 数据库?
RecyclerView smoothScroll位于中心位置。安卓