Saya mendapatkan perilaku gulir yang aneh ketika saya menambahkan RecyclerView di dalam NestedScrollView.
Apa yang terjadi adalah bahwa setiap kali scrollview memiliki lebih banyak baris daripada yang dapat ditampilkan di layar, segera setelah aktivitas diluncurkan, NestedScrollView dimulai dengan offset dari atas (gambar 1). Jika ada beberapa item dalam tampilan gulir sehingga semuanya dapat ditampilkan sekaligus, ini tidak terjadi (gambar 2).
Saya menggunakan versi 23.2.0 dari perpustakaan dukungan.
Gambar 1 : SALAH - dimulai dengan offset dari atas
Gambar 2 : BENAR - beberapa item dalam tampilan pendaur ulang
Saya menempelkan di bawah kode tata letak saya:
<?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>
Apakah saya melewatkan sesuatu? Adakah yang tahu bagaimana cara memperbaikinya?
Perbarui 1
Ini berfungsi dengan benar jika saya menempatkan kode berikut ketika menginisialisasi Aktivitas saya:
sv.post(new Runnable() {
@Override
public void run() {
sv.scrollTo(0,0);
}
});
Di mana sv adalah referensi ke NestedScrollView, namun sepertinya ini adalah peretasan.
Perbarui 2
Seperti yang diminta, ini adalah kode adaptor saya:
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());
}
}
Dan inilah ViewHolder saya:
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);
}
}
Dan di sini adalah tata letak setiap item dalam RecyclerView (hanya android.R.layout.simple_spinner_item
- layar ini hanya untuk menunjukkan contoh bug ini):
<?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"
untukRecyclerView
? pertanda jelas adalah "memaksa tata letak Anda untuk pergi ke bawah ... (di mana ia dimulai ketika Anda memiliki 1.295 item? bawah atau hanya offset kecil atas seperti layar pertama)LayoutManager
Jawaban:
Saya memecahkan masalah tersebut dengan menetapkan:
untuk pandangan saya di atas RecyclerView (yang disembunyikan setelah gulir yang tidak diinginkan). Cobalah untuk mengatur properti ini ke LinearLayout Anda di atas RecyclerView atau ke LinearLayout yang merupakan wadah dari RecyclerView (membantu saya dalam kasus lain).
Seperti yang saya lihat di sumber NestedScrollView, ia mencoba memfokuskan anak pertama yang mungkin ada di onRequestFocusInDescendants dan jika hanya RecyclerView yang fokus, ia menang.
Sunting (terima kasih kepada Waran): dan untuk scroll yang lancar jangan lupa atur
yourRecyclerView.setNestedScrollingEnabled(false);
sumber
android:focusableInTouchMode="false"
ke recyclerView sehingga Anda tidak perlu mengatur true untuk semua tampilan lainnya.Dalam Anda
LinearLayout
setelah langsungNestedScrollView
, penggunaanandroid:descendantFocusability
dengan cara berikutEDIT
Karena banyak dari mereka yang mendapatkan jawaban ini bermanfaat, juga akan memberikan penjelasan.
Penggunaan
descendantFocusability
diberikan di sini . Dan sampaifocusableInTouchMode
di sini . Jadi gunakanblocksDescendants
didescendantFocusability
tidak memungkinkan anak untuk mendapatkan fokus sambil menyentuh dan karenanya perilaku yang tidak direncanakan dapat dihentikan.Adapun
focusInTouchMode
, keduanyaAbsListView
danRecyclerView
memanggil metodesetFocusableInTouchMode(true);
dalam konstruktor mereka secara default, sehingga tidak diperlukan untuk menggunakan atribut itu dalam layout XML Anda.Dan untuk
NestedScrollView
metode berikut digunakan:Di sini,
setFocusable()
metode digunakan sebagai gantisetFocusableInTouchMode()
. Tetapi menurut posting ini ,focusableInTouchMode
harus dihindari kecuali untuk kondisi tertentu karena merusak konsistensi dengan perilaku normal Android. Gim adalah contoh bagus aplikasi yang dapat memanfaatkan properti mode sentuh dengan baik. MapView, jika digunakan dalam layar penuh seperti pada Google Maps, adalah contoh bagus lainnya di mana Anda dapat menggunakan fokus pada mode sentuh dengan benar.sumber
blocksDescendants
untuk memblokir semua fokus keturunan. Saya tidak yakin, tetapi cobalahbeforeDescendants
recyclerView.setFocusable(false); nestedScrollView.requestFocus();
di dalam LinearLayout Bekerja untuk saya.
sumber
Saya memiliki masalah yang sama dan tersedot dengan memperpanjang NestedScrollView dan menonaktifkan anak-anak yang fokus. Untuk beberapa alasan, RecyclerView selalu meminta fokus bahkan ketika saya baru saja membuka dan menutup laci.
sumber
RecyclerView
pemegang EditText di dalamnya .Dalam kasus saya, kode ini memecahkan masalah saya
Tata letak saya berisi tata letak induk sebagai NestedScrollView yang memiliki LinearLayout anak. LinearLayout memiliki orientasi "vertikal" dan childs RecyclerView dan EditText. Referensi
sumber
Saya punya dua tebakan.
Pertama: Coba letakkan baris ini di NestedScrollView Anda
Kedua: Gunakan
sebagai tampilan orang tua Anda Suka ini
Solusi terakhir saya. Aku bersumpah :)
sumber
Masalah ini muncul karena daur ulang tampilan Fokus.
Secara otomatis semua fokus hilang untuk mendaur ulang tampilan jika ukurannya memperluas ukuran layar.
menambahkan
android:focusableInTouchMode="true"
untuk ChildView pertama sepertiTextView
,Button
dan sebagainya (Tidak padaViewGroup
sepertiLinear
,Relative
dan Jadi pada) masuk akal untuk memecahkan masalah tapi API Level 25 dan di atas solusi tidak bekerja.Cukup tambahkan 2 baris ini di ChildView Anda
TextView
,Button
dan Sebagainya (TidakViewGroup
sukaLinear
,Relative
dan Sebagainya )Saya baru saja menghadapi masalah ini pada API level 25. Saya harap orang lain tidak membuang waktu dalam hal ini.
Untuk Pengguliran yang Halus Pada RecycleView tambahkan baris ini
tetapi menambahkan attiributes ini hanya berfungsi dengan API level 21 atau lebih tinggi. Jika Anda ingin agar pengguliran bekerja di bawah API level 25 maka tambahkan baris ini di kelas Anda
sumber
Dalam kode Java, setelah menginisialisasi recyclerView Anda dan mengatur adaptor, tambahkan baris ini:
Anda juga dapat mencoba untuk membungkus tata letak dengan relatifLayout sehingga pandangan tetap di posisi yang sama tetapi recyclerView (yang gulir) pertama dalam hierarki xml. Saran terakhir upaya putus asa: p
sumber
Karena saya terlambat merespons, tetapi dapat membantu orang lain. Cukup gunakan versi di bawah atau lebih tinggi di build.gradle tingkat aplikasi Anda dan masalah ini dihapus.
sumber
untuk menggulir ke atas, panggil saja ini di
setcontentview
:sumber
Cukup tambahkan
android:descendantFocusability="blocksDescendants"
pada ViewGroup di dalam NestedScrollView.sumber