Android. Вложенный просмотрщик повторяет прокрутку при обходе родительского переработчика - PullRequest
0 голосов
/ 18 января 2019

Обновление: Я решил создать репозиторий github с этой проблемой, чтобы любой мог попытаться воспроизвести его и попытаться исправить. https://github.com/LolusKekus/NestsedRecyclerScrollItselfChallenge


Update2 Потратив некоторое время на исследования, я наконец-то нашел решение, отвечающее моим требованиям.

Все, что мне нужно, это расширить класс повторного использования класс и переопределить метод forcusSearch следующим образом:

    @Override
    public View focusSearch(View focused, int direction) {
        View view = super.focusSearch(focused, direction);
        Log.d(TAG, "focusSearch: ");
        if (view instanceof CRecyclerView) {
            int position = ((LinearLayoutManager)((CRecyclerView) view).getLayoutManager()).findFirstVisibleItemPosition();
            view = ((CRecyclerView) view).getLayoutManager().findViewByPosition(position);
        }

        return view;
    }

CRecyclerView - мой расширенный RecyclerView.

В нормальных условиях focusSearch возвращает мой просмотр товара, и все в порядке. Но по некоторым причинам focusSearch возвращает экземпляр RecyclerView, и в результате у меня появляется эта раздражающая автопрокрутка. Я не копаюсь глубже в этой проблеме, потому что у меня есть все, что мне нужно. Но если кто-то может, я буду признателен.


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

Это выглядит так. Перед прокруткой представим, что селектор на 31:

_____________
|31 32 33 34|
|41 42 43 44|
|51 52 53 54|
_____________

теперь нажмите на dpad (я работаю на Android TV):

_____________
|24 25 26 27|
|31 32 33 34|
|41 42 43 44|
_____________

Появляется скрытое окно переработчика, связывает и прокручивает до 24 элементов. Но это не должно быть! Выбранный элемент должен быть 21! И так до вершины вертикального рециклера ... 14 ... 04 ...

Я заметил, что вложенные перезаписи прокручиваются только до последнего видимого элемента на нем.

это поведение появляется после "com.android.support:recyclerview-v7:24.2.1"

Теперь я использую "com.android.support:recyclerview-v7:27.1.1" и столкнулся с этой проблемой.

Активность:

public class MainActivity extends AppCompatActivity {
    List<String> hDataset;
    List<Integer> vDataset;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = this;
        hDataset = new ArrayList<>();
        for (int i=0; i<hItemsCount; i++) {
            hDataset.add(String.format("lolKek Cheburek %d", i));
        }

        vDataset = new ArrayList<>();
        for (int i=0; i<vItemsCount; i++) {
            vDataset.add(i);
        }

        vRecyclerView = findViewById(R.id.vRecyclerView);
        vRecyclerView.setHasFixedSize(true);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        vRecyclerView.setLayoutManager(layoutManager);
        vRecyclerView.setAdapter(new VAdapter(vDataset, hDataset, context));
}

Вертикальный адаптер:

public class VAdapter extends RecyclerView.Adapter<VAdapter.MyVertHolder>() {
    private List<String> hDataset;
    private Context context;

    public VAdapter(List<String> hDataset, List<String> vDataset, Context context) {
       this.hDataset = hDataset;
       this.vDataset = vDataset;
       this.context = context;
    }

    public static class MyVertHolder extends RecyclerView.ViewHolder {
        RecyclerView hRecyclerView;

        public MyVertHolder(final View itemView) {
            super(itemView);
            hRecyclerView = itemView.findViewById(R.id.hRecyclerView);
        }

        public void setAdapter(HAdapter adapter) {
            hRecyclerView.setAdapter(adapter);
        }

        public void setLayoutManager(LinearLayoutManager layoutManager) {
            hRecyclerView.setLayoutManager(layoutManager);
        }
    }

    @NonNull
    @Override
    public MyVertHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater
            .from(parent.getContext())
            .inflate(R.layout.v_item_view, parent, false);

        MyVertHolder holder = new MyVertHolder(itemView);
        holder.setAdapter(new HAdapter(hDataset));
        holder.setLayoutManager(new LinearLayoutManage(context, LinearLayoutManager.HORIZONTAL, false));
        return holder;
    }

    @Override
    public void onBindViewHolder(final @NonNull MyVertHolder holder, int position) {
        ... some bindings
    }
}

