ListView öğesine geri dönerken kaydırma konumunu koru / Kaydet / Geri yükle


397

Ben bir ListViewönceki ekrana dönmeden önce kullanıcı etrafında kaydırma uzun bir var. Kullanıcı bunu ListViewtekrar açtığında , listenin daha önce olduğu noktaya kaydırılmasını istiyorum. Bunu nasıl başaracağınıza dair bir fikrin var mı?


22
Eugene Mymrin / Giorgio Barchiesi tarafından bahsedilen çözümlerin kabul edilen cevaptan daha iyi olduğunu düşünüyorum
Mira Weller

Yanıtlar:


631

Bunu dene:

// 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);

Açıklama:

ListView.getFirstVisiblePosition()en üstteki görünür liste öğesini döndürür. Ancak bu öğe kısmen görünmeyebilir ve listenin tam kaydırma konumunu geri yüklemek isterseniz bu ofseti almanız gerekir. Yani ListView.getChildAt(0)döner Viewüst liste öğesi için, sonra View.getTop() - mList.getPaddingTop()üstünden ofset onun göreceli döndürür ListView. Ardından, ListView'nin kaydırma konumunu geri yüklemek için ListView.setSelectionFromTop()istediğimiz öğenin dizinini ve üst kenarını üstünden konumlandırmak için bir ofset ile çağırırız ListView.


2
Bunun nasıl çalıştığını gerçekten anlamadım. Sadece listView.getFirstVisiblePosition () kullanıyorum ve bunu anlamak, ama burada neler olup bittiğinden emin değilim. Kısa bir açıklama şansı var mı? :)
HXCaine

56
ListView.getFirstVisiblePosition () görünür en üstteki liste öğesini döndürür. Ancak bu öğe kısmen görünmeyebilir ve listenin tam kaydırma konumunu geri yüklemek isterseniz bu ofseti almanız gerekir. ListView.getChildAt (0), üst liste öğesinin Görünümünü döndürür ve ardından View.getTop (), ListView'ın üstünden göreli uzaklığını döndürür. Ardından, ListView'ın kaydırma konumunu geri yüklemek için, istediğimiz öğenin diziniyle ListView.setSelectionFromTop () öğesini çağırırız ve üst kenarını ListView'ın üstünden konumlandırmak için bir ofset. Temiz?
ian

15
Bu kurtarmak için bir satırını kullanarak be daha da basit hale getirilebilir int index = mList.getFirstVisiblePosition();geri ve tek bir satır: mList.setSelectionFromTop(index, 0);. Büyük cevap olsa (+1)! Bu soruna zarif bir çözüm arıyordum.
Phil

17
@ Basit çözümünüz tam kaydırma konumunu geri yüklemek için çalışmaz.
Ixx

2
@nbarraille'in dediği gibi, kod daha çok "v.getTop () - mList.getPaddingTop ()" şeklinde okunmalıdır. Aksi halde neden her zaman sadece bir saçını geri
yüklediğini

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);
    }
}

106
Bu yöntem, sadece ilk görünür öğeyi değil, tam kaydırma konumunu geri yüklediğinden bu en iyi yanıt olduğunu düşünüyorum .
Mira Weller

9
Harika yanıt, ancak içeriği dinamik olarak yüklerken çalışmaz ve onPause () yönteminde durumu kaydetmek istiyorsanız.
Gio

13
harika bir çözüm. Sadece bir Sorun. Öğeler büyükse ve kaydırırsanız, ancak ilk öğe hala görünür durumdaysa, liste en üste atlar. ikinci öğeye veya başka bir yere
kaydırırsanız

4
@passsy Listenin en tepeye sıçradığı bir çözüm buldunuz mu?
Papajohn000

2
Aaronvargas'ın dediği gibi, ListView.getFirstVisiblePosition () 0 olduğunda işe yaramaz.
VinceStyling

54

@ (Kirk Woll) tarafından önerilen çözümü benimsedim ve bu benim için işe yarıyor. Ben de benzer bir tekniği kullandıklarını, "Rehber" uygulaması için Android kaynak kodunda gördük. Daha fazla ayrıntı eklemek istiyorum: ListActivity'den türetilen sınıfımda:

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

Sonra, bazı yöntem geçersiz kılar:

@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);
}

Tabii ki "loadData" DB veri almak ve listeye koymak benim işlevim.

Froyo cihazımda, bu hem telefon yönünü değiştirdiğinizde hem de bir öğeyi düzenleyip listeye geri döndüğünüzde çalışır.


