Я получаю странное поведение при прокрутке, когда добавляю RecyclerView внутри NestedScrollView.
Что происходит, так это то, что всякий раз, когда в scrollview есть больше строк, чем может быть показано на экране, как только действие запускается, NestedScrollView запускается со смещением сверху (изображение 1). Если в режиме прокрутки есть несколько элементов, чтобы их можно было показать сразу, этого не происходит (изображение 2).
Я использую версию 23.2.0 библиотеки поддержки.
Изображение 1 : НЕПРАВИЛЬНО - начинается со смещения сверху
Изображение 2 : ПРАВИЛЬНО - несколько элементов в представлении ресайклера
Я вставляю ниже свой код макета:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title:"
style="@style/TextAppearance.AppCompat.Caption"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/bodyPadding"
style="@style/TextAppearance.AppCompat.Body1"
android:text="Neque porro quisquam est qui dolorem ipsum"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Subtitle:"
style="@style/TextAppearance.AppCompat.Caption"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/TextAppearance.AppCompat.Body1"
android:padding="@dimen/bodyPadding"
android:text="Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:focusable="false"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
Я что-то упускаю? Кто-нибудь знает, как это исправить?
Обновление 1
Он работает правильно, если я помещаю следующий код при инициализации Activity:
sv.post(new Runnable() {
@Override
public void run() {
sv.scrollTo(0,0);
}
});
Где sv - это ссылка на NestedScrollView, но это похоже на взлом.
Обновление 2
По запросу, вот мой код адаптера:
public abstract class ArrayAdapter<T, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> {
private List<T> mObjects;
public ArrayAdapter(final List<T> objects) {
mObjects = objects;
}
/**
* Adds the specified object at the end of the array.
*
* @param object The object to add at the end of the array.
*/
public void add(final T object) {
mObjects.add(object);
notifyItemInserted(getItemCount() - 1);
}
/**
* Remove all elements from the list.
*/
public void clear() {
final int size = getItemCount();
mObjects.clear();
notifyItemRangeRemoved(0, size);
}
@Override
public int getItemCount() {
return mObjects.size();
}
public T getItem(final int position) {
return mObjects.get(position);
}
public long getItemId(final int position) {
return position;
}
/**
* Returns the position of the specified item in the array.
*
* @param item The item to retrieve the position of.
* @return The position of the specified item.
*/
public int getPosition(final T item) {
return mObjects.indexOf(item);
}
/**
* Inserts the specified object at the specified index in the array.
*
* @param object The object to insert into the array.
* @param index The index at which the object must be inserted.
*/
public void insert(final T object, int index) {
mObjects.add(index, object);
notifyItemInserted(index);
}
/**
* Removes the specified object from the array.
*
* @param object The object to remove.
*/
public void remove(T object) {
final int position = getPosition(object);
mObjects.remove(object);
notifyItemRemoved(position);
}
/**
* Sorts the content of this adapter using the specified comparator.
*
* @param comparator The comparator used to sort the objects contained in this adapter.
*/
public void sort(Comparator<? super T> comparator) {
Collections.sort(mObjects, comparator);
notifyItemRangeChanged(0, getItemCount());
}
}
А вот и мой ViewHolder:
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView txt;
public ViewHolder(View itemView) {
super(itemView);
txt = (TextView) itemView;
}
public void render(String text) {
txt.setText(text);
}
}
А вот расположение каждого элемента в RecyclerView (это просто android.R.layout.simple_spinner_item
- этот экран предназначен только для демонстрации примера этой ошибки):
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
style="?android:attr/spinnerItemStyle"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:textAlignment="inherit"/>
android:focusableInTouchMode="false"
forRecyclerView
? что-то явно означает «заставляет ваш макет идти вниз ... (где он начинается, когда у вас 1295 элементов? снизу или просто небольшое верхнее смещение, как на первом экране)»LayoutManager
Ответы:
Я решил такую проблему, установив:
на мой взгляд выше RecyclerView (который был скрыт после нежелательной прокрутки). Попробуйте установить это свойство для своего LinearLayout над RecyclerView или для LinearLayout, который является контейнером RecyclerView (помог мне в другом случае).
Как я вижу в источнике NestedScrollView, он пытается сфокусировать первый возможный дочерний элемент в onRequestFocusInDescendants, и если только RecyclerView фокусируется, он выигрывает.
Изменить (спасибо Waran): и для плавной прокрутки не забудьте установить
yourRecyclerView.setNestedScrollingEnabled(false);
источник
android:focusableInTouchMode="false"
recyclerView, чтобы вам не нужно было устанавливать true для всех других представлений.В вашем
LinearLayout
непосредственно послеNestedScrollView
, использованиеandroid:descendantFocusability
следующим образомРЕДАКТИРОВАТЬ
Поскольку многие из них получают этот ответ полезным, также предоставят объяснения.
Использование
descendantFocusability
дается здесь . И , какfocusableInTouchMode
над здесь . Итак, используяblocksDescendants
вdescendantFocusability
do не позволяет ребенку сосредоточиться при прикосновении, и, следовательно, можно остановить незапланированное поведение.Что касается
focusInTouchMode
, обаAbsListView
иRecyclerView
вызывает методsetFocusableInTouchMode(true);
в своем конструкторе по умолчанию, поэтому нет необходимости использовать этот атрибут в ваших макетах XML.И для этого используется
NestedScrollView
следующий метод:Здесь
setFocusable()
метод используется вместоsetFocusableInTouchMode()
. Но, согласно этому сообщению , этогоfocusableInTouchMode
следует избегать, за исключением определенных условий, поскольку это нарушает согласованность с нормальным поведением Android. Игра - хороший пример приложения, которое может эффективно использовать свойство фокусируемого в сенсорном режиме. MapView, если он используется в полноэкранном режиме, как и в Google Maps, является еще одним хорошим примером того, как правильно использовать фокусируемое в сенсорном режиме.источник
blocksDescendants
блокировать фокус всех потомков. Я не уверен, но попробуйтеbeforeDescendants
recyclerView.setFocusable(false); nestedScrollView.requestFocus();
внутри LinearLayout работал у меня.
источник
У меня была такая же проблема, и я решил расширить NestedScrollView и отключить фокусировку детей. По какой-то причине RecyclerView всегда запрашивал фокус, даже когда я только что открывал и закрывал ящик.
источник
RecyclerView
держателей.В моем случае этот код решает мою проблему
Мой макет содержит родительский макет как NestedScrollView, у которого есть дочерний LinearLayout. LinearLayout имеет "вертикальную" ориентацию и дочерние элементы RecyclerView и EditText. Ссылка
источник
У меня две догадки.
Во-первых: попробуйте поместить эту строку в свой NestedScrollView
Во-вторых: используйте
как ваш родительский взгляд Как это
Мое последнее возможное решение. Клянусь :)
источник
Эта проблема возникает из-за повторного просмотра Focus.
Автоматически весь фокус переходит в режим повторного просмотра, если его размер увеличивал размер экрана.
добавление
android:focusableInTouchMode="true"
к первому ChildView какTextView
,Button
и так далее (не наViewGroup
какLinear
,Relative
и так далее) имеет смысл , чтобы решить эту проблему , но API Level 25 и выше решение не работает.Просто добавьте эти 2 строки в вашем ChildView , как
TextView
,Button
и так далее (не наViewGroup
какLinear
,Relative
и так далее)Я только что столкнулся с этой проблемой на уровне API 25. Надеюсь, другие люди не тратят на это время.
Для плавной прокрутки в RecycleView добавьте эту строку
но добавление этих атрибутов работает только с уровнем API 21 или выше. Если вы хотите, чтобы эта сглаживающая прокрутка работала ниже уровня API 25, добавьте эту строку в свой класс
источник
В коде Java после инициализации recyclerView и настройки адаптера добавьте эту строку:
Вы также можете попытаться обернуть макет с помощью relativeLayout, чтобы представления оставались в том же положении, но recyclerView (который прокручивается) первым в иерархии xml. Последнее предложение - отчаянная попытка: p
источник
Поскольку я опаздываю с ответом, но может помочь кому-то другому. Просто используйте версию ниже или выше на уровне вашего приложения build.gradle, и проблема будет устранена.
источник
чтобы прокрутить вверх, просто вызовите это
setcontentview
:источник
Просто добавьте
android:descendantFocusability="blocksDescendants"
ViewGroup внутри NestedScrollView.источник