2012-07-31 64 views
79

我們在ViewPager這裏遇到了一個非常奇怪的問題。我們在每個ViewPager頁面上嵌入列表,並在更新列表數據時在列表適配器和視圖分頁器適配器上觸發notifyDataSetChanged。ViewPager不重繪內容,仍然/變爲空白

我們觀察到的是,有時頁面不更新其視圖樹,即保持空白,或者有時甚至在分頁時消失。當來回分頁幾次時,內容會突然重新出現。這看起來好像Android缺少視圖更新。我還注意到,在使用層次結構查看器進行調試時,選擇視圖總是會使其重新出現,顯然是因爲層次結構查看器強制所選視圖重繪自己。

雖然我無法以編程方式使此工作;無效列表視圖或整個視圖尋呼機甚至無效。

這與compatibility-v4_r7庫有關。我也嘗試使用最新版本,因爲它聲稱修復了與查看尋呼機有關的許多問題,但它使問題變得更糟(例如,手勢被中斷,以至於它不會讓我有時再遍歷所有頁面)。

是否有其他人也遇到過這些問題,或者您有什麼可能導致此問題的想法?

回答

45

我們終於設法找到了解決方案。顯然我們的實現遭遇了兩個問題:

  1. 我們的適配器沒有刪除在destroyItem()中的視圖。
  2. 我們正在緩存視圖,因此我們只需要一次膨脹我們的佈局,並且由於我們沒有刪除destroyItem()中的視圖,因此我們不會將其添加到instantiateItem()中,而只是返回對應於當前位置的緩存視圖。

我沒有在ViewPager的源代碼看起來太深 - 這是不完全明確,你必須做到這一點 - 但該文檔說:

destroyItem()
刪除給定位置的頁面。該適配器負責從容器中刪除視圖,但它只需確保在從finishUpdate(ViewGroup)返回時完成此操作。

和:

一個非常簡單的PagerAdapter可以選擇使用網頁瀏覽自己爲主要對象,創建後從instantiateItem(ViewGroup中,INT)返回它們,並將它們添加到父ViewGroup中。一個匹配的destroyItem(ViewGroup,int,Object)實現將從父ViewGroup中移除視圖,而isViewFromObject(View,Object)可以實現爲返回視圖==對象;.

所以我的結論是,ViewPager依靠其底層適配器在instantiateItem()/destroyItem()明確添加/刪除其子女。也就是說,如果你的適配器是PagerAdapter的子類,你的子類必須實現這個邏輯。如果您使用ViewPager內的列表,請注意this

+4

不錯的工作,偵探! – Matthias 2012-08-31 18:06:22

+2

我有同樣的問題,但與FragmentPagerAdapter,它爲我處理onDestroy。這裏沒有其他的解決方案。 – 2014-02-18 22:24:22

+12

還可能是什麼問題,是@Boy你救了我的人正在使用,而不是GetChildFragmentManager – Boy 2014-11-16 09:21:56

6

ViewPager會嘗試在重複使用物品時做一些巧妙的事情,但它會要求您在事物發生變化時返回新的物品位置。嘗試添加這對您的PagerAdapter:

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

它基本上告訴ViewPager,一切都已經改變了(並迫使其重新實例一切)。這是我能想到的唯一一件事。

+1

是的,我讀過有關在這個線程此選項:http://stackoverflow.com/questions/7263291/viewpager-pageradapter-not-updating-the-view?rq=1 - 然而,這似乎是大錘方法。當然必須有更優雅的方式?我想知道它是否與使用列表作爲傳呼頁面有關? – Matthias 2012-07-31 09:34:28

+0

這是一個大錘的方法,但你可以從中回過頭來。即從該方法返回正確的值。 – 2012-07-31 10:59:02

+0

有道理,謝謝。 – Matthias 2012-07-31 12:12:07

0

Android支持庫包含一個演示Activity,其中包含每個頁面上帶有ListView的ViewPager。你應該看看它的功能。

在Eclipse(與Android開發工具R20):

  1. 選擇New > Android Sample Project
  2. 選擇目標API級別(我建議的最新可用)
  3. 選擇Support4Demos
  4. 右鍵單擊該項目並選擇Android Tools > Add Support Library
  5. 運行該應用程序並選擇Fragment,然後Pager

此代碼在src/com.example.android.supportv4.app/FragmentPagerSupport.java。祝你好運!

+0

謝謝 - 我會看看那個!也許我會發現一些我們錯誤的東西。 – Matthias 2012-07-31 10:33:12

0

我遇到了這個問題,並有非常類似的問題。我甚至在堆棧上溢出asked it

對於我來說,在父我的觀點的人的父的子類LinearLayout和推翻requestLayout()不調用super.requestLayout()。這阻止了我的ViewPager上調用onMeasureonLayout(儘管層次結構查看器手動調用這些)。沒有被測量,他們將在ViewPager中顯示爲空白。

因此,檢查您的包含意見。確保它們來自View的子類,並且不要盲目重寫requestLayout或類似的東西。

21

我有完全相同的問題,但我實際上銷燬了destroyItem中的視圖(我認爲)。然而,問題是,我把它用viewPager.removeViewAt(index);破壞insted的的viewPager.removeView((View) object);

錯誤:

@Override 
public void destroyItem(ViewGroup viewPager, int position, Object object) { 
    viewPager.removeViewAt(position); 
} 

