Pertahankan / Simpan / Kembalikan posisi gulir saat kembali ke ListView

397

Saya sudah lama ListViewbahwa pengguna dapat menggulir di sekitar sebelum kembali ke layar sebelumnya. Ketika pengguna membuka ini ListViewlagi, saya ingin daftar tersebut digulir ke titik yang sama seperti sebelumnya. Ada ide tentang cara mencapai ini?

rantravee
sumber
22
Saya pikir solusi yang disebutkan oleh Eugene Mymrin / Giorgio Barchiesi lebih baik daripada jawaban yang diterima
Mira Weller

Jawaban:

631

Coba ini:

// save index and top position
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : (v.getTop() - mList.getPaddingTop());

// ...

// restore index and position
mList.setSelectionFromTop(index, top);

Penjelasan:

ListView.getFirstVisiblePosition()mengembalikan item daftar paling terlihat. Tetapi item ini mungkin sebagian digulir keluar dari pandangan, dan jika Anda ingin mengembalikan posisi gulir yang tepat dari daftar Anda perlu mendapatkan offset ini. Jadi ListView.getChildAt(0)mengembalikan Viewuntuk item daftar teratas, dan kemudian View.getTop() - mList.getPaddingTop()mengembalikan ofset relatifnya dari atas ListView. Kemudian, untuk mengembalikan ListViewposisi gulir, kita memanggil ListView.setSelectionFromTop()dengan indeks item yang kita inginkan dan offset ke posisi tepi atas dari atas ListView.

ian
sumber
2
Tidak begitu mengerti bagaimana ini bekerja. Saya hanya menggunakan listView.getFirstVisiblePosition () dan mengerti itu, tetapi tidak yakin apa yang terjadi di sini. Apakah ada kemungkinan penjelasan singkat? :)
HXCaine
56
Jadi ListView.getFirstVisiblePosition () mengembalikan item daftar paling terlihat. Tetapi item ini mungkin sebagian digulir keluar dari pandangan, dan jika Anda ingin mengembalikan posisi gulir yang tepat dari daftar Anda perlu mendapatkan offset ini. Jadi ListView.getChildAt (0) mengembalikan View untuk item daftar teratas, dan kemudian View.getTop () mengembalikan offset relatifnya dari bagian atas ListView. Kemudian, untuk mengembalikan posisi gulir ListView, kami memanggil ListView.setSelectionFromTop () dengan indeks item yang kita inginkan dan offset untuk memposisikan tepi atas dari bagian atas ListView. Semua jelas?
ian
15
Hal ini dapat dibuat lebih sederhana be menggunakan satu baris untuk menyimpan: int index = mList.getFirstVisiblePosition();dan hanya satu baris untuk mengembalikan: mList.setSelectionFromTop(index, 0);. Jawabannya bagus (+1)! Saya telah mencari solusi elegan untuk masalah ini.
Phil
17
@Phil Solusi simplistis Anda tidak berfungsi untuk mengembalikan posisi pengguliran yang tepat.
Ixx
2
seperti yang dikatakan @nbarraille, kode harus dibaca lebih seperti "v.getTop () - mList.getPaddingTop ()." Kalau tidak, Anda akan menghabiskan satu jam seperti saya mencoba mencari tahu mengapa selalu mengembalikan hanya rambut ...
jdowdell
544
Parcelable state;

@Override
public void onPause() {    
    // Save ListView state @ onPause
    Log.d(TAG, "saving listview state");
    state = listView.onSaveInstanceState();
    super.onPause();
}
...

@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    // Set new items
    listView.setAdapter(adapter);
    ...
    // Restore previous state (including selected item index and scroll position)
    if(state != null) {
        Log.d(TAG, "trying to restore listview state");
        listView.onRestoreInstanceState(state);
    }
}
Eugene Mymrin
sumber
106
Saya pikir ini adalah jawaban terbaik karena metode ini mengembalikan posisi gulir yang tepat dan tidak hanya item yang terlihat pertama.
Mira Weller
9
Jawaban bagus tetapi tidak akan berfungsi saat memuat konten secara dinamis dan Anda ingin menyimpan status dalam metode onPause ().
Gio
13
solusi hebat Hanya satu Masalah. Jika itemnya besar dan Anda menggulir, tetapi item pertama masih terlihat daftar melompat kembali ke atas. jika Anda gulir ke item kedua atau di mana pun semuanya bekerja
lancar
4
@passsy Apakah Anda pernah menemukan solusi daftar melompat kembali ke atas?
Papajohn000
2
Seperti yang dikatakan aaronvargas, ini tidak bisa berfungsi ketika ListView.getFirstVisiblePosition () adalah 0.
VinceStyling
54

