सूची दृश्य पर लौटते समय स्क्रॉल स्थिति को बनाए रखें / सहेजें / पुनर्स्थापित करें


397

मेरे पास एक लंबा समय ListViewहै जो उपयोगकर्ता पिछली स्क्रीन पर लौटने से पहले स्क्रॉल कर सकता है। जब उपयोगकर्ता इसे ListViewफिर से खोलता है , तो मैं चाहता हूं कि सूची उसी बिंदु पर स्क्रॉल की जाए जो पहले थी। इसे प्राप्त करने के बारे में कोई विचार?


22
मुझे लगता है कि यूजीन मायरिन / जियोर्जियो बर्चेसी द्वारा वर्णित समाधान स्वीकृत उत्तर से बेहतर हैं
मीरा वेलर

जवाबों:


631

इसे इस्तेमाल करे:

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

स्पष्टीकरण:

ListView.getFirstVisiblePosition()शीर्ष दृश्यमान सूची आइटम लौटाता है। लेकिन इस आइटम को आंशिक रूप से स्क्रॉल किया जा सकता है, और यदि आप इस ऑफसेट को प्राप्त करने के लिए आवश्यक सूची की सटीक स्क्रॉल स्थिति को पुनर्स्थापित करना चाहते हैं। इसलिए शीर्ष सूची आइटम ListView.getChildAt(0)के Viewलिए वापस आता है , और फिर View.getTop() - mList.getPaddingTop()ऊपर से इसकी सापेक्ष ऑफसेट लौटाता है ListView। फिर, ListViewहम स्क्रॉल स्थिति को पुनर्स्थापित करने के लिए कॉल करते हैंListView.setSelectionFromTop() उस आइटम के सूचकांक के साथ करते हैं जिसे हम चाहते हैं और एक ऑफसेट इसके शीर्ष किनारे से स्थिति को ऊपर करने के लिएListView


2
वास्तव में समझ में नहीं आता कि यह कैसे काम करता है। मैं listView.getFirstVanishPosition () का उपयोग कर रहा हूं और केवल यह समझता हूं, लेकिन यह सुनिश्चित नहीं है कि यहां क्या हो रहा है। एक संक्षिप्त विवरण का कोई मौका? :)
एचएक्सकैन

56
इसलिए ListView.getFirstVoublePosition () शीर्ष दृश्यमान सूची आइटम लौटाता है। लेकिन इस आइटम को आंशिक रूप से स्क्रॉल किया जा सकता है, और यदि आप इस ऑफसेट को प्राप्त करने के लिए आवश्यक सूची की सटीक स्क्रॉल स्थिति को पुनर्स्थापित करना चाहते हैं। इसलिए ListView.getChildAt (0) शीर्ष सूची आइटम के लिए दृश्य लौटाता है, और फिर View.getTop () ListView के शीर्ष से इसकी सापेक्ष ऑफ़सेट लौटाता है। फिर, ListView की स्क्रॉल स्थिति को पुनर्स्थापित करने के लिए, हम ListView.setSelectionFromTop () को उस आइटम के इंडेक्स के साथ कहते हैं जिसे हम चाहते हैं और एक दृश्य की सूची के शीर्ष से उसके शीर्ष किनारे को ऑफसेट करने के लिए एक ऑफसेट। सब साफ़?
इआन

15
इसे और भी सरल बनाया जा सकता है ताकि एक लाइन को बचाया जा सके: int index = mList.getFirstVisiblePosition();और पुनर्स्थापित करने के लिए केवल एक लाइन mList.setSelectionFromTop(index, 0);:। हालांकि महान जवाब (+1)! मैं इस समस्या का एक सुंदर समाधान ढूंढ रहा हूं।
फिल

17
@ अपने सरलीकृत समाधान सटीक स्क्रॉलिंग स्थिति को पुनर्स्थापित करने के लिए काम नहीं करता है।
Ixx

2
जैसा कि @nbarraille ने कहा, कोड को "v.getTop () - mList.getPaddingTop ()" अधिक पढ़ना चाहिए। अन्यथा आप एक घंटे बिताएंगे जैसे मैंने यह जानने की कोशिश की कि यह हमेशा सिर्फ एक बाल को क्यों बंद करता है ...
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);
    }
}