1
Bu çözüm benim için çalıştı. Diğerleri yapmadı. ListView örneği durumunun kaydedilmesi / geri yüklenmesi, ListView öğelerinin silinmesi ve eklenmesi konusunda nasıl davranır?
Bryan

2
FYI bunu bir parçada (bir liste parçası kullanıyorum) kullanırsanız ve diğer parçalara giderseniz, mListState = getListView().onSaveInstanceState().temelde cihaz döndürme çağrılırken içerik görünümü oluşturulmadığı için bu çökecektir.
Mgamerz

2
onRestoreInstanceStateasla çağrılmaz :(
dVaffection

1
@GiorgioBarchiesi Çözümü sizin için çalışan @ (Kirk Wool) kimdir? Kullanıcı görünüşe göre adını değiştirdi.
Piovezan

1
Evet, bu resmi din. Ama benim durumumda veriler yerel olarak yüklenir, çok sınırlı bir uzunluğa sahiptir ve bir saniyede yüklenir, bu yüzden erethic oldum :-)
Giorgio Barchiesi

26

Çok basit bir yol:

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

//Here u should save the currentPosition anywhere

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

SetSelection yöntemi listeyi sağlanan öğeye sıfırlar. Dokunmatik modda değilse, dokunmatik modda öğe yalnızca ekranda konumlandırılacaksa, öğe gerçekten seçilecektir.

Daha karmaşık bir yaklaşım:

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);

2
cevabınızda bir hata oluştu. Yönteme setSelection
Janusz

Fikir iyi çalışıyor, ancak sözde bir sorun var. İlk görünür konum sadece biraz gösterilebilir (belki de satırın sadece küçük bir kısmı) ve setSelection (), geri yükleme olduğunda bu satırı tamamen görünür olacak şekilde ayarlar yapılmış.
rantravee

Lütfen ikinci seçeneğime bir göz atın. Ben ilk cevabımı ekledim
Francesco Laurita

27
view.getScrollX () ve view.getScrollY () her zaman 0 döndürür!
rantravee

3
View.getChildAt () ve View.getTop () kullanarak yukarıdaki (kabul edilen) çözümüme göz atın. ListView dahili olarak kaydırmayı sürdürdüğü için ListView'de View.getScrollY () yöntemini kullanamazsınız.
ian

17

Bununla ilgili ilginç bir şey buldum.

SetSelection ve scrolltoXY'yi denedim ama hiç çalışmadı, liste aynı pozisyonda kaldı, bazı deneme ve hatalardan sonra işe yarayan aşağıdaki kodu aldım

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

Runnable'ı göndermek yerine runOnUiThread'i de denerseniz (en azından bazı cihazlarda)

Bu, doğrudan olması gereken bir şey için çok garip bir çözümdür.


1
Aynı sorunu yaşadım! Ve setSelectionFromTop()çalışmıyor.
ofavre

+1. listnew.post (), bazı cihazlarda çalışmaz ve diğer bazı cihazlarda belirli durumlarda çalışmaz, ancak runOnUIThread iyi çalışır.
Omar Rehman

@Omar, bunun üzerinde çalışmadığı bazı cihaz ve işletim sistemi örnekleri verebilir misiniz? Bir HTC G2 (2.3.4) ve Galaxy Nexus (4.1.2) denedim ve her ikisinde de çalıştı. Bu ileti dizisindeki diğer yanıtların hiçbiri aygıtlarımın hiçbirinde işe yaramadı.
Dan J

2
listview.post, 4.0.4 ile Galaxy Note'umda iyi çalışıyor, ancak 2.3.6 ile Nexus One'ımda çalışmıyor. Ancak, onOnUIThread (eylem) her iki cihazda da iyi çalışır.
Omar Rehman

11

DİKKAT!! AbsListView'da, ListView.getFirstVisiblePosition () 0 ise onSaveState () işlevinin düzgün çalışmasına izin vermeyen bir hata vardır.

Ekranın çoğunu kaplayan büyük resimleriniz varsa ve ikinci resme ilerlerseniz, ancak ilkinden biraz gösteriliyorsa, kaydırma konumu kaydedilmeyecek ...

itibaren AbsListView.java:1650 (yorum maden)

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

Ancak bu durumda, aşağıdaki koddaki 'üst', durumun doğru bir şekilde geri yüklenmesini engelleyen diğer sorunlara neden olan negatif bir sayı olacaktır. 'Üst' negatif olduğunda, bir sonraki çocuğu alın

// 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);

Bir cazibe gibi çalışıyor ama tam olarak anlamıyorum. İlk öğe hala görünüyorsa, bir sonraki çocuğu almak nasıl bir anlam ifade eder? SetSelectionFromTop öğesini yeni dizine eklememelisiniz, listenin ikinci alt öğeden başlayarak gösterilmesine neden olur mu? İlkini nasıl görüyorum?
tafi