Saya mengadopsi solusi yang disarankan oleh @ (Kirk Woll), dan itu berfungsi untuk saya. Saya juga melihat dalam kode sumber Android untuk aplikasi "Kontak", bahwa mereka menggunakan teknik yang sama. Saya ingin menambahkan beberapa perincian: Di atas pada kelas yang diturunkan dari ListActivity saya:

private static final String LIST_STATE = "listState";
private Parcelable mListState = null;

Kemudian, beberapa metode menimpa:

@Override
protected void onRestoreInstanceState(Bundle state) {
    super.onRestoreInstanceState(state);
    mListState = state.getParcelable(LIST_STATE);
}

@Override
protected void onResume() {
    super.onResume();
    loadData();
    if (mListState != null)
        getListView().onRestoreInstanceState(mListState);
    mListState = null;
}

@Override
protected void onSaveInstanceState(Bundle state) {
    super.onSaveInstanceState(state);
    mListState = getListView().onSaveInstanceState();
    state.putParcelable(LIST_STATE, mListState);
}

Tentu saja "loadData" adalah fungsi saya untuk mengambil data dari DB dan memasukkannya ke dalam daftar.

Pada perangkat Froyo saya, ini berfungsi baik ketika Anda mengubah orientasi telepon, dan ketika Anda mengedit item dan kembali ke daftar.

Giorgio Barchiesi
sumber
1
Solusi ini berhasil untuk saya. Yang lain tidak. Bagaimana cara menyimpan / memulihkan keadaan instance ListView dalam hal menghapus dan memasukkan item dalam ListView?
Bryan
2
FYI jika Anda menggunakan ini dalam sebuah fragmen (Saya menggunakan fragmen daftar) dan menavigasi ke fragmen lain, ini akan macet karena tampilan konten tidak dibuat saat memanggil mListState = getListView().onSaveInstanceState().Terutama pada rotasi perangkat.
Mgamerz
2
onRestoreInstanceStatetidak pernah dipanggil :(
dVaffection
1
@GiorgioBarchiesi Who @ (Kirk Wool) solusi mana yang cocok untuk Anda? Pengguna tampaknya mengubah namanya.
Piovezan
1
Ya, itulah agama resmi. Tetapi dalam kasus saya, data dimuat secara lokal, memiliki panjang yang sangat terbatas, dan memuat dalam sepersekian detik, jadi saya menjadi gila :-)
Giorgio Barchiesi
26

Cara yang sangat sederhana:

/** Save the position **/
int currentPosition = listView.getFirstVisiblePosition();

//Here u should save the currentPosition anywhere

/** Restore the previus saved position **/
listView.setSelection(savedPosition);

Metode setSelection akan mengatur ulang daftar ke item yang disediakan. Jika tidak dalam mode sentuh item sebenarnya akan dipilih jika dalam mode sentuh item hanya akan diposisikan di layar.

Pendekatan yang lebih rumit:

listView.setOnScrollListener(this);

//Implements the interface:
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
    mCurrentX = view.getScrollX();
    mCurrentY = view.getScrollY();
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {

}

//Save anywere the x and the y

/** Restore: **/
listView.scrollTo(savedX, savedY);
Francesco Laurita
sumber
2
ada kesalahan dalam jawaban Anda. Metode ini disebut setSelection
Janusz
Idenya bekerja dengan baik, tetapi ada masalah pseudo. Posisi pertama yang terlihat mungkin hanya ditampilkan sedikit, (mungkin hanya sebagian kecil dari baris), dan seteleksi () mengatur baris ini agar benar-benar terlihat ketika pemulihan dilakukan. terbuat.
rantravee
Silakan lihat opsi kedua saya. Saya baru saja menambahkannya ke jawaban pertama saya
Francesco Laurita
27
view.getScrollX () dan view.getScrollY () selalu mengembalikan 0!
rantravee
3
Lihatlah solusi saya (diterima) di atas menggunakan View.getChildAt () dan View.getTop (). Anda tidak dapat menggunakan View.getScrollY () pada ListView karena ListView mempertahankan penggulirannya secara internal.
ian
17

