Android 在PagerAdapter上调用notifyDataSetChanged后,TableLayout滚动到未知位置
我有一个带有Android 在PagerAdapter上调用notifyDataSetChanged后,TableLayout滚动到未知位置,android,android-tablayout,Android,Android Tablayout,我有一个带有TabLayout和PagerAdapter的示例项目。 调用pagerAdapter.notifyDataSetChanged()时,TableLayout会发生奇怪的事情在表格布局之后。使用viewPager(viewPager)设置 TabLayout正在滚动到未知的x位置,因此当前选项卡不可见。但是,如果我向左滚动到预期选项卡,则该选项卡具有指示器 发生了什么事?有人能帮我吗?我花在这上面的时间太多了 下面是代码 public class MainActivity exte
TabLayout
和PagerAdapter
的示例项目。
调用pagerAdapter.notifyDataSetChanged()时,TableLayout会发生奇怪的事情代码>在<代码>表格布局之后。使用viewPager(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();
}
});
}
}
我在nexus模拟器和nexus real设备(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'
}
}
}
链接到报告的问题并准备作为附件测试项目您可以直接设置当前位置
您可以在通知数据集更改之前获取所选位置,并将其保存在静态变量中,并每次更新:
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);
以下是我的项目中的代码:
@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) {
}
@覆盖
已选择的公共选项卡(TabLayout.Tab){
//imageHashMap=新建HashMap();
onClear或SelectalImage(flickum.PIC\u SELECTION\u ACTION.CLEAR);
selectedImageUrls=newHashMap();
String tag=tab.getText().toString();
字符串标记名=tag.substring(1,tag.length());
currentTab=标记名;
if(标记名!=null){
dbAlbumPhotoList=新的ArrayList();
if(标记名.equals(“全部”)){
dbAlbumPhotoList=dbAlbumPhotosHashMap.get(album.getAlbumName());
}否则{
dbAlbumPhotoList=dbAlbumPhotosHashMap.get(标记名);
}
}
updatePhotoCount();
SetPhotoselectedActions(假);
}
@凌驾
已选择的公共选项卡(TabLayout.Tab){
}
@凌驾
已重新选择公共选项卡(TabLayout.Tab){
}
每次使用setupWithViewPager
设置查看寻呼机时,成本可能会很高。因为ViewPager适配器上的notifyDataSetChanged()
,导致TableLayout重新绘制其所有视图。因此,对于重绘,TabLayout
删除所有相关的视图
并重新添加它们
请检查寻呼机适配器上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)
为了保留上次选择的选项卡,我创建了自己的CustomTableLayout类并保留了上次选择的位置
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;
}
}
最后,确保在重新创建表格布局后重新选择选项卡
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
必须保留上次选择的位置,以防数据集更改。这就是我所理解的,欢迎任何评论或更多的理解。我刚刚在Rasi的TableLayout实现中添加了notifyDataSetChanged方法
它对我有用
public class CustomTabLayout 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 CustomTabLayout(Context context) {
super(context);
}
public CustomTabLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomTabLayout(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;
}
public void notifyDataSetChanged() {
post(new Runnable() {
@Override
public void run() {
TabLayout.Tab selectedTab = getTabAt(getSelectedTabPosition());
if (selectedTab != null) {
selectedTab.select();
}
}
});
}
}
并通知电话
mPagerAdapter.notifyDataSetChanged();
mCustomTabLayout.notifyDataSetChanged();
你可以致电:
setupWithViewPager(@Nullable final ViewPager viewPager, boolean autoRefresh)
并将paramautoRefresh
设置为false
另请参见:如果要解决此问题,您需要修改TabLayout源代码
void populateFromPagerAdapter() {
removeAllTabs();
if (mPagerAdapter != null) {
final int adapterCount = mPagerAdapter.getCount();
for (int i = 0; i < adapterCount; i++) {
addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
}
// need call post to run the code, to fix children views not layout
post(new Runnable() {
@Override
public void run() {
// Make sure we reflect the currently set ViewPager item
if (mViewPager != null && adapterCount > 0) {
final int curItem = mViewPager.getCurrentItem();
if (curItem != getSelectedTabPosition() && curItem < getTabCount()) {
selectTab(getTabAt(curItem));
}
}
}
});
}
}
void populateFromPagerAdapter(){
移除所有选项卡();
if(mPagerAdapter!=null){
final int adapterCount=mPagerAdapter.getCount();
对于(int i=0;i0){
final int curItem=mViewPager.getCurrentItem();
if(curItem!=getSelectedTabPosition()&&curItem
你能发布那个项目吗?点击蓝色链接这里
-我帖子的最后一段错误来自第行:如果没有-(getWidth()/2)
它会按预期工作。您可以在从方法返回并将scrollBase
值更改为正确值之前放置一个断点。看。很好的一个,我能设法破解它吗?我试着通过反射来实现,但没有足够的接缝来实现。尽管如此,-width
还是有道理的,这意味着你会通过改变它来破坏其他东西。我想应该有一些if-else语句。是的,这段代码来自我的项目,它工作正常。我还刷新了一些操作选项卡的UI,但我没有使用notifydatasetchange,相反,我使用Eventbus根据我的need@deadfish我已经在我的应用程序中使用了这段代码,它在fineAfter中运行良好。notifyDataSetChanged无需创建新的处理程序()和设置延迟。TabLayout包含处理程序。使用tabLayout.post()非常感谢您的回答@Mohammadnabil我的荣幸您也可以使用该库如果您有一个带有片段的自定义viewPager的表格布局,此解决方案将非常有效。我需要更新片段UI,但它在onTabSelected中崩溃了,因为它重新绘制了选项卡内容。我花了大约3个小时来实现这一点。重置viewPager在内存管理方面不是很昂贵吗?这就是notifyDataSetChanged()出现在图片中的原因。这似乎是Rahul现有答案的更清晰版本,如上所示:
void populateFromPagerAdapter() {
removeAllTabs();
if (mPagerAdapter != null) {
final int adapterCount = mPagerAdapter.getCount();
for (int i = 0; i < adapterCount; i++) {
addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
}
// need call post to run the code, to fix children views not layout
post(new Runnable() {
@Override
public void run() {
// Make sure we reflect the currently set ViewPager item
if (mViewPager != null && adapterCount > 0) {
final int curItem = mViewPager.getCurrentItem();
if (curItem != getSelectedTabPosition() && curItem < getTabCount()) {
selectTab(getTabAt(curItem));
}
}
}
});
}
}