@tafi, İlk öğe 'kısmen' görülebilir. Dolayısıyla, bu öğenin üst kısmı ekranın üstünde olur ve bu nedenle negatif bir sayı olur. (Bu, hatırlamadığım diğer sorunlara neden olur ...) Bu nedenle, her zaman (?) Kullanılabilir olması gereken ikinci Öğenin 'üst kısmını' kullanırız veya ilk etapta kaydırma olmaz !
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);
        }
    }
}

Bu yeterli


Merhaba, yukarıdaki kod örneklerinin etkinlikler arasında kaydedilmeyen bir RecyclerView listesi ile bana yardımcı olur mu? Aşağıdaki soruyu buraya gönderdim: stackoverflow.com/questions/35413495/… ?
AJW

6

Bazıları bu soruna bir çözüm arayanlar için, sorunun kökü liste görünümleri bağdaştırıcınızı ayarladığınız yerde olabilir. Bağdaştırıcıyı liste görünümünde ayarladıktan sonra kaydırma konumunu sıfırlar. Dikkate alınması gereken bir şey. Biz liste görünümüne referans kapmak sonra benim onCreateView içine adaptör ayarı taşındı ve benim için sorunu çözdü. =)


1

Bunu gönderiyorum çünkü kimsenin bundan bahsetmediğine şaşırdım.

Kullanıcı geri düğmesini tıkladıktan sonra, çıktığı haliyle liste görünümüne geri döner.

Bu kod, "yukarı" düğmesini geri düğmesiyle aynı şekilde davranacak şekilde geçersiz kılar, böylece Liste Görünümü -> Ayrıntılar -> Liste Görüntüsüne Dön (ve başka seçenek yok) durumunda bu, kaydırma konumunu ve içeriği korumak için en basit koddur liste görünümünde.

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

Dikkat: Ayrıntılar etkinliğinden başka bir etkinliğe gidebiliyorsanız, yukarı düğmesi sizi bu etkinliğe geri döndürür, böylece bunun çalışması için geri düğmesi geçmişini değiştirmeniz gerekir.



1

EN İYİ ÇÖZÜM:

// 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);
   }
});

SONRASI VE İPLİKTE ÇAĞRIYORUZ!


1

Durumu yeniden yüklemeden ve sonra geri yüklemeden önce kaydederseniz, yeniden yükleme sonrasında kaydırma durumunu koruyabilirsiniz. Benim durumumda eşzamansız bir ağ isteği yaptım ve listeyi tamamlandıktan sonra geri aramada yeniden yükledim. Devleti buradan geri yüklerim. Kod örneği Kotlin'dir.

val state = myList.layoutManager.onSaveInstanceState()

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

    myList.adapter.things = newThings
    myList.layoutManager.onRestoreInstanceState(state)
}

0

Bir etkinlikte barındırılan parçaları kullanıyorsanız, bunun gibi bir şey yapabilirsiniz:

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());
          }
     }
}

0

ListViewKendinizin kaydırma konumunu kaydediyor / geri yüklüyorsanız , android çerçevede zaten uygulanan işlevselliği çoğaltırsınız. ListViewGeri yükleme ince kaydırma konumu sadece iyi kendi başına hariç bir uyarı: @aaronvargas bir hata var belirtildiği gibi AbsListViewilk liste öğesi için ince kaydırma konumu geri izin vermez. Bununla birlikte, kaydırma konumunu geri yüklemenin en iyi yolu geri yüklemektir. Android çerçevesi sizin için daha iyisini yapacaktır. Sadece aşağıdaki koşulları yerine getirdiğinizden emin olun:

  • xml mizanpaj dosyasındaki liste için bir setSaveEnabled(false)yöntem çağırmadığınızdan ve android:saveEnabled="false"özniteliği ayarlamadığınızdan emin olun
  • ExpandableListViewgeçersiz long getCombinedChildId(long groupId, long childId)uzun yöntem döndürmesi için geçersiz kılma yöntemi (sınıftaki varsayılan uygulama BaseExpandableListAdapternegatif sayı döndürür). İşte örnekler:

.

@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;
}
  • Eğer bir fragmanda kullanılırsa ListViewveya ExpandableListViewkullanılırsa, fragmanı aktivite rekreasyonunda yeniden yaratmayın (örneğin ekran döndürmeden sonra). Parçayı findFragmentByTag(String tag)yöntemle elde edin .
  • emin olun ListViewbir android:idve benzersizdir.