Saya menemukan sesuatu yang menarik tentang ini.

Saya mencoba setSelection dan scrolltoXY tetapi tidak berhasil sama sekali, daftar tetap di posisi yang sama, setelah beberapa coba-coba saya mendapat kode berikut yang berfungsi

final ListView list = (ListView) findViewById(R.id.list);
list.post(new Runnable() {            
    @Override
    public void run() {
        list.setSelection(0);
    }
});

Jika alih-alih memposting Runnable Anda mencoba menjalankanOnUiThread juga tidak berfungsi (setidaknya pada beberapa perangkat)

Ini adalah solusi yang sangat aneh untuk sesuatu yang harus lurus ke depan.

shafiq
sumber
1
Saya mengalami masalah yang sama! Dan setSelectionFromTop()tidak berhasil.
ofavre
+1. listnew.post (), tidak berfungsi pada beberapa perangkat, dan pada beberapa perangkat lainnya tidak berfungsi dalam kasus tertentu, tetapi menjalankanOnUIThread berfungsi dengan baik.
Omar Rehman
@ Ommar, dapatkah Anda memberikan beberapa contoh perangkat dan OS yang tidak berfungsi? Saya mencoba HTC G2 (2.3.4) dan Galaxy Nexus (4.1.2) dan berhasil pada keduanya. Tidak ada jawaban lain di utas ini yang berfungsi untuk semua perangkat saya.
Dan J
2
listview.post berfungsi dengan baik pada Galaxy Note saya dengan 4.0.4, tetapi tidak berfungsi pada Nexus One saya dengan 2.3.6. Namun, onOnUIThread (tindakan) berfungsi dengan baik di kedua perangkat.
Omar Rehman
11

PERINGATAN!! Ada bug di AbsListView yang tidak memungkinkan onSaveState () berfungsi dengan benar jika ListView.getFirstVisiblePosition () adalah 0.

Jadi Jika Anda memiliki gambar besar yang mengambil sebagian besar layar, dan Anda menggulir ke gambar kedua, tetapi sedikit yang pertama ditampilkan, posisi gulir Tidak akan disimpan ...

dari AbsListView.java:1650 (komentar milik saya)

// this will be false when the firstPosition IS 0
if (haveChildren && mFirstPosition > 0) {
    ...
} else {
    ss.viewTop = 0;
    ss.firstId = INVALID_POSITION;
    ss.position = 0;
}

Tetapi dalam situasi ini, 'top' dalam kode di bawah ini akan menjadi angka negatif yang menyebabkan masalah lain yang mencegah negara untuk dipulihkan dengan benar. Jadi ketika 'top' negatif, dapatkan anak berikutnya

// save index and top position
int index = getFirstVisiblePosition();
View v = getChildAt(0);
int top = (v == null) ? 0 : v.getTop();

if (top < 0 && getChildAt(1) != null) {
    index++;
    v = getChildAt(1);
    top = v.getTop();
}
// parcel the index and top

// when restoring, unparcel index and top
listView.setSelectionFromTop(index, top);
aaronvargas
sumber
Ini berfungsi seperti pesona tetapi saya tidak sepenuhnya memahaminya. Jika item pertama masih terlihat, bagaimana masuk akal untuk mendapatkan anak berikutnya? Tidakkah seharusnya setSelectionFromTop dengan indeks baru menyebabkan daftar ditampilkan mulai dari anak kedua? Bagaimana saya masih melihat yang pertama?
tafi
@ tafi, Item pertama bisa 'sebagian' terlihat. Jadi bagian atas item itu akan berada di atas layar, dan dengan demikian akan menjadi angka negatif. (Ini menyebabkan masalah lain yang saya tidak ingat ...) Jadi, kami menggunakan 'atas' dari Item kedua untuk penempatan, yang harus selalu (?) Tersedia, atau tidak akan ada scrolling di tempat pertama !
aaronvargas
6
private Parcelable state;
@Override
public void onPause() {
    state = mAlbumListView.onSaveInstanceState();
    super.onPause();
}

