it-swarm.com.de

RecyclerView-Bildlauf auf dem Einsatz

Ich versuche, RecyclerView zum Erstellen einer Chat-Anwendung zu verwenden. Ich verwende eine LinearLayoutManager mit setReverseLayout(true)

Wenn ich ganz nach unten gescrollt bin (dies ist der Datensatz start = neueste Nachricht) und eine neue Nachricht in den Datensatz eingefügt wird, wird das Element wie erwartet am unteren Ende der Liste angezeigt (die Ansicht wird nach oben verschoben, um Platz zu schaffen für den neuen Artikel).

Das Problem, das ich habe, ist, wenn ich nach oben gescrollt bin, um die älteren Nachrichten zu sehen. Wenn eine neue Nachricht am Anfang des Datasets eingefügt wird, wird die Ansicht um etwa eine Nachrichtenhöhe nach oben verschoben, obwohl diese Nachricht nicht einmal gerendert wird, da sie sich außerhalb des Bereichs des Viewports befindet.

Wie kann ich das Bildlaufverhalten beibehalten, wenn die Ansicht nach unten gescrollt wird, aber deaktivieren, wenn ich zu den älteren Nachrichten gescrollt habe?

UPDATE: Ich habe auch eine kleine App erstellt, in der dieses Problem reproduziert wird: https://github.com/ehehhh/RecyclerViewProblem

UPDATE 2: Ich habe den Fix, der auch beim Repo funktionierte, festgeschrieben.

Relevanter Code (hoffentlich):

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 Init-Code:

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

Adapter:

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

Wenn ein neues Element zum Datensatz hinzugefügt wird, rufe ich einfach die datasetChanged-Methode im Adapter auf.

18
ehehhh

in der Recycler-Ansicht ist notifyDataSetChanged überflüssig, wenn Sie wissen, dass die Elemente geändert wurden 

notifyItemInserted(position) 

in diesem speziellen Fall funktionierte das

 notifyItemInserted(0);

oder

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

dadurch werden nur die Ansichten in diesem Bereich erneut gebunden 

Überprüfen Sie https://developer.Android.com/reference/Android/support/v7/widget/RecyclerView.Adapter.html#notifyItemInserted(int)

4
Hala.M

Ich hatte ein ähnliches Problem. Ich habe gerade eine Chat-Anwendung erstellt, und in RecyclerView wurden immer Zeilen von oben angezeigt. Ich wollte, dass die letzte eingefügte Nachricht unten angezeigt wird. Das hat bei mir funktioniert, recyclerView.scrollToPosition(messages.size()-1) hinzugefügt in 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