106
मुझे लगता है कि यह सबसे अच्छा जवाब है क्योंकि यह विधि सटीक स्क्रॉल स्थिति को पुनर्स्थापित करती है और न केवल पहली दिखाई देने वाली वस्तु।
मीरा वेलर

9
बढ़िया उत्तर लेकिन गतिशील रूप से सामग्री लोड करने पर काम नहीं करेगा और आप ऑनपोज़ () विधि में राज्य को बचाना चाहते हैं।
जियो

13
महान समाधान। सिर्फ एक समस्या। यदि आइटम बड़े हैं और आप स्क्रॉल करते हैं, लेकिन पहला आइटम अभी भी दिखाई दे रहा है तो सूची शीर्ष पर वापस जाती है। अगर आप दूसरे आइटम पर स्क्रॉल करते हैं या कहीं और सब कुछ काम करता है
पासिंग जूल

4
@passsy क्या आपको कभी कोई समाधान मिला जो सूची में शीर्ष पर वापस जा रहा है?
पापजोहान 1000

2
जैसा कि अनारोनवार्स ने कहा, यह तब काम नहीं कर सका जब ListView.getFirstVoublePosition () 0. है
विंसर्टिंग

54

मैंने @ (Kirk Woll) द्वारा सुझाए गए समाधान को अपनाया, और यह मेरे लिए काम करता है। मैंने "संपर्क" ऐप के लिए एंड्रॉइड स्रोत कोड में भी देखा है, कि वे एक समान तकनीक का उपयोग करते हैं। मैं कुछ और विवरण जोड़ना चाहूंगा: शीर्ष पर मेरी ListActivity-व्युत्पन्न वर्ग:

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

फिर, कुछ विधि ओवरराइड होती है:

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

बेशक "लोडडाटा" डीबी से डेटा प्राप्त करने और इसे सूची में डालने का मेरा कार्य है।

मेरे Froyo डिवाइस पर, यह तब काम करता है जब आप फ़ोन ओरिएंटेशन बदलते हैं, और जब आप किसी आइटम को संपादित करते हैं और सूची में वापस जाते हैं।


1
इस समाधान ने मेरे लिए काम किया। दूसरों ने नहीं किया। सूची दृश्य स्थिति को सहेजना / पुनर्स्थापित करना सूची दृश्य में आइटम को हटाने और सम्मिलित करने के संबंध में कैसे व्यवहार करता है?
ब्रायन

2
FYI करें यदि आप इसे एक टुकड़े में उपयोग कर रहे हैं (मैं एक सूची के टुकड़े का उपयोग कर रहा हूँ) और अन्य टुकड़ों में नेविगेट करता हूं, तो यह क्रैश हो जाएगा क्योंकि mListState = getListView().onSaveInstanceState().मुख्य रूप से डिवाइस के रोटेशन पर कॉल करते समय सामग्री दृश्य नहीं बनाई जाती है ।
ममगर्ज़

2
onRestoreInstanceStateकभी नहीं कहा जाता है :(
dVaffection

1
@GiorgioBarchiesi कौन है (कर्क ऊन) जिसका समाधान आपके लिए काम करता है? उपयोगकर्ता ने स्पष्ट रूप से अपना नाम बदल लिया है।
Piovezan

1
हाँ, यह आधिकारिक धर्म है। लेकिन मेरे मामले में डेटा स्थानीय रूप से लोड किया गया है, बहुत सीमित लंबाई है, और एक दूसरे विभाजन में लोड होता है, इसलिए मैं erethic :-)
जियोर्जियो बारचीस

26

एक बहुत ही सरल तरीका:

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

//Here u should save the currentPosition anywhere

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

विधि सेटिसलेशन सूची को आपूर्ति किए गए आइटम पर रीसेट करेगा। यदि टच मोड में नहीं है तो आइटम को वास्तव में चुना जाएगा यदि टच मोड में आइटम केवल स्क्रीन पर तैनात किया जाएगा।

अधिक जटिल दृष्टिकोण:

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
आपके उत्तर में एक त्रुटि थी। विधि को सेटसेलेक्शन कहा जाता है
Janusz