@Override
public void onResume() {
    super.onResume();

    if (getAdapter() != null) {
        mAlbumListView.setAdapter(getAdapter());
        if (state != null){
            mAlbumListView.requestFocus();
            mAlbumListView.onRestoreInstanceState(state);
        }
    }
}

Cukup

Leo Phan
sumber
Hai, apakah kode Anda di atas membantu saya dengan daftar RecyclerView di mana instancestate tidak disimpan di antara kegiatan? Saya memposting pertanyaan berikut di sini: stackoverflow.com/questions/35413495/… ?
AJW
6

Untuk beberapa orang yang mencari solusi untuk masalah ini, akar masalah mungkin di mana Anda mengatur adaptor tampilan daftar Anda. Setelah Anda mengatur adaptor pada tampilan daftar, itu akan mengatur ulang posisi gulir. Hanya sesuatu yang perlu dipertimbangkan. Saya pindah pengaturan adaptor ke onCreateView saya setelah kami mengambil referensi ke listview, dan itu memecahkan masalah bagi saya. =)

Ryan Newsom
sumber
1

Saya memposting ini karena saya terkejut tidak ada yang menyebutkan ini.

Setelah pengguna mengklik tombol kembali, ia akan kembali ke tampilan daftar dalam kondisi yang sama saat ia keluar dari sana.

Kode ini akan menimpa tombol "atas" untuk berperilaku dengan cara yang sama seperti tombol kembali sehingga dalam kasus Listview -> Detail -> Kembali ke Listview (dan tidak ada pilihan lain) ini adalah kode paling sederhana untuk mempertahankan posisi gulir dan konten dalam tampilan daftar.

 public boolean onOptionsItemSelected(MenuItem item) {
     switch (item.getItemId()) {
         case android.R.id.home:
             onBackPressed();
             return(true);
     }
     return(super.onOptionsItemSelected(item)); }

Perhatian: Jika Anda dapat pergi ke aktivitas lain dari aktivitas detail, tombol naik akan mengembalikan Anda kembali ke aktivitas itu sehingga Anda harus memanipulasi sejarah tombol back agar ini berfungsi.

Mazvél
sumber
1

SOLUSI TERBAIK ADALAH:

// save index and top position
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : (v.getTop() - mList.getPaddingTop());

// ...

// restore index and position
mList.post(new Runnable() {
    @Override
    public void run() {
      mList.setSelectionFromTop(index, top);
   }
});

ANDA HARUS MEMANGGIL DALAM POS DAN DI BENANG!

Andrew Sneck
sumber
1

Anda dapat mempertahankan status gulir setelah memuat ulang jika Anda menyimpan keadaan sebelum memuat ulang dan mengembalikannya. Dalam kasus saya, saya membuat permintaan jaringan yang tidak sinkron dan memuat ulang daftar itu dalam panggilan balik setelah selesai. Di sinilah saya mengembalikan keadaan. Contoh kode adalah Kotlin.

val state = myList.layoutManager.onSaveInstanceState()

getNewThings() { newThings: List<Thing> ->

    myList.adapter.things = newThings
    myList.layoutManager.onRestoreInstanceState(state)
}
Michael Peterson
sumber
0

Jika Anda menggunakan fragmen yang dihosting pada suatu aktivitas, Anda dapat melakukan sesuatu seperti ini:

public abstract class BaseFragment extends Fragment {
     private boolean mSaveView = false;
     private SoftReference<View> mViewReference;

     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
          if (mSaveView) {
               if (mViewReference != null) {
                    final View savedView = mViewReference.get();
                    if (savedView != null) {
                         if (savedView.getParent() != null) {
                              ((ViewGroup) savedView.getParent()).removeView(savedView);
                              return savedView;
                         }
                    }
               }
          }

          final View view = inflater.inflate(getFragmentResource(), container, false);
          mViewReference = new SoftReference<View>(view);
          return view;
     }

     protected void setSaveView(boolean value) {
           mSaveView = value;
     }
}

public class MyFragment extends BaseFragment {
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
          setSaveView(true);
          final View view = super.onCreateView(inflater, container, savedInstanceState);
          ListView placesList = (ListView) view.findViewById(R.id.places_list);
          if (placesList.getAdapter() == null) {
               placesList.setAdapter(createAdapter());
          }
     }
}
saulobrito
sumber
0

Jika Anda menyimpan / mengembalikan posisi gulir ListViewdiri Anda, Anda pada dasarnya menduplikasi fungsi yang sudah diterapkan dalam kerangka kerja android. The ListViewmengembalikan baik posisi gulir hanya baik pada sendiri kecuali satu peringatan: sebagai @aaronvargas disebutkan ada bug di AbsListViewyang tidak akan membiarkan untuk mengembalikan posisi gulir baik untuk daftar item pertama. Namun demikian cara terbaik untuk mengembalikan posisi gulir adalah tidak mengembalikannya. Kerangka kerja Android akan lebih baik untuk Anda. Pastikan Anda telah memenuhi ketentuan berikut:

  • pastikan Anda belum memanggil setSaveEnabled(false)metode dan tidak mengaturandroid:saveEnabled="false" atribut untuk daftar di file tata letak xml
  • untuk metode ExpandableListViewoverride long getCombinedChildId(long groupId, long childId)sehingga mengembalikan angka panjang positif (implementasi default di kelas BaseExpandableListAdaptermengembalikan angka negatif). Berikut ini contohnya:

.

@Override
public long getChildId(int groupPosition, int childPosition) {
    return 0L | groupPosition << 12 | childPosition;
}

@Override
public long getCombinedChildId(long groupId, long childId) {
    return groupId << 32 | childId << 1 | 1;
}

@Override
public long getGroupId(int groupPosition) {
    return groupPosition;
}

@Override
public long getCombinedGroupId(long groupId) {
    return (groupId & 0x7FFFFFFF) << 32;
}
  • jika ListViewatau ExpandableListViewdigunakan dalam sebuah fragmen, jangan membuat ulang fragmen tersebut pada aktivitas rekreasi (setelah rotasi layar misalnya). Dapatkan fragmen dengan findFragmentByTag(String tag)metode.
  • pastikan ListViewmemiliki android:iddan unik.

Untuk menghindari peringatan yang disebutkan di atas dengan item daftar pertama, Anda dapat membuat adaptor Anda dengan cara mengembalikan adaptor khusus ketinggian nol piksel untuk ListViewposisi at 0. Berikut adalah contoh sederhana proyek yang menunjukkan ListViewdan ExpandableListViewmengembalikan posisi gulir halusnya sedangkan posisi gulirnya tidak disimpan secara eksplisit. /pulih. Posisi gulir halus dipulihkan dengan sempurna bahkan untuk skenario kompleks dengan beralih sementara ke beberapa aplikasi lain, rotasi layar ganda dan beralih kembali ke aplikasi uji. Harap dicatat, jika Anda secara eksplisit keluar dari aplikasi (dengan menekan tombol Kembali) posisi gulir tidak akan disimpan (dan semua Tampilan lainnya tidak akan menyimpan statusnya). https://github.com/voromto/RestoreScrollPosition/releases

Sergey
sumber
0

Untuk aktivitas yang berasal dari ListActivity yang mengimplementasikan LoaderManager.LoaderCallbacks menggunakan SimpleCursorAdapter tidak berfungsi untuk mengembalikan posisi di onReset (), karena aktivitas itu hampir selalu dimulai kembali dan adaptor dimuat kembali ketika tampilan detail ditutup. Caranya adalah mengembalikan posisi di onLoadFinished ():

di onListItemClick ():

// save the selected item position when an item was clicked
// to open the details
index = getListView().getFirstVisiblePosition();
View v = getListView().getChildAt(0);
top = (v == null) ? 0 : (v.getTop() - getListView().getPaddingTop());

di onLoadFinished ():

// restore the selected item which was saved on item click
// when details are closed and list is shown again
getListView().setSelectionFromTop(index, top);

di onBackPressed ():

// Show the top item at next start of the app
index = 0;
top = 0;
Perotin
sumber
0

Tak satu pun dari solusi yang ditawarkan di sini tampaknya bekerja untuk saya. Dalam kasus saya, saya memiliki ListViewdi Fragmentmana saya mengganti FragmentTransaction, jadi Fragmentcontoh baru dibuat setiap kali fragmen ditampilkan, yang berarti bahwa ListViewnegara tidak dapat disimpan sebagai anggota Fragment.