İlk liste öğesiyle yukarıda belirtilen uyarıdan kaçınmak için adaptörünüzü 0 konumunda özel kukla sıfır piksel yükseklik görünümü döndürme biçiminde oluşturabilirsiniz. ListViewİşte basit örnek proje, kaydırma konumlarının açıkça kaydedilmediği halde ince kaydırma konumlarını gösterir ListViewve ExpandableListViewgeri yükler. / restore. Başka bir uygulamaya geçici geçiş, çift ekran döndürme ve test uygulamasına geri dönme gibi karmaşık senaryolar için bile hassas kaydırma konumu mükemmel bir şekilde geri yüklenir. Uygulamadan açıkça çıkıyorsanız (Geri düğmesine basarak) kaydırma konumunun kaydedilmeyeceğini (diğer tüm Görünümlerin durumlarını kaydetmeyeceğini) lütfen unutmayın. https://github.com/voromto/RestoreScrollPosition/releases


0

SimpleCursorAdapter kullanarak LoaderManager.LoaderCallbacks uygulayan ListActivity'den türetilen bir etkinlik için, etkinlik neredeyse her zaman yeniden başlatıldığından ve ayrıntılar görünümü kapatıldığında bağdaştırıcı yeniden yüklendiğinden onReset () içindeki konumu geri yüklemek için çalışmadı. Hile onLoadFinished () içindeki konumu geri yüklemekti:

onListItemClick () içinde:

// 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());

onLoadFinished () içinde:

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

onBackPressed () içinde:

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

0

Burada sunulan çözümlerin hiçbiri benim için işe yaramadı. Benim durumumda, ListViewiçinde Fragmentdeğiştirdiğim bir var FragmentTransaction, bu yüzden Fragmenther parça gösterildiğinde yeni bir örnek oluşturulur, bu da ListViewdurumun üyesi olarak depolanamayacağı anlamına gelirFragment .

Bunun yerine, devleti özel Applicationsınıfımda depoladım . Aşağıdaki kod size bunun nasıl çalıştığı hakkında bir fikir vermelidir:

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 ... */

}

Temel fikir, durumu parça örneğinin dışında saklamanızdır. Uygulama sınıfınızda statik bir alana sahip olma fikrinden hoşlanmıyorsanız, bunu bir parça arabirimi uygulayarak ve durumu etkinliğinizde depolayarak yapabilirsiniz.

Başka bir çözüm de depolamak olacaktır SharedPreferences, ancak biraz daha karmaşık hale gelir ve durumun uygulama lansmanlarında kalıcı olmasını istemediğiniz sürece uygulama başlatmasında temizlediğinizden emin olmanız gerekir.

 

Ayrıca, "ilk öğe görünür durumdayken kaydedilmeyen kaydırma konumu" ndan kaçınmak için, 0pxyüksekliği yüksek olan bir sahte öğe görüntüleyebilirsiniz . Bu, getView()adaptörünüzde geçersiz kılmayla elde edilebilir , örneğin:

@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);
}

0

Cevabım Firebase içindir ve 0 konumu geçici bir çözümdür

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) {
        }
    });

ve dönüştürmek

0 konumu a kullanmadığınız boş bir öğe ekleyin

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;
}
}

Bu işi kullanıcıyı rahatsız etmeden geçici olarak gördüm, umarım sizin için çalışır


0

Aşağıdaki kodu kullanın:

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());
}

ve verileriniz her yenilendiğinde aşağıdaki kodu kullanın:

adapter.notifyDataSetChanged();
mList.setSelectionFromTop(index, top);

0

FirebaseListAdapter kullanıyorum ve çalışmak için herhangi bir çözüm alamadım. Sonunda bunu yaptım. Sanırım daha zarif yollar var ama bu tam ve çalışan bir çözüm.

Oluşturmadan önce:

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

FirebaseListAdapter içinde:

@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();
    }
}

Ben de FirebaseRecyclerAdapter için bunu çözmek zorunda beri burada çözüm gönderiyorum:

Oluşturmadan önce:

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

FirebaseRecyclerAdapter içinde:

@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();
    }
}

0

Ryan Newsom'un mükemmel cevabını açıklığa kavuşturmak ve onu parçalar için ve bir "ana" ListView parçasından "ayrıntılar" parçasına ve sonra tekrar "kaptana" gitmek istediğimiz olağan durum için ayarlamak için

    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
    }

Buradaki "sihir", ayrıntılar parçasından ListView parçasına geri döndüğümüzde, görünümün yeniden oluşturulmadığı, ListView'ın bağdaştırıcısını ayarlamadığımız için her şeyin bıraktığımız gibi kalmasıdır!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.