विचार अच्छी तरह से काम करता है, लेकिन एक छद्म समस्या है। पहली दिखाई देने वाली स्थिति को केवल थोड़ा सा दिखाया जा सकता है, (शायद पंक्ति का एक छोटा सा हिस्सा), और सेटस्लेक्शन () इस पंक्ति को पूरी तरह से दिखाई देने के लिए सेट करें जब पुनर्स्थापना हो बनाया गया।
रणत्रवे

कृपया मेरे दूसरे विकल्प पर एक नज़र डालें। मैंने इसे सिर्फ अपने पहले उत्तर में जोड़ा है
फ्रांसेस्को लॉरिटा

27
view.getScrollX () और view.getScrollY () हमेशा 0 लौटें!
राँत्रवी

3
View.getChildAt () और View.getTop () का उपयोग करके उपरोक्त मेरे (स्वीकृत) समाधान पर एक नज़र डालें। आप एक ListView पर View.getScrollY () का उपयोग नहीं कर सकते क्योंकि एक ListView आंतरिक रूप से अपनी स्क्रॉलिंग बनाए रखता है।
इआन

17

मुझे इस बारे में कुछ दिलचस्प लगा।

मैंने सेट सेलेक्शन और स्क्रोलएक्सएक्सवाई की कोशिश की, लेकिन यह बिल्कुल भी काम नहीं किया, सूची उसी स्थिति में रही, कुछ परीक्षण और त्रुटि के बाद मुझे निम्नलिखित कोड मिला जो काम करता है

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

यदि रननेबल को पोस्ट करने के बजाय आप रनऑन यूआईट्रेड की कोशिश करते हैं तो यह काम नहीं करता है (कम से कम कुछ उपकरणों पर)

यह किसी ऐसी चीज़ के लिए बहुत ही अजीब है जो सीधे आगे होनी चाहिए।


1
मैंने उसी मुद्दे का अनुभव किया! और setSelectionFromTop()काम नहीं करता है।
inavre

+1। listnew.post (), कुछ उपकरणों पर काम नहीं करता है, और कुछ अन्य उपकरणों पर यह कुछ मामलों में काम नहीं करता है, लेकिन runOnUIThread ठीक काम करता है।
उमर रहमान

@ उमर, क्या आप डिवाइस और OSes के कुछ उदाहरण दे सकते हैं जो इस पर काम नहीं करते हैं? मैंने एक HTC G2 (2.3.4) और एक गैलेक्सी नेक्सस (4.1.2) की कोशिश की और यह दोनों पर काम किया। इस सूत्र में किसी भी अन्य उत्तर ने मेरे किसी भी उपकरण के लिए काम नहीं किया।
दान जे

2
listview.post 4.0.4 के साथ मेरे गैलेक्सी नोट पर ठीक काम करता है, लेकिन 2.3.6 के साथ मेरे नेक्सस वन पर काम नहीं करता है। हालाँकि, onOnUIThread (कार्रवाई) दोनों उपकरणों पर ठीक काम करता है।
उमर रहमान

11

सावधान!! AbsListView में एक बग होता है, जो ListView.getFirstVanishPosition () 0 है, तो onSaveState () को सही ढंग से काम करने की अनुमति नहीं देता है।

इसलिए यदि आपके पास बड़ी छवियां हैं जो अधिकांश स्क्रीन को ऊपर ले जाती हैं, और आप दूसरी छवि पर स्क्रॉल करते हैं, लेकिन पहले से थोड़ी सी दिखाई दे रही है, तो स्क्रॉल स्थिति को सहेजा नहीं जाएगा ...

से AbsListView.java:1650 (टिप्पणी मेरा)

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

लेकिन इस स्थिति में, नीचे दिए गए कोड में 'शीर्ष' एक नकारात्मक संख्या होगी जो अन्य मुद्दों का कारण बनता है जो राज्य को सही तरीके से बहाल करने से रोकते हैं। इसलिए जब 'शीर्ष' नकारात्मक हो, तो अगला बच्चा प्राप्त करें

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

