RecyclerView et ItemTouchHelper faites glisser le doigt pour enlever problème
Je suis en train de mettre en œuvre "glisser pour supprimer les" fonctionnalité via RecyclerView et ItemTouchHelper. J'ai un problème étrange et je ne peut pas localiser le problème pour la vie de moi. J'ai glisser un élément de distance à partir du haut (pas le premier), il s'en va, c'est très bien. Quand je scroll loin et de revenir, il y a un artefact dans la ligne au-dessus glissée à l'écart de l'élément. Semble que la ligne n'est pas établi (ou peut-être est x traduit?). La vidéo montre le problème.
Étapes de la vidéo:
- J'coup l'écart de l'Élément 2
- Faites défiler vers le bas
- Revenir
- Point 1 n'est plus visible
- J'ai faites défiler vers le bas de nouveau
- Je faire défiler en arrière
- Tout est bien maintenant
- De nouveau, mais avec un tiers (pas le second) de l'élément à partir du haut, même problème
- Encore une fois, avec le très premier élément, pas de problème
Code: (ensemble github exemple d'application ici)
public class MainActivity extends AppCompatActivity {
RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(new TestAdapter());
setUpItemTouchHelper();
}
private void setUpItemTouchHelper() {
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
int swipedPosition = viewHolder.getAdapterPosition();
TestAdapter adapter = (TestAdapter)mRecyclerView.getAdapter();
adapter.remove(swipedPosition);
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(mRecyclerView);
}
static class TestAdapter extends RecyclerView.Adapter {
List<String> items;
public TestAdapter() {
items = new ArrayList<>();
//this should give us a couple of screens worth
for (int i=1; i<= 15; i++) {
items.add("Item " + i);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new TestViewHolder(parent);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
TestViewHolder viewHolder = (TestViewHolder)holder;
String item = items.get(position);
viewHolder.titleTextView.setText(item);
}
@Override
public int getItemCount() {
return items.size();
}
public void remove(int position) {
if (position < 0 || position >= items.size()) {
return;
}
items.remove(position);
notifyItemRemoved(position);
}
}
static class TestViewHolder extends RecyclerView.ViewHolder {
TextView titleTextView;
public TestViewHolder(ViewGroup parent) {
super(LayoutInflater.from(parent.getContext()).inflate(R.layout.row_view, parent, false));
titleTextView = (TextView) itemView.findViewById(R.id.title_text_view);
}
}
}
EDIT:
J'ai un hack qui élimine ce problème, mais je veux savoir la cause et comment puis-je résoudre le problème. Le hack est l'appel de notifyDataSetChanged() mais après les animations sont fait (sinon, l'animation devient fin). Fondamentalement, j'ai ajouter un ItemDecorator et de comprendre qu'une animation est terminée.
mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
boolean running;
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (parent.getItemAnimator().isRunning()) {
running = true;
}
if (running == true && !parent.getItemAnimator().isRunning()) {
//first time it's not running
running = false;
parent.getAdapter().notifyDataSetChanged();
}
super.onDraw(c, parent, state);
}
});
Vous devez vous connecter pour publier un commentaire.
Essayez d'ajouter
notifyDataSetChanged()
dans votre méthode removenotifyItemRemoved(position)
informe le RecyclerView Carte de données dans la carte a été retirée à une position particulière.notifyDataSetChanged()
informe le joint d'observateurs que le sous-jacent de données a été modifiée et une Vue reflétant l'ensemble de données doit actualiser lui-même.Mise à JOUR
Essayez d'ajouter
mRecyclerView.removeViewAt(position);
avantnotifyItemRemoved(position);
Cela ne perturbera pas l'animation.Mise à JOUR: 23.1.1 corrige le bug. N'utilisez pas de 23.1.0.
Ressemble à ce bug est une régression dans le recycleur vue soutien de la bibliothèque. Je pense que c'est le s'engager la cause, mais n'est pas toujours 100% comprendre la situation afin de ne pas me tenir sur ce point.
Le bug se manifeste avec
com.android.support:recyclerview-v7
version23.1.0
mais pas avec23.0.1
ou22.2.1
Je vais essayer de trouver un endroit correct pour le rapport et poste le lien dans le commentaire de cette réponse.
Je tiens à vous suggérons de voir ce lien parce que c'est la façon la plus simple pour implémenter cette fonctionnalité
Faites glisser et glisser avec RecyclerView à l'aide de ItemTouchHelper
J'ai eu un problème similaire avec glisser à réorganiser. Le RecyclerView a été en laissant un "fantôme" de la vue juste déplacé sous le point de vue qui s'est déplacé dans cette position. Aléatoire de la réponse de l'ajout de 'notifyDataSetChanged()' pour mon onItemMoved méthode fonctionne, mais qui détruit l'échange d'animation. Le problème a été résolu quand j'ai couru notifyDataSetChanged après un court délai: