2015-09-02 36 views
7

Zastanawiałem się, czy to normalne zachowanie viewpager i jego adapter, aby zawsze wywoływać metodę getItem() dla indeksu 0 i 1, nawet jeśli natychmiast ustawię aktualną pozycję.ViewPager Adapter getItem zawsze wołał o indeks 0 i 1

Oto mój kod:

mNewsPagerAdapter = new NewsDetailPagerAdapter(getChildFragmentManager()); 
mNewsPagerAdapter.updateNewsList(news); 

mViewPager = (ViewPager) mView.findViewById(R.id.horizontal_view_pager); 
mViewPager.setPageMargin(2); 
mViewPager.setPageMarginDrawable(R.color.black); 

mViewPager.setAdapter(mNewsPagerAdapter); 
mViewPager.setCurrentItem(mCurrentPositionPager, false); 

Gdybym przejść z mojej działalności głównej do mojej działalności szczegółowo z tym viewpager, adapter zawsze wywołuje metodę getItem() do pozycji 0 i 1, a po tej metodzie getItem() dla pozycja mOriginalPosition i jej sąsiadów. Zastanawiałem się, czy to jest prawidłowe zachowanie, czy też przeoczyłem coś, aby wdrożyć je we właściwy sposób. Dzięki za pomoc :)

Edycja: Dodano mój kod adapter

public class NewsDetailPagerAdapter extends FragmentStatePagerAdapter { 

private SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>(); 

private ArrayList<News> mNewsList; 

public NewsDetailPagerAdapter(FragmentManager fm) { 
    super(fm); 
} 

/** 
* Setzt die neuen News. 
**/ 
public void updateNewsList(ArrayList<News> list) { 
    mNewsList = list; 
} 

@Override 
public Fragment getItem(int position) { 
    Log.d("debug", "getItem position:" + position); 
    News newsItem = mNewsList.get(position); 


    NavigationFragment fragment = new NavigationFragment(); 

    mPageReferenceMap.put(position, fragment); 

    return fragment; 
} 


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

@Override 
public int getItemPosition(Object object) { 
    return POSITION_NONE; 
} 

public Fragment getFragment(int position) { 
    return mPageReferenceMap.get(position); 
} 

}

+0

jaką wartość chcesz odzyskać dzięki metodzie getcount firmy Newspageradapert – koutuk

+0

@jennymo Jaką pozycję ustawiasz? – forcewill

+0

dodaj swój kod adaptera –

Odpowiedz

1

Właściwie jest to zachowanie normale. W rzeczywistości, jako soos wiążący ViewPager z adapterem, adapter tworzy pierwszy układ widoczności (indeks 0), kończący następny (indeks 1). Robi się to domyślnie w "setAdapter". Następnie, gdy ustawisz inną pozycję, adapter utworzy fragment na wybranym indeksie, poprzedni i następny.

Jest to zwykły kod ViewPager setAdapter:

public void setAdapter(PagerAdapter adapter) { 
    if (mAdapter != null) { 
     mAdapter.setViewPagerObserver(null); 
     mAdapter.startUpdate(this); 
     for (int i = 0; i < mItems.size(); i++) { 
      final ItemInfo ii = mItems.get(i); 
      mAdapter.destroyItem(this, ii.position, ii.object); 
     } 
     mAdapter.finishUpdate(this); 
     mItems.clear(); 
     removeNonDecorViews(); 
     mCurItem = 0; 
     scrollTo(0, 0); 
    } 

    final PagerAdapter oldAdapter = mAdapter; 
    mAdapter = adapter; 
    mExpectedAdapterCount = 0; 

    if (mAdapter != null) { 
     if (mObserver == null) { 
      mObserver = new PagerObserver(); 
     } 
     mAdapter.setViewPagerObserver(mObserver); 
     mPopulatePending = false; 
     final boolean wasFirstLayout = mFirstLayout; 
     mFirstLayout = true; 
     mExpectedAdapterCount = mAdapter.getCount(); 
     if (mRestoredCurItem >= 0) { 
      mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); 
      setCurrentItemInternal(mRestoredCurItem, false, true); 
      mRestoredCurItem = -1; 
      mRestoredAdapterState = null; 
      mRestoredClassLoader = null; 
     } else if (!wasFirstLayout) { 
      populate(); 
     } else { 
      requestLayout(); 
     } 
    } 

    if (mAdapterChangeListener != null && oldAdapter != adapter) { 
     mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter); 
    } 
} 

W celu zmiany zachowania ViewPager, można przedłużyć klasyczny ViewPager przesłanianie metody setAdapter i ustawić mCurrItem do żądanej pozycji.

Mam nadzieję, że to pomogło

Edit:

Po różnych badaniach, znaleźliśmy rozwiązanie.

Jeśli adapter ViewPager jest ustawiony po wyświetleniu układu ViewPager, elementy 0 i 1 są załadowane. Jeśli chcesz uniknąć tego zachowania, ale nie możesz ustawić adaptera zanim układ stanie się widoczny (ponieważ czekasz na dane), możesz użyć tego obejścia:

1) Ustaw widoczność ViewPager na GONE

2) Po otrzymaniu wszystkich danych, aktualizacji adaptera i ustawić aktualną wartość elementu

3) Wreszcie można ustawić widoczność ViewPager widocznych

Tutaj można znaleźć przykład:

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
         Bundle savedInstanceState) { 

    View v = inflater.inflate(R.layout.detail_overview_fragment, container, false); 

    final int position = getArguments().getInt("position"); 
    final ViewPager viewPager = (ViewPager) v.findViewById(R.id.viewpager); 
    viewPager.setVisibility(View.GONE); 

    Handler handler = new Handler(); 
    handler.postDelayed(new Runnable() { 
     @Override 
     public void run() { 
      viewPager.setAdapter(new PagerAdapter(getChildFragmentManager())); 
      viewPager.setCurrentItem(position); 
      viewPager.setVisibility(View.VISIBLE); 

     } 
    },5000); 

    return v; 
} 
+0

Ale mam inny projekt z domyślnym androidem viewpager i nie pokazuje on opisanego zachowania ... więc myślę, że w moim kodzie musi być błąd . Niestety nie jestem w stanie dostrzec różnicy w obu implementacjach, ponieważ wyglądają one prawie tak samo -. – jennymo

+0

Czy możesz w jakiś sposób udostępnić projekt, w którym viewPager nie ładuje fragmentów w indeksie 0 i 1, gdy pojawia się setAdapter? To jest "dziwne" zachowanie i jestem pewien, że jest coś dziwnego w konfiguracji .. –

+0

To jest link do projektu: https://drive.google.com/open?id=0B1aHkcAaWIA-NGhVYUtzcnVKU1k. Jak widać, jest to naprawdę prosta implementacja i adapter nie tworzy fragmentów w indeksie 0 i 1, jeśli wybiorę element 15 na przykład. Chcę tego zachowania w moim projekcie aplikacji powyżej z powodu problemów z permamentami: D Więc jestem naprawdę sceptyczny, jeśli tworzenie dwóch poprzednich fragmentów 0 i 1 jest naprawdę pożądanym zachowaniem google ... :) – jennymo

2

Tak, jest to normalne zachowanie ViewPagera, ponieważ zawsze będzie starał się wyprzedzić użytkownika, wyświetlając karty ograniczające się w obszarze rysunku. Osobiście nie polecam tworzenia niestandardowego ViewPagera, ponieważ prawie na pewno przełamiesz funkcjonalność, chyba że naprawdę wiesz, co robisz.Klasa adapter powinien wyglądać mniej więcej tak:

public class YourCustomPagerAdapter extends FragmentStatePagerAdapter { 
    private List<Fragment> fragmentList = new ArrayList<>(); 
    private List<String> titleList = new ArrayList<>(); 

    public WizardPagerAdapter(FragmentManager fm) { 
     super(fm); 
    } 

    public void addFragment(Fragment fragment, String title) { 
     fragmentList.add(fragment); 
     titleList.add(title); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     return fragmentList.get(position); 
    } 

    @Override 
    public CharSequence getPageTitle(int position) { 
     super.getPageTitle(position); 
     return titleList.get(position); 
    } 

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

i należy dodać fragmenty jako takie:

@Override 
public void onCreate(Bundle savedInstanceState) { 
    ... 
    YourCustomPagerAdapter adapter = new YourCustomPagerAdapter (getSupportFragmentManager()); 
    adapter.addFragment(FragmentOne.newInstance(), "Frag 1"); 
    adapter.addFragment(FragmentTwo.newInstance(), "Frag 2"); 
    viewPager.setAdapter(adapter); 
    ... 
} 
+0

Nie utworzyłem niestandardowego podglądu, jest to domyślny widok na Androida. I jak wspomniałem w moim komentarzu kilka postów poniżej, otrzymałem także inny projekt android z viewpagerem, w którym to zachowanie nie występuje. Więc myślałem, że to musi być błąd w moim obecnym projekcie. A tak przy okazji ... Zmieniłem adapter na twoje rozwiązanie, ale niestety wciąż nie udało się – jennymo

+0

Bez powodzenia robienia czego? Twoje pytanie dotyczyło oczekiwanego zachowania ViewPager. Jeśli podasz dalej, być może będę mógł pomóc. – Chisko

+0

Naprawdę chcę tej nagrody: P – Chisko

-1

myślę, że błędem jest adapter:

/** 
    * Setzt die neuen News. 
    **/ 
    public void updateNewsList(ArrayList<News> list) { 
     //mNewsList = list; 
     mNewsList.clear(); 
     mNewsList.addAll(list); 
     /** 
     * Notifies the attached observers that the underlying data has been changed 
     * and any View reflecting the data set should refresh itself. 
     */ 
     this.notifyDataSetChanged(); 
    } 

błąd powód: ta lista jest innym elementem dla tego adaptera.

+0

Nie, niestety to nie rozwiązuje problemu – jennymo

2

Jest to normalne (i inteligentne w mojej opinii). Klasa ViewPager ma jedną właściwość o nazwie mOffscreenPageLimit z domyślną wartością 1. Liczba ta określa liczbę stron po lewej i prawej stronie bieżącej strony, które Viewpager wstępnie załaduje. Na przykład masz 10 stron, aktualna pozycja to 5, a mOffcreenPageLimit 1, strona na pozycji 4 i 6 zostanie załadowana.

Można zmienić tę właściwość przez wywołanie tej metody

viewpager. setOffscreenPageLimit(int) 

Jeśli przejdzie w całkowitą, która jest mniejsza niż 1, to nie ma znaczenia.