यह एक आकर्षण की तरह काम करता है लेकिन मैं इसे पूरी तरह से नहीं समझता। यदि पहला आइटम अभी भी दिखाई दे रहा है, तो अगले बच्चे को पाने के लिए कैसे समझ में आता है? सेट नहीं करना चाहिए नए सूचकांक के साथ चयन फ़र्मटॉप का कारण सूची को दूसरे बच्चे से शुरू करना दिखाया जाना चाहिए? मैं अभी भी पहली बार कैसे देख रहा हूं?
तफी

@tafi, पहला आइटम 'आंशिक रूप से' दिखाई दे सकता है। तो उस आइटम का शीर्ष स्क्रीन के ऊपर होगा, और इस प्रकार एक नकारात्मक संख्या होगी। (यह अन्य मुद्दों का कारण बनता है जो मुझे याद नहीं है ...) तो हम प्लेसमेंट के लिए दूसरे आइटम के 'शीर्ष' का उपयोग करते हैं, जो हमेशा (?) उपलब्ध होना चाहिए, या पहली जगह में कोई स्क्रॉलिंग नहीं होगी। !
अनारोन्वार्गस

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

बस काफी है


नमस्ते, क्या ऊपर दिया गया आपका कोड मुझे RecyclerView सूची में मदद कर सकता है जहाँ गतिविधियों के बीच अस्थिर नहीं बचा जा रहा है? मैंने निम्नलिखित प्रश्न यहाँ पोस्ट किया: stackoverflow.com/questions/35413495/… ?
AJW

6

इस समस्या के समाधान की तलाश में कुछ के लिए, समस्या की जड़ वह जगह हो सकती है जहां आप अपनी सूची दृश्य एडेप्टर सेट कर रहे हैं। एडॉप्टर को सूची में सेट करने के बाद, यह स्क्रॉल स्थिति को रीसेट करता है। बस कुछ विचार करने के लिए। हमने सूची को संदर्भित करने के बाद एडेप्टर को मेरे ऑनक्रीट व्यू में स्थापित किया, और इसने मेरे लिए समस्या को हल कर दिया। =)


1

यह पोस्ट कर रहा हूँ क्योंकि मुझे आश्चर्य है कि किसी ने भी इसका उल्लेख नहीं किया था।

उपयोगकर्ता द्वारा बैक बटन पर क्लिक करने के बाद वह उसी स्थिति में सूची में वापस आ जाएगा, जब वह उससे बाहर गया था।

यह कोड लिस्टव्यू के मामले में बैक बटन के समान व्यवहार करने के लिए "अप" बटन को ओवरराइड कर देगा -> विवरण -> विवरण -> सूची पर वापस जाएं (और कोई अन्य विकल्प नहीं) यह स्क्रॉलपोस्ट और सामग्री को बनाए रखने का सबसे सरल कोड है सूची में।

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

सावधानी: यदि आप विवरण गतिविधि से किसी अन्य गतिविधि पर जा सकते हैं तो अप बटन आपको उस गतिविधि पर वापस लौटा देगा ताकि आपको काम करने के लिए बैकबटन इतिहास में हेरफेर करना पड़े।


1

बस android:saveEnabled="true"सूची दृश्य xml घोषणा में पर्याप्त नहीं है?


1
android: saveEnabled डिफ़ॉल्ट रूप से सही पर सेट है। यह कुछ भी नहीं करता है।
ब्रैड

नहीं। यह काफी नहीं है, आपको stackoverflow.com/questions/3014089/… या OR stackoverflow.com/questions/3014089/…
राहुल मंडलीया

1

सबसे अच्छा समाधान है:

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

आप पोस्ट और तीन में कॉल करना होगा!


1

यदि आप पुनः लोड होने से पहले राज्य को सहेजते हैं और इसे पुनर्स्थापित करते हैं, तो आप पुनः लोड होने के बाद स्क्रॉल स्थिति बनाए रख सकते हैं। मेरे मामले में मैंने एक अतुल्यकालिक नेटवर्क अनुरोध किया और इसे पूरा करने के बाद कॉलबैक में सूची को पुनः लोड किया। यह वह जगह है जहां मैं राज्य को पुनर्स्थापित करता हूं। कोड नमूना कोटलिन है।

