NotifyItemChanged() сделать прокрутку RecyclerView и перейти к UP

У меня есть RecycleView с адаптером, который отображает список серверов и пользователь должен выбрать один сервер.

когда я вызываю notifyItemChanged (previousPosition) внутри метода onClick() чтобы старый сервер не был выбран и выбран новый сервер, которые заставляют список RecycleView подпрыгивать точно в середине списка.

и эта проблема возникает, когда я нажимаю один из последних двух или трех серверов внутри списка RecycleView

вот код моего RecyclerView.Adapter:

public class ServerAdapter extends RecyclerView.Adapter<ServerAdapter.ServerViewHolder> {

    private List<Server> listServers = new ArrayList<>();
    private int[] icons = new int[]{R.drawable.server1,R.drawable.server2,R.drawable.server3,R.drawable.server4,R.drawable.server5,R.drawable.server6,R.drawable.offline};
    private int selected = 0;
    private int previousSelected = 0;

    public ServerAdapter(List<Server> listServers){
        this.listServers = listServers;
    }

    @Override
    public ServerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.server_relative_layout,parent,false);
        return new ServerViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ServerViewHolder holder, final int position) {
        if(position == selected){
            holder.getBackground().setSelected(true);
        }else{
            holder.getBackground().setSelected(false);
        }
        holder.getBackground().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(position != selected){
                    previousSelected = selected;
                    selected = position;
                    holder.getBackground().setSelected(true);
                    notifyItemChanged(previousSelected);
                }
            }
        });
        holder.getImageServer().setImageResource(icons[position%6]);
        holder.getTextNameServer().setText(listServers.get(position).getName());
        holder.getTextConnected().setText(listServers.get(position).getUrl());
    }

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

    public class ServerViewHolder extends RecyclerView.ViewHolder{
        private ImageView imageServer;
        private TextView textNameServer;
        private TextView textConnected;
        private View background;
        public ServerViewHolder(View itemView) {
            super(itemView);
            imageServer = (ImageView)itemView.findViewById(R.id.imageServer);
            textNameServer = (TextView)itemView.findViewById(R.id.textNameServer);
            textConnected = (TextView)itemView.findViewById(R.id.textConnected);
            background = itemView;
        }

        public ImageView getImageServer() {
            return imageServer;
        }

        public TextView getTextConnected() {
            return textConnected;
        }

        public TextView getTextNameServer() {
            return textNameServer;
        }

        public View getBackground() {
            return background;
        }
    }
}

любые решения для решения этой проблемы? спасибо.

Проблема произошла именно тогда, когда я определяю высоту макета и не позволяю ей wrap_content

<android.support.v7.widget.RecyclerView
    android:layout_width="wrap_content"
    android:layout_height="400dp"
    android:id="@+id/serverRecyclerView"
    android:layout_margin="10dp"
/>

или когда я помещаю его под что-то для примера:

<android.support.v7.widget.RecyclerView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/serverRecyclerView"
    android:layout_margin="10dp"
    android:layout_below="@+id/image"/>

мой код точно:

<android.support.v7.widget.RecyclerView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/serverRecyclerView"
    android:layout_margin="10dp"
    android:layout_alignTop="@+id/imageBall"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:layout_toRightOf="@+id/camera"
    android:layout_toEndOf="@+id/camera"/>

Ответ 1

Похоже, что это ошибка: https://code.google.com/p/android/issues/detail?id=203574

Лучшим обходным решением, похоже, является ответ Барта, чтобы установить свойство AutoMeasure для RetyclerView LinearLayoutManager равным false.

  LinearLayoutManager llm = new LinearLayoutManager(context);
  llm.setAutoMeasureEnabled(false);       
  recyclerView.setLayoutManager(llm);

У установленного FixedSize на истинное решение было слишком много побочных эффектов...

RecyclerView.setHasFixedSize(истина)

Ответ 2

Я не знаю, почему, но я использовал:

RecyclerView.setHasFixedSize(true)

Это сработало для меня. Надеюсь, это поможет.

Ответ 3

 android:descendantFocusability="blocksDescendants"

Ответ 4

RecyclerView.ItemAnimator animator = myRecyclerListView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
    ((SimpleItemAnimator)animator).setSupportsChangeAnimations(false);
}

Ответ 5

для всех, кто сталкивается с этой проблемой, попробуйте использовать

