【问题标题】:ViewPager2 flashes/reloads on swipeViewPager2 在滑动时闪烁/重新加载
【发布时间】:2020-09-25 15:26:51
【问题描述】:

我正在尝试使用新的 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();

    }
}

【问题讨论】:

  • 为什么你有 2 个 ViewPager?你只需要 1 个。
  • 因为 viewpager 被一个视图隔开。如果您可以在一个浏览器中完成,我很想听听如何
  • 看起来您的 ViewPager 是相互重叠的。所以这对我来说没有意义。
  • 没有意义怎么办?一个 ViewPager 在顶部,由一个视图分隔,然后是第二个 ViewPager。

标签: java android android-viewpager2


【解决方案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)
}

【讨论】:

    【解决方案2】:

    您可以尝试使用adapter.setOffscreenPageLimit = n。它设置应保留到当前可见页面任一侧的页面数。如果页面数量有限,将在需要时从适配器重新创建超出此限制的页面。 更多详情请联系here

    【讨论】:

      【解决方案3】:

      在您的setCurrentItem() 用法中(在onPageScrollStateChanged() 下),将第二个参数设置为false

      当您以编程方式设置页面时,这将禁用 ViewPager 中的动画(不是永久),这就是您看到类似 flash 动画的原因。


      要知道为什么:

      考虑两个 ViewPager A 和 B

      您在 A 中从一页滚动到另一页,这会在 ViewPager B 中引发相同的滚动。在 A 中从一个页面完全滚动到另一个页面后,currentItem 由 A 在内部设置,但不是为 B

      现在,您通过调用 setCurrentItem([index], true) 通知 B 页面更改,无论您的滚动如何,都会动画引入 flash 的页面更改(您的感应滚动重置为正常,并且一页到另一页的页面动画开始)

      【讨论】:

        【解决方案4】:

        这看起来有点可疑,您在 onPageScrollStateChanged 中调用 setCurrentItem 对每个传递的 state... 尝试添加一些 ifsetCurrentItem 仅当 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_SETTLINGViewPager2 的自动滚动(捕捉)到最近的页面 - 在这里我不知道ViewPager2 拖动“按代码”(与scrollTo 共享位置)也会进入这个state 导致相同的快照行为(onPageScrolled 也是如此?)...值得测试,放一些日志在那里

        另外:您正在拖动一个ViewPager2,而在onPageScrolled 中,您在第二个ViewPager2 上调用scrollTo。这可能会导致在第二个侦听器上调用onPageScrolled 调用,该侦听器正在调用第一个ViewPager2 scrollTo 方法等等......循环。当用户开始拖动一个 ViewPager2 并在移动结束时重新注册时考虑动态注销监听器 (SCROLL_STATE_IDLE state)

        【讨论】:

          【解决方案5】:

          我认为问题在于,在两个 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);
                      }
          

          【讨论】:

          • 问题是这个功能的要求是每个viewpager之间的滑动需要同步
          猜你喜欢
          • 2012-06-19
          • 1970-01-01
          • 2016-06-05
          • 2023-03-22
          • 1970-01-01
          • 2017-07-19
          • 2013-10-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多