val state = myList.layoutManager.onSaveInstanceState()

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

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

0

यदि आप किसी गतिविधि पर होस्ट किए गए टुकड़ों का उपयोग कर रहे हैं, तो आप कुछ इस तरह कर सकते हैं:

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

यदि आप ListViewअपने आप को स्क्रॉल स्थिति को सहेज रहे हैं / पुनर्स्थापित कर रहे हैं तो आप अनिवार्य रूप से एंड्रॉइड फ्रेमवर्क में पहले से लागू कार्यक्षमता को दोहरा रहे हैं। ListViewपुनर्स्थापित ठीक पुस्तक की स्थिति अभी अच्छी तरह से अपने आप ही को छोड़कर एक चेतावनी के रूप @aaronvargas उल्लेख वहाँ एक बग में है AbsListViewकि पहली सूची आइटम के लिए ठीक पुस्तक स्थिति बहाल करने के लिए नहीं दूँगा। फिर भी स्क्रॉल स्थिति को पुनर्स्थापित करने का सबसे अच्छा तरीका इसे पुनर्स्थापित करना नहीं है। एंड्रॉइड फ्रेमवर्क आपके लिए इसे बेहतर करेगा। बस सुनिश्चित करें कि आप निम्नलिखित शर्तों को पूरा कर चुके हैं:

  • सुनिश्चित करें कि आपने setSaveEnabled(false)विधि को नहीं बुलाया है और सेट नहीं किया हैandroid:saveEnabled="false" xml लेआउट फ़ाइल में सूची के लिए विशेषता
  • के लिए ExpandableListViewओवरराइड long getCombinedChildId(long groupId, long childId)विधि इतना है कि यह सकारात्मक लंबे संख्या (कक्षा में डिफ़ॉल्ट कार्यान्वयन रिटर्न BaseExpandableListAdapterरिटर्न नकारात्मक संख्या)। यहाँ उदाहरण हैं:

@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;
}
  • अगर ListViewया ExpandableListViewएक टुकड़े में प्रयोग किया जाता है तो गतिविधि के मनोरंजन (उदाहरण के लिए स्क्रीन रोटेशन के बाद) पर टुकड़े को फिर से न बनाएँ। के साथ टुकड़ा प्राप्त करते हैंfindFragmentByTag(String tag)विधि के ।
  • सुनिश्चित करें कि ListViewएक है android:idऔर यह अद्वितीय है।

पहली सूची आइटम के साथ पूर्वोक्त चेतावनी से बचने के लिए आप अपने एडॉप्टर को उस तरह से शिल्प कर सकते हैं जिस तरह से यह ListViewस्थिति के लिए विशेष डमी शून्य पिक्सेल ऊँचाई दृश्य लौटाता है । यहां सरल उदाहरण प्रोजेक्ट शो है ListViewऔर ExpandableListViewउनके ठीक स्क्रॉल पदों को पुनर्स्थापित करना है जबकि उनके स्क्रॉल पदों को स्पष्ट रूप से सहेजा नहीं गया है / बहाल। ठीक स्क्रॉल स्थिति कुछ अन्य अनुप्रयोग, डबल स्क्रीन रोटेशन और परीक्षण अनुप्रयोग पर वापस स्विच करने के लिए अस्थायी स्विचिंग के साथ जटिल परिदृश्यों के लिए भी पूरी तरह से बहाल है। कृपया ध्यान दें, यदि आप स्पष्ट रूप से एप्लिकेशन से बाहर निकल रहे हैं (बैक बटन दबाकर) तो स्क्रॉल स्थिति को बचाया नहीं जाएगा (साथ ही अन्य सभी दृश्य उनके राज्य को नहीं बचाएंगे)। https://github.com/voromto/RestoreScrollPosition/releases


0

ListActivity से प्राप्त एक गतिविधि के लिए जो LoaderManager.LoaderCallbacks को एक SimpleCursorAdapter का उपयोग करके लागू करता है, यह onReset () में स्थिति को पुनर्स्थापित करने के लिए काम नहीं करता था, क्योंकि गतिविधि को लगभग हमेशा पुनरारंभ किया गया था और विवरण देखने के बंद होने पर एडाप्टर को फिर से लोड किया गया था। चाल onLadFinished () में स्थिति को बहाल करने के लिए थी:

