在android的recyclerview上实现项目触摸助手的正确方法 [英] correct way to implement item touch helper on recyclerview in android

查看:92
本文介绍了在android的recyclerview上实现项目触摸助手的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遵循了此处上的教程当我运行代码时,如何实现onItemTouchHelper和回调方法,它的工作原理是我可以长按并拾取该项目,但是当我将其移过列表中其他项目之一时,我的应用将强制使用索引关闭越界例外,这里有人可以帮助我吗?

这是我的代码,但与本教程中的代码相同,

简单项目触摸助手回调

public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback 
{

private final predictsCardAdapter mAdapter;

public SimpleItemTouchHelperCallback(predictsCardAdapter adapter){
    mAdapter = adapter;
}

@Override
public boolean isLongPressDragEnabled(){
    return true;
}
@Override
public boolean isItemViewSwipeEnabled(){
    return false;
}

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    int dragFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
    int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;

    return makeMovementFlags(dragFlags,swipeFlags);
}

@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    mAdapter.onItemMove(viewHolder.getAdapterPosition(), 
    target.getAdapterPosition());
    //mAdapter.notifyItemMoved(viewHolder.getAdapterPosition(), 
    //target.getAdapterPosition());
    return true;
}

@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
}

这是我的适配器

public class predictsCardAdapter extends   
RecyclerView.Adapter<predictsCardAdapter.MyViewHolder> implements    
ItemTouchHelperAdapter{
private List<addNewCard> cardMakerList;

@Override
public boolean onItemMove(int fromPosition, int toPosition) {
    if (fromPosition < toPosition){
        for (int i = fromPosition; i < toPosition; i++){
            Collections.swap(cardMakerList,i,i+1);
        }
    }else{
        for (int i = fromPosition; i > toPosition; i--){
            Collections.swap(cardMakerList,i,i-1);
        }
    }
    notifyItemMoved(fromPosition,toPosition);
    return true;
}

@Override
public void onItemDismiss(int position) {
cardMakerList.remove(position);
    notifyItemRemoved(position);
}

public class MyViewHolder extends RecyclerView.ViewHolder{
    public TextView cardText, speechText;
    public ImageView cardImage;
    public ContentLoadingProgressBar progress;

    public MyViewHolder(View view){
        super(view);
        cardText = (TextView) view.findViewById(R.id.predictscardText);
        speechText = (TextView) view.findViewById(R.id.predictsspeechText);
        cardImage = (ImageView) view.findViewById(R.id.predictscardimage);
        progress = (ContentLoadingProgressBar)  
        view.findViewById(R.id.predictsprogress);
    }

}
public predictsCardAdapter(List<addNewCard> cardMakerList){
    this.cardMakerList = cardMakerList;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
    View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.predicted_card, parent, false);
    return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder 
(final MyViewHolder predicts_holder, int position) {
    addNewCard cardmaker = cardMakerList.get(position);
    predicts_holder.cardText.setText(cardmaker.getCardName());
    predicts_holder.speechText.setText(cardmaker.getCardName());
    //Drawable d = new  
    BitmapDrawable(Utility.getPhoto(cardmaker.getCardIcon()));

    String url = cardmaker.getCardIcon();
    ImageLoader imageLoader = ImageLoader.getInstance();
    DisplayImageOptions options = new  
    DisplayImageOptions.Builder().cacheInMemory(true)
            .cacheOnDisc(true).resetViewBeforeLoading(true)
            .showImageForEmptyUri(R.drawable.loading_image)
            .showImageOnFail(R.drawable.broken_image).build();

    imageLoader.displayImage
    (url, predicts_holder.cardImage, options, new  
    SimpleImageLoadingListener() {
        @Override
        public void onLoadingStarted(String imageUri, View view) {
            predicts_holder.progress.setVisibility(View.VISIBLE);
        }

        @Override
        public void onLoadingFailed
        (String imageUri, View view, FailReason failReason) {
            predicts_holder.progress.setVisibility(View.GONE);
        }

        @Override
        public void onLoadingComplete
    (String imageUri, View view, Bitmap loadedImage) {
            predicts_holder.progress.setVisibility(View.GONE);
        }
    });
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
predicts_holder.cardText.setTextAppearance
(android.R.style.TextAppearance_Material_Small);
    }
    else{
        predicts_holder.cardText.setTextAppearance
(predicts_holder.cardImage.getContext(    ), 
android.R.style.TextAppearance_Material_Small);
    }
    predicts_holder.cardText.setTextSize(10);
}
@Override
public int getItemCount(){
    return cardMakerList.size();
}
}

