我正在尝试使用新的ViewPager2构建Android应用程序。我添加了两个由视图分隔的ViewPagers,并且当您滑动时,两个viewpagers都应移动。两个视图寻呼机均正确移动,但手势完成后,滑动视图闪烁,并且未滑动视图重新加载,如随附的gif所示。这是我的Activity,ViewPagerAdapter和Fragment的代码。感谢您的帮助
public class MainActivity extends FragmentActivity {
ActivityMainBinding viewBinding;
MyPager adapter1, adapter2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
List<String> data = populateData();
adapter1 = new MyPager(this, data);
adapter2 = new MyPager(this, data);
viewBinding.viewPager.setAdapter(adapter1);
viewBinding.viewPager2.setAdapter(adapter2);
viewBinding.viewPager2.setOffscreenPageLimit(data.size());
viewBinding.viewPager.setOffscreenPageLimit(data.size());
viewBinding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
viewBinding.viewPager2.scrollTo(positionOffsetPixels, 0);
}
@Override
public void onPageScrollStateChanged(final int state) {
viewBinding.viewPager2.setCurrentItem(viewBinding.viewPager.getCurrentItem(), true);
}
});
viewBinding.viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
viewBinding.viewPager.scrollTo(positionOffsetPixels, 0);
}
@Override
public void onPageScrollStateChanged(final int state) {
viewBinding.viewPager.setCurrentItem(viewBinding.viewPager2.getCurrentItem(), true);
}
});
}
private List<String> populateData() {
List<String> data = new ArrayList<>();
for (int x = 0; x < 10; x++) {
String derril = "derril " + x;
data.add(derril);
}
return data;
}
}
public class MyPager extends FragmentStateAdapter {
List<String> data;
public MyPager(@NonNull FragmentActivity fragmentActivity, List<String> data) {
super(fragmentActivity);
this.data = data;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return DerrilFragment.newInstance(data.get(position));
}
@Override
public int getItemCount() {
return data.size();
}
}
public class DerrilFragment extends Fragment {
PizzaBinding viewBinding;
String data;
private DerrilFragment(String data) {
this.data = data;
}
public static DerrilFragment newInstance(String data) {
return new DerrilFragment(data);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
viewBinding = DataBindingUtil.inflate(inflater, R.layout.pizza, container, false);
viewBinding.text.setText(data);
return viewBinding.getRoot();
}
}
答案 0 :(得分:1)
您可以通过RecyclerView
来实现。
class MainActivity : AppCompatActivity() {
private var isFirstFocused = false
private val helper: SnapHelper = LinearSnapHelper()
private val helper2: SnapHelper = LinearSnapHelper()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recycler1.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (isFirstFocused) recycler2.scrollBy(dx, dy)
}
})
recycler2.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (!isFirstFocused) recycler1.scrollBy(dx, dy)
}
})
recycler2.setOnTouchListener { v, event ->
if (event.action != null && event.action == MotionEvent.ACTION_DOWN ) {
isFirstFocused = false
return@setOnTouchListener true
}
return@setOnTouchListener false
}
recycler1.setOnTouchListener { v, event ->
if (event.action != null && event.action == MotionEvent.ACTION_DOWN ) {
isFirstFocused = true
return@setOnTouchListener true
}
return@setOnTouchListener false
}
helper.attachToRecyclerView(recycler1)
helper2.attachToRecyclerView(recycler2)
val manager = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false)
val manager2 = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false)
recycler1.layoutManager = manager
recycler2.layoutManager = manager2
recycler2.adapter = Adapter(items)
recycler1.adapter = Adapter(items)
}
private val items = listOf("One", "Two", "Three")
}
class Adapter(val list: List<String>) : RecyclerView.Adapter<Adapter.Holder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context).inflate(
R.layout.activity_listview,
parent,
false
)
return Holder(view)
}
override fun onBindViewHolder(holder: Holder, position: Int) {
holder.itemView.text_view.text = list[position]
}
override fun getItemCount() = list.size
class Holder(view: View) : RecyclerView.ViewHolder(view)
}
答案 1 :(得分:0)
您可以尝试使用adapter.setOffscreenPageLimit = n
。它设置应保留到当前可见页面两侧的页面数。如果页面数量有限,则需要时将通过适配器重新创建超出此限制的页面。
更多详细信息,请参见here。
答案 2 :(得分:0)
在您的setCurrentItem()
用法(在onPageScrollStateChanged()
下)中,将第二个参数设置为false
当您以编程方式设置页面时,这将禁用ViewPager中的动画(不是永久性的),这就是您看到类似Flash动画的原因。
要知道为什么:
考虑两个ViewPagers A和B
您在 A 中从一页滚动到另一页,从而在ViewPager
B 中引起相同的滚动。在 A 中从一页完全滚动到另一页后, currentItem
由A内部设置,而不是由B 设置。
现在,您通过调用setCurrentItem([index], true)
通知B有关页面更改,无论滚动如何,页面都会动画引入闪光的页面更改(将您引起的滚动重置为正常,然后开始一页到另一页的页面动画)
答案 3 :(得分:0)
这似乎有点令人怀疑,您在setCurrentItem
内为每个传递的onPageScrollStateChanged
调用state
...尝试仅添加一些if
和setCurrentItem
当state==ViewPager2.SCROLL_STATE_IDLE
状态列表:
ViewPager2.SCROLL_STATE_IDLE
ViewPager2.SCROLL_STATE_DRAGGING
ViewPager2.SCROLL_STATE_SETTLING
ViewPager2.SCROLL_STATE_DRAGGING
状态通过onPageScrolled
方法处理(共享位置偏移量,也就是用手指拖动)
ViewPager2.SCROLL_STATE_SETTLING
是ViewPager2
的自动滚动(快照)到最接近的页面-在此我不能保证ViewPager2
被“按代码”拖动(与{{1 }})也会进入此scrollTo
并引起相同的捕捉行为(state
也是如此)...值得测试,在其中放置一些日志
还:您拖动一个onPageScrolled
,然后在ViewPager2
中第二个onPageScrolled
调用scrollTo
。这可能会导致在第二个侦听器上调用ViewPager2
,这正在调用第一个onPageScrolled
ViewPager2
方法,依此类推...如此循环。当用户将开始拖动一个scrollTo
并在移动结束时重新注册(ViewPager2
SCROLL_STATE_IDLE
)时考虑动态注销监听器
答案 4 :(得分:0)
我认为问题在于,在两个ViewPagers的' onPageScrolled '方法中,您正在滚动其他寻呼机。因此,两个页面可能同时在互相滚动。例如,如果您正在滚动ViewPager_1,则其 onPageScrolled 方法将滚动ViewPager_2,而当现在滚动ViewPager_2时,将调用其onPageScrolled方法,这将滚动ViewPager_1,反之亦然。 因此,您可能需要考虑执行以下检查:如果ViewPager_1保持触摸,则不应执行ViewPager_2的 onPageScrolled 方法内的代码。或者,如果您想避免这些检查。然后 registerOnPageChangeCallback / unregisterOnPageChangeCallback 当另一个ViewPager保持触摸时的监听器。
@Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
viewBinding.viewPager.scrollTo(positionOffsetPixels, 0);
}