从ViewPager迁移到ViewPager2中遇到的问题
ou2356 opened this issue · comments
我的ViewPager2中管理着3个Fragment,其中两个Fragment都有RecyclerView,这两个RecyclerView都管理着同样的实时更新的item数据,但是我发现在ViewPager2中当RecyclerView有item数据实时更新出来时所有的item都会闪烁或者发生奇怪的偏移。但是这一系列的现象在ViewPager中都没有出现到,我对这个现象进行了一系列的追溯,有了一点眉目,但不知道该如何解决这个问题,下面展示3种我调试的现象,欢迎大家来参观讨论,我挺期待用上ViewPager2的:
现象1(ViewPager2的问题现象):
Clipchamp.mp4
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Theme.AppCompat.DayNight"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="@+id/view_pager2">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="20dp" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@+id/app_bar_layout"
app:layout_constraintBottom_toTopOf="@+id/sendMsgEt"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
viewPager2 = findViewById(R.id.view_pager2);
tabLayout = findViewById(R.id.tab_layout);
//禁止ViewPager的左右滑动
viewPager2.setUserInputEnabled(false);
viewPager2.setOffscreenPageLimit(3);
viewPager2.setAdapter(new FragmentStateAdapter(supportFragmentManager, getLifecycle()) {
@NonNull
@Override
public Fragment createFragment(int position) {
switch (position){
case 0 :
chatFragment = new mChatFragment();
return chatFragment;
case 1 :
terminalFragment = new mTerminalFragment();
return terminalFragment;
case 2 :
controlFragment = new mControlFragment();
return controlFragment;
default:
return null;
}
}
@Override
public int getItemCount() {
return 3;
}
});
tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager2, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
//ViewPager选中时对Tab执行的代码
switch (position){
case 0 :
tab.setText("对话模式");
break;
case 1 :
tab.setText("终端模式");
break;
case 2 :
tab.setText("控件模式");
break;
default: break;
}
}
});
tabLayoutMediator.attach();
messageRecyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
Log.e("RecyclerViewLayout","newTop:"+top+"\tnewBottom:"+bottom);
}
});
OnLayoutChangeListener中捕获的日志如下(RecyclerView每新增一个item其中的newBottom都会发生两次改变先是0后面变成1953,我认为导致这个问题的原因就在于newBottom改变成了0):
于是我对令newBottom变成0的代码经行了追溯,发现下面两处有可能是导致newBottom变成0的代码(我能力有限,只能debug后建立断点后一点点往回看,希望理解),令我好奇的是下面两处代码在newBottom变成1953时并没有被执行,这也让我更加肯定下面两处代码把newBottom变成了0:
现象2(把xml布局文件中ViewPager2的layout_height="0dp"修改成固定的"350dp",其它部分代码同上)
Clipchamp.mp4
修改后的xml代码如下
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager2"
android:layout_width="match_parent"
android:layout_height="350dp"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@+id/app_bar_layout"
app:layout_constraintBottom_toTopOf="@+id/sendMsgEt"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
捕获日志如下(可见RecyclerView每新增一个item其中的newBottom只更新了一次,且都为963,可以说没有改变,一切正常,但这样的固定值的布局显然不是我想要的):
现象3(把ViewPager2改回用ViewPager)
Clipchamp.mp4
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Theme.AppCompat.DayNight"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="@+id/view_pager">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="20dp" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@+id/app_bar_layout"
app:layout_constraintBottom_toTopOf="@+id/sendMsgEt"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setOffscreenPageLimit(3);
viewPager.setAdapter(new FragmentPagerAdapter(supportFragmentManager) {
@NonNull
@Override
public Fragment getItem(int position) {
switch (position){
case 0 :
chatFragment = new mChatFragment();
return chatFragment;
case 1 :
terminalFragment = new mTerminalFragment();
return terminalFragment;
case 2 :
controlFragment = new mControlFragment();
return controlFragment;
default:
return null;
}
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position){
switch (position){
case 0 :
return "对话模式";
case 1 :
return "终端模式";
case 2 :
return "控件模式";
default:
return null;
}
}
});
TabLayout tabLayout = findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(viewPager);
最后贴上RecyclerView的item更新代码
private void refreshMsgUI(){
((AppCompatActivity)context).runOnUiThread(()->{
terminalFragment.recyclerViewAdapter.notifyItemInserted(terminalFragment.recyclerViewAdapter.getItemCount()-1);
if (isTerScrollToBottom) {
terminalFragment.messageRecyclerView.scrollToPosition(terminalFragment.recyclerViewAdapter.getItemCount()-1);
}
chatFragment.recyclerViewAdapter.notifyItemInserted(chatFragment.recyclerViewAdapter.getItemCount()-1);
if (isChatScrollToBottom) {
chatFragment.messageRecyclerView.scrollToPosition(chatFragment.recyclerViewAdapter.getItemCount()-1);
}
});
}