Alih-alih, saya akhirnya menyimpan status di Applicationkelas khusus saya . Kode di bawah ini akan memberi Anda gambaran bagaimana cara kerjanya:

public class MyApplication extends Application {
    public static HashMap<String, Parcelable> parcelableCache = new HashMap<>();


    /* ... code omitted for brevity ... */
}

 

public class MyFragment extends Fragment{
    private ListView mListView = null;
    private MyAdapter mAdapter = null;


    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        mAdapter = new MyAdapter(getActivity(), null, 0);
        mListView = ((ListView) view.findViewById(R.id.myListView));

        Parcelable listViewState = MyApplication.parcelableCache.get("my_listview_state");
        if( listViewState != null )
            mListView.onRestoreInstanceState(listViewState);
    }


    @Override
    public void onPause() {
        MyApplication.parcelableCache.put("my_listview_state", mListView.onSaveInstanceState());
        super.onPause();
    }

    /* ... code omitted for brevity ... */

}

Ide dasarnya adalah Anda menyimpan keadaan di luar instance fragmen. Jika Anda tidak menyukai gagasan memiliki bidang statis di kelas aplikasi Anda, saya kira Anda bisa melakukannya dengan menerapkan antarmuka fragmen dan menyimpan keadaan dalam aktivitas Anda.

Solusi lain adalah menyimpannya SharedPreferences, tetapi itu menjadi sedikit lebih rumit, dan Anda harus memastikan Anda menghapusnya pada saat peluncuran aplikasi kecuali Anda ingin keadaan tetap ada di seluruh peluncuran aplikasi.

 

Juga, untuk menghindari "posisi gulir tidak disimpan ketika item pertama terlihat", Anda dapat menampilkan item pertama dummy dengan 0pxtinggi. Ini dapat dicapai dengan mengganti getView()adaptor Anda, seperti ini:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if( position == 0 ) {
        View zeroHeightView = new View(parent.getContext());
        zeroHeightView.setLayoutParams(new ViewGroup.LayoutParams(0, 0));
        return zeroHeightView;
    }
    else
        return super.getView(position, convertView, parent);
}
Magnus W
sumber
0

Jawaban saya adalah untuk Firebase dan posisi 0 adalah solusi

Parcelable state;

DatabaseReference everybody = db.getReference("Everybody Room List");
    everybody.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            state = listView.onSaveInstanceState(); // Save
            progressBar.setVisibility(View.GONE);
            arrayList.clear();
            for (DataSnapshot messageSnapshot : dataSnapshot.getChildren()) {
                Messages messagesSpacecraft = messageSnapshot.getValue(Messages.class);
                arrayList.add(messagesSpacecraft);
            }
            listView.setAdapter(convertView);
            listView.onRestoreInstanceState(state); // Restore
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {
        }
    });

dan convertView

posisi 0 a tambahkan item kosong yang tidak Anda gunakan

public class Chat_ConvertView_List_Room extends BaseAdapter {

private ArrayList<Messages> spacecrafts;
private Context context;

@SuppressLint("CommitPrefEdits")
Chat_ConvertView_List_Room(Context context, ArrayList<Messages> spacecrafts) {
    this.context = context;
    this.spacecrafts = spacecrafts;
}

@Override
public int getCount() {
    return spacecrafts.size();
}

@Override
public Object getItem(int position) {
    return spacecrafts.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@SuppressLint({"SetTextI18n", "SimpleDateFormat"})
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = LayoutInflater.from(context).inflate(R.layout.message_model_list_room, parent, false);
    }

    final Messages s = (Messages) this.getItem(position);

    if (position == 0) {
        convertView.getLayoutParams().height = 1; // 0 does not work
    } else {
        convertView.getLayoutParams().height = RelativeLayout.LayoutParams.WRAP_CONTENT;
    }

    return convertView;
}
}

Saya telah melihat pekerjaan ini sementara waktu tanpa mengganggu pengguna, saya harap ini berfungsi untuk Anda

Trk
sumber
0

gunakan kode di bawah ini:

int index,top;

@Override
protected void onPause() {
    super.onPause();
    index = mList.getFirstVisiblePosition();

    View v = challengeList.getChildAt(0);
    top = (v == null) ? 0 : (v.getTop() - mList.getPaddingTop());
}