我也有一个ItemTouchHelperAdapter

public interface ItemTouchHelperAdapter {
boolean onItemMove(int fromPosition, int toPosition);
void onItemDismiss(int position);
}

我在这样的活动中使用它

 ItemTouchHelper.Callback callback = new     
 SimpleItemTouchHelperCallback(predicts_card_adapter);
    ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
    touchHelper.attachToRecyclerView(recyclerView);

我得到的错误是

java.lang.IndexOutOfBoundsException

at java.util.Collections.swap(Collections.java:1937)

at 

ss.sealstudios.com.socialstories.predictsCardAdapter.
onItemMove(predictsCardAdapter.java:33)

at ss.sealstudios.com.socialstories.SimpleItemTouchHelperCallback
.onMove(SimpleItemTouchHelperCallback.java:36)

如果我取消注释

,请在onMove方法中

mAdapter.onItemMove(viewHolder.getAdapterPosition(),   
target.getAdapterPosition());

拖放一半有效,因此我可以将其拖放但不能拖放,并且视图不会移动以适应它 这让我认为它是我的cardMaker列表,但这只是数据库中的列表,有人可以看到我看不到的东西吗?

解决方案

我编辑适配器的onItemMove方法,这样可以避免出现异常并获得正确的有序列表,请参见以下代码:

@Override
public boolean onItemMove(int fromPosition, int toPosition) {
    if (cardMakerList == null || cardMakerList.size() == 0) {
        return;
    }
    if (fromPosition < 0 || fromPosition >= cardMakerList.size()) {
        return;
    }
    if (toPosition < 0 || toPosition >= cardMakerList.size()) {
        return;
    }
    if (fromPosition == toPosition) {
        return;
    }
    T toMoveE = cardMakerList.get(fromPosition);
    if (fromPosition > toPosition) {
        for (int i = fromPosition; i > toPosition; i--) {
            cardMakerList.set(i, cardMakerList.get(i - 1));
        }
    } else {
        for (int i = fromPosition; i < toPosition; i++) {
            cardMakerList.set(i, cardMakerList.get(i + 1));
        }
    }
    cardMakerList.set(toPosition, toMoveE);
    notifyItemMoved(fromPosition, toPosition);
    return true;
}

i followed a tutorial here on how to implement onItemTouchHelper and callback methods when i run my code it works to the point that i can long press and pick up the item but the moment i move it past one of the other items in the list my app will force close with an index out of bounds exception can anybody here help me?

here is my code but it is identical to the code in the tutorial,

Simple Item Touch Helper Callback

public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback 
{

private final predictsCardAdapter mAdapter;

public SimpleItemTouchHelperCallback(predictsCardAdapter adapter){
    mAdapter = adapter;
}

@Override
public boolean isLongPressDragEnabled(){
    return true;
}
@Override
public boolean isItemViewSwipeEnabled(){
    return false;
}

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    int dragFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
    int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;

    return makeMovementFlags(dragFlags,swipeFlags);
}

@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    mAdapter.onItemMove(viewHolder.getAdapterPosition(), 
    target.getAdapterPosition());
    //mAdapter.notifyItemMoved(viewHolder.getAdapterPosition(), 
    //target.getAdapterPosition());
    return true;
}

@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
}

heres my adapter

public class predictsCardAdapter extends   
RecyclerView.Adapter<predictsCardAdapter.MyViewHolder> implements    
ItemTouchHelperAdapter{
private List<addNewCard> cardMakerList;

@Override
public boolean onItemMove(int fromPosition, int toPosition) {
    if (fromPosition < toPosition){
        for (int i = fromPosition; i < toPosition; i++){
            Collections.swap(cardMakerList,i,i+1);
        }
    }else{
        for (int i = fromPosition; i > toPosition; i--){
            Collections.swap(cardMakerList,i,i-1);
        }
    }
    notifyItemMoved(fromPosition,toPosition);
    return true;
}

@Override
public void onItemDismiss(int position) {
cardMakerList.remove(position);
    notifyItemRemoved(position);
}

public class MyViewHolder extends RecyclerView.ViewHolder{
    public TextView cardText, speechText;
    public ImageView cardImage;
    public ContentLoadingProgressBar progress;

    public MyViewHolder(View view){
        super(view);
        cardText = (TextView) view.findViewById(R.id.predictscardText);
        speechText = (TextView) view.findViewById(R.id.predictsspeechText);
        cardImage = (ImageView) view.findViewById(R.id.predictscardimage);
        progress = (ContentLoadingProgressBar)  
        view.findViewById(R.id.predictsprogress);
    }

}
public predictsCardAdapter(List<addNewCard> cardMakerList){
    this.cardMakerList = cardMakerList;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
    View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.predicted_card, parent, false);
    return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder 
(final MyViewHolder predicts_holder, int position) {
    addNewCard cardmaker = cardMakerList.get(position);
    predicts_holder.cardText.setText(cardmaker.getCardName());
    predicts_holder.speechText.setText(cardmaker.getCardName());
    //Drawable d = new  
    BitmapDrawable(Utility.getPhoto(cardmaker.getCardIcon()));

    String url = cardmaker.getCardIcon();
    ImageLoader imageLoader = ImageLoader.getInstance();
    DisplayImageOptions options = new  
    DisplayImageOptions.Builder().cacheInMemory(true)
            .cacheOnDisc(true).resetViewBeforeLoading(true)
            .showImageForEmptyUri(R.drawable.loading_image)
            .showImageOnFail(R.drawable.broken_image).build();

    imageLoader.displayImage
    (url, predicts_holder.cardImage, options, new  
    SimpleImageLoadingListener() {
        @Override
        public void onLoadingStarted(String imageUri, View view) {
            predicts_holder.progress.setVisibility(View.VISIBLE);
        }

        @Override
        public void onLoadingFailed
        (String imageUri, View view, FailReason failReason) {
            predicts_holder.progress.setVisibility(View.GONE);
        }

        @Override
        public void onLoadingComplete
    (String imageUri, View view, Bitmap loadedImage) {
            predicts_holder.progress.setVisibility(View.GONE);
        }
    });
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
predicts_holder.cardText.setTextAppearance
(android.R.style.TextAppearance_Material_Small);
    }
    else{
        predicts_holder.cardText.setTextAppearance
(predicts_holder.cardImage.getContext(    ), 
android.R.style.TextAppearance_Material_Small);
    }
    predicts_holder.cardText.setTextSize(10);
}
@Override
public int getItemCount(){
    return cardMakerList.size();
}
}

i also have a ItemTouchHelperAdapter

public interface ItemTouchHelperAdapter {
boolean onItemMove(int fromPosition, int toPosition);
void onItemDismiss(int position);
}

and i use it in my activity like this

 ItemTouchHelper.Callback callback = new     
 SimpleItemTouchHelperCallback(predicts_card_adapter);
    ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
    touchHelper.attachToRecyclerView(recyclerView);

the error i get is

java.lang.IndexOutOfBoundsException

at java.util.Collections.swap(Collections.java:1937)

at 

ss.sealstudios.com.socialstories.predictsCardAdapter.
onItemMove(predictsCardAdapter.java:33)

at ss.sealstudios.com.socialstories.SimpleItemTouchHelperCallback
.onMove(SimpleItemTouchHelperCallback.java:36)

in the onMove methods if i uncomment the

mAdapter.onItemMove(viewHolder.getAdapterPosition(),   
target.getAdapterPosition());

the drag and drop half works so i can drag it but not drop it and the views dont move to accomodate it which makes me think its my cardMaker list but that is just a list from a database, can anybody see something i cant?

解决方案

I edit the onItemMove method of your adapter ,this can avoid the Exception and get the right ordered list,see below code:

@Override
public boolean onItemMove(int fromPosition, int toPosition) {
    if (cardMakerList == null || cardMakerList.size() == 0) {
        return;
    }
    if (fromPosition < 0 || fromPosition >= cardMakerList.size()) {
        return;
    }
    if (toPosition < 0 || toPosition >= cardMakerList.size()) {
        return;
    }
    if (fromPosition == toPosition) {
        return;
    }
    T toMoveE = cardMakerList.get(fromPosition);
    if (fromPosition > toPosition) {
        for (int i = fromPosition; i > toPosition; i--) {
            cardMakerList.set(i, cardMakerList.get(i - 1));
        }
    } else {
        for (int i = fromPosition; i < toPosition; i++) {
            cardMakerList.set(i, cardMakerList.get(i + 1));
        }
    }
    cardMakerList.set(toPosition, toMoveE);
    notifyItemMoved(fromPosition, toPosition);
    return true;
}

这篇关于在android的recyclerview上实现项目触摸助手的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