右:

@Override 
public void destroyItem(ViewGroup viewPager, int position, Object object) { 
    viewPager.removeView((View) object); 
} 
+0

感謝您的提示。一直在研究這個問題很長一段時間。 – Moritz 2013-01-11 13:06:19

+2

這對我有效,但你知道爲什麼第一個是問題嗎? – HannahMitt 2014-07-01 16:13:43

+0

@HannahMitt removeViewAt將刪除ViewPager當前子項列表中的特定位置上的任何視圖,並且頁面可以以任何順序添加到ViewPager(因此,頁面0實際上可能位於索引1處的ViewPager中或其他任何位置)。 removeView將遍歷子列表並精確移除指定的對象。 – 2015-10-07 20:55:10

0

有同樣的問題,這是一件好事做ListView(因爲我如果列表爲空,空視圖顯示正常)。我只是在有問題的ListView上打電話requestLayout()。現在它畫得很好!

-1

我有類似的問題。我緩存視圖,因爲我只需要ViewPager中的3個視圖。當我向前滑動一切都沒問題但是當我開始向後滑動出現錯誤時,它說「我的視圖已經有一個父母」。解決方案是手動刪除不需要的項目。

@Override 
    public Object instantiateItem(ViewGroup container, int position) { 
     int localPos = position % SIZE; 
     TouchImageView view; 
     if (touchImageViews[localPos] != null) { 
      view = touchImageViews[localPos]; 
     } else { 
      view = new TouchImageView(container.getContext()); 
      view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 
      touchImageViews[localPos] = view; 
     } 
     view.setImageDrawable(mDataModel.getPhoto(position)); 
     Log.i(IRViewPagerAdpt.class.toString(), "Add view " + view.toString() + " at pos: " + position + " " + localPos); 
     if (view.getParent() == null) { 
     ((ViewPager) container).addView(view); 
    } 
     return view; 
    } 

    @Override 
    public void destroyItem(ViewGroup container, int position, Object view) { 
     //  ((ViewPager) container).removeView((View) view); 
     Log.i(IRViewPagerAdpt.class.toString(), "remove view " + view.toString() + " at pos: " + position); 
    } 

.................. 

private static final int SIZE = 3; 
private TouchImageView[] touchImageViews = new TouchImageView[SIZE]; 
0

我在使用ViewPager和FragmentStatePagerAdapter時遇到了同樣的問題。我試着用一個3秒延遲的處理程序來調用invalidate()和requestLayout(),但它不起作用。做什麼工作是重置viewPager的背景顏色,如下所示:

MyFragment.java

private Handler mHandler; 
    private Runnable mBugUpdater; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     View rootView = new ViewPager(getActivity()); 
     //...Create your adapter and set it here... 

     mHandler = new Handler(); 
     mBugUpdater = new Runnable(){ 
      @Override 
      public void run() { 
       mVp.setBackgroundColor(mItem.getBackgroundColor()); 
       mHandler = null; 
       mBugUpdater = null; 
      }   
     }; 
     mHandler.postDelayed(mBugUpdater,50); 

     return rootView; 
    } 

    @Override 
    public void onPause() { 
     if(mHandler != null){ 
      //Remove the callback if it hasn't triggered yet 
      mHandler.removeCallbacks(mBugUpdater); 
      mHandler = null; 
      mBugUpdater = null; 
     } 
     super.onPause(); 
    } 
41

如果ViewPager設置一個片段裏面有FragmentPagerAdapter,使用getChildFragmentManager()代替getSupportFragmentManager()作爲參數來初始化你FragmentPagerAdapter

mAdapter = new MyFragmentPagerAdapter(getChildFragmentManager()); 

而不是

mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager()); 
+2

良好的捕獲,它似乎解決了我的問題,當使用FragmentPagerAdapter – Tobliug 2016-03-18 10:48:22

+1

謝謝 - 這工作。我試圖強制'FragmentPagerAdapter'上的'getItem()'嵌套在重新創建的Fragment中。 – 2016-04-22 07:15:36

+1

令人印象深刻的趕上。謝謝 – user3819810 2016-07-25 10:40:09

0

對我來說,問題是回來的活動應用程序過程中被殺害後。我正在使用從Android來源修改的自定義視圖尋呼機適配器。視圖尋呼機直接嵌入到活動中。

調用viewPager.setCurrentItem(position, true);

(動畫)設定的數據和notifyDataSetChanged()後,似乎工作,但如果該參數設置爲false,它不和片段是空白。這是一個可能對某人有幫助的邊緣案例。

1

我有同樣的症狀的問題,而是一個不同的原因是竟然是我的一個愚蠢的錯誤。以爲我會在這裏添加它以防萬一。

我有一個ViewPager使用FragmentStatePagerAdapter其用於具有兩個片段,但我後來添加的三分之一。但是,我忘記了默認的屏幕頁面限制爲1 - 因此,當我切換到新的第三個片段時,第一個片段會被破壞,然後在切換回來之後重新創建。問題是我的活動負責通知這些片段初始化它們的UI狀態。當活動和片段生命週期相同時,這恰好工作,但爲了解決這個問題,我必須在啓動生命週期中更改片段以初始化他們自己的UI。最後,我也結束了改變setOffscreenPageLimit 2,這樣(因爲他們不是很內存密集型在這種情況下是安全的)所有的三個片段,更讓在任何時候。