inListItemClick ():

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

inLoadFinished ():

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

ऑनबीबैपड्रेस ():

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

0

यहां दिए गए समाधानों में से कोई भी मेरे लिए काम नहीं करता था। मेरे मामले में, मेरे पास एक ListViewऐसा है Fragmentजिसमें मैं एक जगह ले रहा हूं FragmentTransaction, इसलिए Fragmentहर बार एक नया उदाहरण बनाया जाता है जब टुकड़ा दिखाया जाता है, जिसका अर्थ है कि ListViewराज्य को सदस्य के रूप में संग्रहीत नहीं किया जा सकता हैFragment

इसके बजाय, मैंने अपने कस्टम Applicationवर्ग में राज्य का भंडारण किया । नीचे दिए गए कोड से आपको पता चल जाएगा कि यह कैसे काम करता है:

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

}

मूल विचार यह है कि आप स्थिति को खंड के बाहर संग्रहीत करते हैं। यदि आपको अपनी एप्लिकेशन क्लास में एक स्थिर क्षेत्र होने का विचार पसंद नहीं है, तो मुझे लगता है कि आप इसे एक खंड इंटरफ़ेस लागू करके और अपनी गतिविधि में राज्य को संग्रहीत करके कर सकते हैं।

एक अन्य समाधान इसे स्टोर करना होगा SharedPreferences, लेकिन यह थोड़ा अधिक जटिल हो जाता है, और आपको यह सुनिश्चित करने की आवश्यकता होगी कि आप इसे एप्लिकेशन लॉन्च पर स्पष्ट कर दें, जब तक कि आप नहीं चाहते कि राज्य को ऐप लॉन्च के बाद जारी रखा जाए।

 

इसके अलावा, "पहले आइटम दिखाई देने पर सहेजे नहीं गए स्क्रॉल स्थिति" से बचने के लिए, आप 0pxऊंचाई के साथ एक डमी पहला आइटम प्रदर्शित कर सकते हैं । इसे getView()अपने एडॉप्टर में ओवरराइड करके प्राप्त किया जा सकता है , जैसे:

@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

मेरा जवाब फायरबेस और स्थिति 0 के लिए एक समाधान है

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

और कन्वर्ट

स्थिति 0 कोई रिक्त आइटम जोड़ें जिसका आप उपयोग नहीं कर रहे हैं

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

मैंने उपयोगकर्ता को परेशान किए बिना यह काम अस्थायी रूप से देखा है, मुझे आशा है कि यह आपके लिए काम करता है


0

इस नीचे दिए गए कोड का उपयोग करें:

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

और जब भी आपका ताज़ा आपका डेटा इस कोड का उपयोग करें:

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

0

मैं FirebaseListAdapter का उपयोग कर रहा हूं और काम करने का कोई भी समाधान नहीं निकाल सका। मैंने ऐसा करना समाप्त कर दिया। मैं अनुमान लगा रहा हूं कि और अधिक सुंदर तरीके हैं लेकिन यह एक पूर्ण और काम करने वाला समाधान है।

OnCreate से पहले:

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

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

चूंकि मुझे भी FirebaseRecyclerAdapter के लिए इसे हल करना था पोस्ट कर रहा हूं:

OnCreate से पहले:

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

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

0

रयान न्यूज़ोम के उत्कृष्ट उत्तर को स्पष्ट करने के लिए और इसे टुकड़ों के लिए समायोजित करने के लिए और सामान्य स्थिति के लिए जिसे हम "विवरण" के टुकड़े से "मास्टर" सूची में नेविगेट करना चाहते हैं और फिर "मास्टर" पर वापस जाएं।

    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
    }

यहां "मैजिक" यह है कि जब हम विवरण खंड से वापस सूची दृश्य टुकड़े पर नेविगेट करते हैं, तो दृश्य को फिर से बनाया नहीं जाता है, हम सूची दृश्य के एडेप्टर को सेट नहीं करते हैं, इसलिए सब कुछ वैसा ही रहता है जैसा हमने छोड़ा था!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.