在PagerAdapter上调用notifyDataSetChanged后,TabLayout会滚动到未知位置

dea*_*ish 7 android android-tablayout

我有一个示例项目TabLayout和PagerAdapter.奇怪的事情发生了TabLayout当我打电话pagerAdapter.notifyDataSetChanged();后,tabLayout.setupWithViewPager(viewPager);

TabLayout滚动到未知的x位置,因此当前选项卡不可见.但是,如果我向左滚动到期望选项卡,则此选项卡有指示符.

到底是怎么回事?谁能帮助我?我花了太多时间.

在此输入图像描述

代码下方.

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Get the ViewPager and set it's PagerAdapter so that it can display items
        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        final SampleFragmentPagerAdapter pagerAdapter = new SampleFragmentPagerAdapter(getSupportFragmentManager(), MainActivity.this);
        viewPager.setAdapter(pagerAdapter);

        // Give the TabLayout the ViewPager
        TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
        tabLayout.setupWithViewPager(viewPager);

        findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                pagerAdapter.notifyDataSetChanged();
            }
        });
    }

}
Run Code Online (Sandbox Code Playgroud)

我测试了nexus仿真器和nexus真实设备(api 21+)

Gradle设置:

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "xx.xxx.myapplication4"
        minSdkVersion 21
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

链接到报告的问题并准备在此处测试项目作为附件

Rah*_*hul 7

每次使用设置视图寻呼机setupWithViewPager可能都是昂贵的.因为notifyDataSetChanged()在ViewPager适配器上导致TabLayout重绘其所有视图.因此,对于重绘,TabLayout删除所有关联的Views并重新添加它们.

请检查以下notifyDataSetChanged在寻呼机适配器之后发生的线程执行步骤.

  at android.support.design.widget.TabLayout.removeAllTabs(TabLayout.java:654)
  at android.support.design.widget.TabLayout.populateFromPagerAdapter(TabLayout.java:904)
  at android.support.design.widget.TabLayout$PagerAdapterObserver.onChanged(TabLayout.java:2211)
  at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37)
  - locked <0x129f> (a java.util.ArrayList)
  at android.support.v4.view.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:287)
  at com.sample.testtablayout.MainActivity$1.onClick(MainActivity.java:45)
Run Code Online (Sandbox Code Playgroud)

根据线程执行 -

单击操作按钮>寻呼机适配器通知已更改数据集> TabLayout通过观察者获得数据更改通知>它尝试从适配器填充新数据>删除所有选项卡.

下面是一个TabLayout类代码,您可以从中检查所有选项卡何时删除,然后最后选择的选项卡丢失(故意标记为空).

/**
 * Remove all tabs from the action bar and deselect the current tab.
 */
public void removeAllTabs() {
    // Remove all the views
    for (int i = mTabStrip.getChildCount() - 1; i >= 0; i--) {
        removeTabViewAt(i);
    }

    for (final Iterator<Tab> i = mTabs.iterator(); i.hasNext();) {
        final Tab tab = i.next();
        i.remove();
        tab.reset();
        sTabPool.release(tab);
    }

    mSelectedTab = null; // Thats a cause for your issue.
}
Run Code Online (Sandbox Code Playgroud)

为了保留最后选择的选项卡,我创建了自己的CustomTabLayout类并保留了最后选择的位置.

public class RetainableTabLayout extends TabLayout {

   /*
   * Variable to store invalid position.
   */
   private static final int INVALID_TAB_POS = -1;

   /*
   * Variable to store last selected position, init it with invalid tab position.
   */
   private int mLastSelectedTabPosition = INVALID_TAB_POS;

   public RetainableTabLayout(Context context) {
       super(context);
   }

   public RetainableTabLayout(Context context, AttributeSet attrs) {
       super(context, attrs);
   }

   public RetainableTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
  }

   @Override
    public void removeAllTabs() {
       // Retain last selected position before removing all tabs
       mLastSelectedTabPosition = getSelectedTabPosition();
       super.removeAllTabs();
   }

   @Override
   public int getSelectedTabPosition() {
       // Override selected tab position to return your last selected tab position
       final int selectedTabPositionAtParent = super.getSelectedTabPosition();
       return selectedTabPositionAtParent == INVALID_TAB_POS ? 
              mLastSelectedTabPosition : selectedTabPositionAtParent;
   }
}
Run Code Online (Sandbox Code Playgroud)

最后一定要在重新创建之后重新选择标签TabLayout.

findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            pagerAdapter.notifyDataSetChanged();
            // At the end make sure to reselect your last item.
            new Handler().postDelayed(
                    new Runnable() {
                        @Override
                        public void run() {
                            final TabLayout.Tab selectedTab = tabLayout.getTabAt(
                                 tabLayout.getSelectedTabPosition());
                            if (selectedTab != null) {
                                selectedTab.select();
                            }
                        }
                    }, 100);
        }
    });
Run Code Online (Sandbox Code Playgroud)

此问题将解决您的问题,但我认为TabLayout必须保留最后选择的位置以防数据集更改.这是我所理解的,欢迎任何评论或更多理解.

  • .notifyDataSetChanged之后,无需创建新的Handler()并设置延迟。TabLayout包含处理程序。使用tabLayout.post() (2认同)

小智 6

您可以致电:

setupWithViewPager(@Nullable final ViewPager viewPager, boolean autoRefresh)
Run Code Online (Sandbox Code Playgroud)

并将参数设置autoRefresh为false.

也可以看看: TabLayout(ViewPager,boolean)


Rau*_*pan 0

可以直接设置当前位置。

您可以在通知数据集更改之前获取所选位置并将其保存在静态变量中并每次更新:

public static tabPostion;

    @Override
    public void onTabSelected(TabLayout.Tab tab) {
      tabPostion = tab.getPosition();
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {

    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {

    }

//set the postion of the pervious tab
    yourviewpager.setCurrentItem(tabPostion);
Run Code Online (Sandbox Code Playgroud)

下面是我的项目的代码:

   @Override
    public void onTabSelected(TabLayout.Tab tab) {

        // imageHashMap = new HashMap<>();
        onClearOrSelectAllImage(FlickQuickEnum.PIC_SELECTION_ACTION.CLEAR);
        selectedImageUrls = new HashMap<>();
        String tag = tab.getText().toString();
        String tagName = tag.substring(1, tag.length());
        currentTab = tagName;
        if (tagName != null) {
            dbAlbumPhotoList = new ArrayList<>();
            if (tagName.equals("All")) {
                dbAlbumPhotoList = dbAlbumPhotosHashMap.get(album.getAlbumName());
            } else {
                dbAlbumPhotoList = dbAlbumPhotosHashMap.get(tagName);
            }
        }
        updatePhotoCount();
        setPhotosSelectedActions(false);
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {

    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {

    }
Run Code Online (Sandbox Code Playgroud)