web-dev-qa-db-fra.com

RecyclerView défilement sur insertion

J'essaie d'utiliser RecyclerView pour créer une application de discussion. J'utilise une LinearLayoutManager avec setReverseLayout(true)

Lorsque je fais défiler l'écran jusqu'en bas (le jeu de données start = message le plus récent) et qu'un nouveau message est inséré dans le jeu de données, l'élément apparaît au bas de la liste, comme prévu (la vue défile pour faire de la place pour le nouvel article).

Le problème que j'ai est lorsque j'ai fait défiler pour voir les messages plus anciens. Lorsqu'un nouveau message est inséré au début du jeu de données, la vue est défilée d'environ une hauteur de message, même si ce message n'est même pas rendu car il est en dehors de la plage de la fenêtre d'affichage.

Comment puis-je conserver le comportement de défilement lorsque la vue défile jusqu'en bas, mais le désactiver lorsque j'ai fait défiler les messages plus anciens?

UPDATE: J'ai également créé une petite application dans laquelle ce problème est reproduit: https://github.com/ehehhh/RecyclerViewProblem

UPDATE 2: J'ai mis à jour le correctif qui a également fonctionné pour le dépôt.

Code pertinent (espérons-le):

compile 'com.Android.support:recyclerview-v7:24.2.0'

XML: 

<Android.support.v7.widget.RecyclerView
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:clipToPadding="false"
            Android:paddingBottom="8dp"
            Android:paddingTop="8dp"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

RecyclerView code d'initialisation:

layoutManager = new LinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
layoutManager.setReverseLayout(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setScrollContainer(true);
recyclerView.setLayoutAnimation(null);
recyclerView.setItemAnimator(null);
adapter = new ChatAdapter(...);
recyclerView.setAdapter(adapter);

Adaptateur:

public class ChatAdapter extends RecyclerView.Adapter<ChatViewHolder> {

    private List<MessageWrapper> dataset;

    public ChatAdapter(List<MessageWrapper> dataset, ...) {
        this.dataset = dataset;
        setHasStableIds(true);
    }

    ...

    @Override
    public long getItemId(int position) {
        return dataset.get(position).getId();
    }

    @Override
    public int getItemCount() {
        return dataset.size();
    }

    public void datasetChanged(List<MessageWrapper> dataset) {
        this.dataset = dataset;
        notifyDataSetChanged();
    }
}

Lorsqu'un nouvel élément est ajouté à l'ensemble de données, j'appelle simplement la méthode datasetChanged dans l'adaptateur.

18
ehehhh

dans la vue Recycler, l’utilisation de notifyDataSetChanged est redondante si vous savez que les éléments ont été modifiés vous pouvez utiliser 

notifyItemInserted(position) 

dans ce cas particulier ce qui a fonctionné était

 notifyItemInserted(0);

ou

 notifyItemRangeInserted(positionStart, newItems.size() - 1)

cela ne fera que relier les vues dans cette plage 

check https://developer.Android.com/reference/Android/support/v7/widget/RecyclerView.Adapter.html#notifyItemInserted(int)

4
Hala.M

J'ai eu un problème similaire. J'étais en train de créer une application de chat et mon RecyclerView affichait toujours des lignes du haut, et je voulais que ce dernier soit affiché en bas pour afficher le dernier message inséré. C’est ce qui a fonctionné pour moi, a ajouté recyclerView.scrollToPosition(messages.size()-1) dans ChildEventListener:

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private MessageAdapter mMessageAdapter;
    private List<Message> messages;

    private FirebaseDatabase mFirebaseDatabase;
    private DatabaseReference mMessagesDatabaseRef;

    ....


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mFirebaseDatabase = FirebaseDatabase.getInstance();
        mMessagesDatabaseRef = mFirebaseDatabase.getReference().child("messages");


        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);


        // Initialize message ListView and its adapter
        messages = new ArrayList<>();
        mMessageAdapter = new MessageAdapter(messages);



        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
        recyclerView.setLayoutManager(mLayoutManager);

        recyclerView.setAdapter(mMessageAdapter);

       .....   

        mMessagesDatabaseRef.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {


                messages.add(dataSnapshot.getValue(Message.class));

                recyclerView.scrollToPosition(messages.size()-1);
                mMessageAdapter.notifyDataSetChanged();

            }

            ......


        });

    }



}
0
Nemus