correct way to implement item touch helper on recy

2019-06-13 19:08发布

问题:

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?

回答1:

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