Горизонтальный адаптер:

class HAdapter extends RecyclerView.Adapter<HAdapter.MyHolder> {
    private List<String> dataset;
    public HAdapter(List<String> dataset) {
        this.dataset = dataset;
    }

    public static class MyHolder extends RecyclerView.ViewHolder {

        private TextView tvItemText;

        public MyHolder(FrameLayout itemView) {
            super(itemView);
            tvItemText = itemView.findViewById(R.id.tvItemText);
        }
    }

@Override
    public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        FrameLayout itemView = (FrameLayout) LayoutInflater
.from(parent.getContext()).inflate(R.layout.item_view, parent, false);
        return new MyHolder(itemView);
    }

    @Override
    public void onBindViewHolder(final @NonNull MyHolder holder, final int position) {
        holder.setItemText(dataset.get(position));
}

макет основной деятельности:


<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="MainActivity">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/vRecyclerView"
            android:orientation="vertical"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
</FrameLayout>

вертикальный вид элемента макета:

<?xml version="1.0" encoding="utf-8"?>

<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@color/colorAccent"
    android:id="@+id/hRecyclerView"
    android:focusableInTouchMode="true"
    android:focusable="true"
    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

макет вида горизонтального элемента:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/flContainer"
    android:layout_margin="5dp"
    android:focusable="true"
    android:layout_width="250dp"
    android:layout_height="150dp">

    <TextView
        android:id="@+id/tvItemText"
        android:textColor="@color/white"
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</FrameLayout>

Я хочу прекратить это раздражающее поведение с автопрокруткой. Спасибо.

Ответы [ 3 ]

0 голосов
/ 18 января 2019

Добавьте это к вашему классу HAdapter

private View.OnKeyListener mOnKeyListener = new View.OnKeyListener() {
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
       RecyclerView rv = (RecyclerView) v.getParent();
       if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
           rv.getLayoutManager().scrollToPosition(0);
       }          
       return false;
    }
};

и

itemView.setOnKeyListener(mOnKeyListener);

в метод onCreateViewHolder вашего класса HAdapter.

Этот предназначен только дляклавиша со стрелкой вверх, вы можете расширить предложение if, чтобы включить также клавишу со стрелкой вниз.

Редактировать:

В качестве альтернативы, вы можете поместить это в предложение ifвместо вызова метода scrollToPosition:

private View.OnKeyListener mOnKeyListener = new View.OnKeyListener() {
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        RecyclerView rv = (RecyclerView) v.getParent();
        if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
           int pos = rv.getLayoutManager().getPosition(v);
           rv.scrollBy(-((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, pos * width, mContext.getResources().getDisplayMetrics())), 0);
        }          
        return false;
    }
};

где width - ширина элемента (ов) RecyclerView в dp.

Предложение:

Я бы переместил методы setAdapter и setLayoutManager из класса ViewHolder в тело класса HAdapter.(Сделайте то же самое в классе VAdapter). Они не имеют ничего общего с шаблоном ViewHolder.Шаблон ViewHolder используется для оптимизации производительности путем кэширования представлений, возвращаемых функцией findViewById ()

Edit 2:

Добавьте этот класс в ваш проект:

https://raw.githubusercontent.com/wuakitv/leanback-v17/master/src/android/support/v17/leanback/widget/PersistentFocusWrapper.java

Затем измените ваш v_item_view.xml:

<?xml version="1.0" encoding="utf-8"?>

<lolkek.example.com.testrecycler.PersistentFocusWrapper
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <android.support.v7.widget.RecyclerView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/hRecyclerView"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</lolkek.example.com.testrecycler.PersistentFocusWrapper>

Я протестировал его, и он работает.

0 голосов
/ 18 января 2019

Вам необходимо сохранить состояние / положение каждого горизонтального адаптера RecyclerView. Когда вы прокручиваете вертикальный RecyclerView, вы, очевидно, рециркулируете виды, поэтому, если состояние горизонтального адаптера не сохраняется, при прокрутке вертикального RecyclerView вы окажетесь в каком-то положении для прокручиваемого горизонтального RecyclerView, отличного от того, который вы используете. были до того, как вид был переработан.

0 голосов
/ 18 января 2019

пожалуйста, удалите

android:focusableInTouchMode="true"
android:focusable="true"

и дайте мне знать статус.

...