在PagerAdapter上调用notifyDataSetChanged后,TabLayout滚动到未知位置 [英] TabLayout scrolls to unkown position after calling notifyDataSetChanged on PagerAdapter

查看:107
本文介绍了在PagerAdapter上调用notifyDataSetChanged后,TabLayout滚动到未知位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有带有TabLayoutPagerAdapter的示例项目. 当我在tabLayout.setupWithViewPager(viewPager);

I have sample project with TabLayout and PagerAdapter. Strange things happens with TabLayout when I call pagerAdapter.notifyDataSetChanged(); after tabLayout.setupWithViewPager(viewPager);

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

TabLayout is scrolling to unknown x position so the current tab is not visible. However if I scroll to left to expecting tab, this tab has indicator.

这是怎么回事?有人可以帮我吗?我花了太多时间.

What is going on? Could anyone help me? I have spent on it too many time.

代码下方.

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

}

我在nexus模拟器和nexus真实设备(api 21+)上进行了测试

I tested on nexus emulators and nexus real devices (api 21+)

成绩设置:

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

链接到已报告的问题,并准备作为附件测试项目 这里

Link to reported issue and ready to test project as attachment here

推荐答案

每次使用setupWithViewPager的设置视图分页器可能代价很高.因为ViewPager适配器上的notifyDataSetChanged()导致TabLayout重绘其所有视图.因此,对于重新绘制,TabLayout删除其所有关联的Views并重新添加它们.

Every time setup view pager with the use of setupWithViewPager might be costly. Because notifyDataSetChanged() on your ViewPager Adapter causing TabLayout to redraw its all views. So for redrawing, TabLayout remove all its associated Views and re add them.

请检查下面的线程执行步骤,这些步骤在notifyDataSetChanged之后在寻呼机适配器上进行.

Please check below thread execution steps which happen after notifyDataSetChanged on pager adapter.

  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)

根据线程执行-

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

Clicked on Action Button > Pager Adapter Notified for data set changed > TabLayout got notification of data change through observers > It try to populate new data from adapter > Removed all tabs.

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

Below is a code of TabLayout class, from which you can check whenever all tabs are going to remove then last selected tab is lost(Intentionally marked null).

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

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

To retain last selected tab I have created my own CustomTabLayout class and retained last selected position.

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

最后,请确保在重新创建TabLayout之后重新选择选项卡.

At the end make sure to reselect your tab after recreation of your 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);
        }
    });

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

This issue will resolve your problem but what I believe is TabLayout must have to retain last selected position in case of data set change. This is what I understand, any comments or more understanding is welcome.

这篇关于在PagerAdapter上调用notifyDataSetChanged后,TabLayout滚动到未知位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