dan kapan pun Anda menyegarkan data Anda gunakan kode di bawah ini:

adapter.notifyDataSetChanged();
mList.setSelectionFromTop(index, top);
Rohit Lalwani
sumber
0

Saya menggunakan FirebaseListAdapter dan tidak bisa mendapatkan solusi apa pun untuk bekerja. Saya akhirnya melakukan ini. Saya menduga ada cara yang lebih elegan tetapi ini adalah solusi yang lengkap dan berfungsi.

Sebelum diCreate:

private int reset;
private int top;
private int index;

Di dalam FirebaseListAdapter:

@Override
public void onDataChanged() {
     super.onDataChanged();

     // Only do this on first change, when starting
     // activity or coming back to it.
     if(reset == 0) {
          mListView.setSelectionFromTop(index, top);
          reset++;
     }

 }

onStart:

@Override
protected void onStart() {
    super.onStart();
    if(adapter != null) {
        adapter.startListening();
        index = 0;
        top = 0;
        // Get position from SharedPrefs
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        top = sharedPref.getInt("TOP_POSITION", 0);
        index = sharedPref.getInt("INDEX_POSITION", 0);
        // Set reset to 0 to allow change to last position
        reset = 0;
    }
}

onStop:

@Override
protected void onStop() {
    super.onStop();
    if(adapter != null) {
        adapter.stopListening();
        // Set position
        index = mListView.getFirstVisiblePosition();
        View v = mListView.getChildAt(0);
        top = (v == null) ? 0 : (v.getTop() - mListView.getPaddingTop());
        // Save position to SharedPrefs
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        sharedPref.edit().putInt("TOP_POSITION" + "", top).apply();
        sharedPref.edit().putInt("INDEX_POSITION" + "", index).apply();
    }
}

Karena saya juga harus menyelesaikan ini untuk FirebaseRecyclerAdapter saya memposting solusi untuk itu juga:

Sebelum diCreate:

private int reset;
private int top;
private int index;

Di dalam FirebaseRecyclerAdapter:

@Override
public void onDataChanged() {
    // Only do this on first change, when starting
    // activity or coming back to it.
    if(reset == 0) {
        linearLayoutManager.scrollToPositionWithOffset(index, top);
        reset++;
    }
}

onStart:

@Override
protected void onStart() {
    super.onStart();
    if(adapter != null) {
        adapter.startListening();
        index = 0;
        top = 0;
        // Get position from SharedPrefs
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        top = sharedPref.getInt("TOP_POSITION", 0);
        index = sharedPref.getInt("INDEX_POSITION", 0);
        // Set reset to 0 to allow change to last position
        reset = 0;
    }
}

onStop:

@Override
protected void onStop() {
    super.onStop();
    if(adapter != null) {
        adapter.stopListening();
        // Set position
        index = linearLayoutManager.findFirstVisibleItemPosition();
        View v = linearLayoutManager.getChildAt(0);
        top = (v == null) ? 0 : (v.getTop() - linearLayoutManager.getPaddingTop());
        // Save position to SharedPrefs
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        sharedPref.edit().putInt("TOP_POSITION" + "", top).apply();
        sharedPref.edit().putInt("INDEX_POSITION" + "", index).apply();
    }
}
John T
sumber
0

Untuk mengklarifikasi jawaban yang sangat baik dari Ryan Newsom dan untuk menyesuaikannya untuk fragmen dan untuk kasus biasa yang ingin kita navigasi dari fragmen "master" ListView ke fragmen "detail" dan kemudian kembali ke "master"

    private View root;
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
           if(root == null){
             root = inflater.inflate(R.layout.myfragmentid,container,false);
             InitializeView(); 
           } 
           return root; 
        }

    public void InitializeView()
    {
        ListView listView = (ListView)root.findViewById(R.id.listviewid);
        BaseAdapter adapter = CreateAdapter();//Create your adapter here
        listView.setAdpater(adapter);
        //other initialization code
    }

"Ajaib" di sini adalah bahwa ketika kita menavigasi kembali dari fragmen detail ke fragmen ListView, tampilan tidak dibuat ulang, kita tidak mengatur adaptor ListView, jadi semuanya tetap seperti kita meninggalkannya!

befstrat
sumber