yourRecyclerView.notifyItemChanged(int position, Object payload);

Этот трюк сделал для меня.

Использование

setAutoMeasureEnabled(false);

также работал, но в некоторых случаях рециклирования выглядел странно. Удачи!

Ответ 6

Я столкнулся с подобной проблемой, просто позабочусь о файле макета xml.
Не используйте layout_below, layout_above или другие аналогичные свойства в представлении родительского вида RecyclerView или RecyclerView.
Вы можете использовать LinearLayout weight, layout_marginBottom или sth для достижения layout_below или другой.

Ответ 7

Мой RecyclerView был внутри ConstraintLayout, и у меня также была такая проблема, и вызов setAutoMeasureEnabled(false) из RecyclerView LayoutManager не устранил проблему для меня, более того, этот метод устарел в версии 28.0.0. Что я сделал, так это то, что я обернул свой RecyclerView с RelativeLayout, и теперь он работает как шарм. Как упоминалось в bugtracker, эта "проблема" является намеренным поведением в LinearLayout и не будет исправлена. Поэтому, если это возможно, просто оберните ваш RecyclerView примерно так:

<RelativeLayout
    android:id="@+id/container_messages_list"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:background="@drawable/chat_back_pattern"
    app:layout_constraintBottom_toTopOf="@+id/bottom_view"
    app:layout_constraintTop_toBottomOf="@+id/toolbar">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/messages_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v7.widget.RecyclerView>
</RelativeLayout>

Ответ 8

Поздний ответ лучше, чем ничего, если вы используете NestedScrollView в качестве родительского представления RecyclerView, вы должны удалить его.

Ответ 9

У меня была похожая проблема, и я попробовал все решения, перечисленные выше, но никто не работал. Я уже дополнял "Payloads" до "notifyItemChanged (position, payloads)", потому что мне просто нужно было "загрузить" значение флажка, чтобы я передавал значение внутри "Payloads", не вызывая обновление всего видоискателя. Это решение работало для всех держателей представлений в моем представлении переработчика, за исключением последнего (и, вероятно, для всех "переработанных" я имею в виду тех, кто вспоминает "onBindViewHolder", "перерабатывая" существующее представление). Я думаю, что использование "notifyItemChanged" сработает, если у вас есть только обзор реселлера, и я также думаю, что эта проблема "автоматической прокрутки" возникает при использовании вложенных представлений прокрутки & взгляды переработчика.

Я был в случае выставлен "raed", поэтому "ScroolView → RecyclerView ->" n "x RecyclerView". У меня есть просмотр scroolview, который содержит обзор переработчика, чьи держатели могут содержать представления переработчика.

Удалить родительский ScrollView - это действительно странное решение, и я не смог его использовать, поэтому я установил "onStopNestedScroll" внутри "ScrollView", а не внутри RecyclerView.

Лично я использовал это программно перед частью кода, которая вызывает метод notifyItemChanged, выполнив:

msvContainer.onStopNestedScroll(mRecyclerView);

Где "msvContainer" - это мой ScrollView, который содержит RecyclerView, а "mRecyclerView" - это мой RecyclerView, содержащийся в ScrollView. Этот способ сработал на 99%, потому что в первый раз, когда я вызываю "notifyItemChanged", представление прокручивается вверх только для ScrollView, поэтому оно скрывает кнопку внутри моего ScrollView, которая находится ниже моего RecyclerView, но не прокручивает элементы RecyclerView. После первого вызова notifyItemChanged работает правильно.

Я нашел это призвание:

msvContainer.stopNestedScroll();

тоже работает. Но я предлагаю использовать первый метод с целевым представлением, если у вас есть несколько вложенных представлений прокрутки.

В любом случае вам следует вызывать "startNestedScroll" после того, как вы исчерпали критическую часть повторного обновления держателя представления, потому что целевое представление, поэтому в моем случае RecyclerView не будет прокручиваться, пока вы не вызовете этот метод, поэтому он не будет перерабатывать его Держатели просмотра тоже.

(В моем случае, если у меня есть несколько представлений Recycler в родительском представлении Recycler внутри родительского представления Scroll, если мне нужно было вызвать "notifyItemChanged" внутри самого внутреннего представления Recycler, я бы использовал метод "stopNestedScroll" для каждого родительского представления, а затем повторно активировал прокрутку после критической части прокрутки)

Надеюсь, что это полезно, приятного кодирования! до свидания