You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Fragment恢复时让ViewPager2从停止位置续启自动滚动

解决方案

针对ViewPager2在Fragment不可见时停止自动滚动、恢复时继续滚动的问题,我们可以通过绑定Fragment生命周期+封装滚动控制逻辑来解决,以下是具体实现:

修改后的完整代码

public class ChannelPagerViewHolder extends RecyclerView.ViewHolder {
    private static final int LIMIT = 7;
    private static final @ViewPager2.OffscreenPageLimit int OFFSCREEN_PAGE_LIMIT = 2;
    private static final long AUTO_SCROLL_INTERVAL = 1000; // 自动滚动间隔(毫秒)

    private Context mContext;
    private LifecycleOwner mLifecycleOwner;
    private ViewPager2 viewPager;
    private LiveData<List<ChannelItem>> mChannelItemList;
    private BannerAdapter bannerAdapter;
    private Handler mHandler;
    private int currentPage;
    private int prevPageNumber;
    private Timer autoScrollTimer;
    private TimerTask autoScrollTask;

    public ChannelPagerViewHolder(View view, Context context, LifecycleOwner lifecycleOwner, int placement) {
        super(view);
        Log.d("ChannelPagerViewHolder", "");
        mContext = context;
        mLifecycleOwner = lifecycleOwner;
        viewPager = view.findViewById(R.id.view_pager);
        viewPager.setOffscreenPageLimit(OFFSCREEN_PAGE_LIMIT);

        viewPager.getLayoutParams().width =
                (int) (Resources.getSystem().getDisplayMetrics().widthPixels);
        viewPager.getLayoutParams().height =
                viewPager.getLayoutParams().width / 2;
        bannerAdapter = new BannerAdapter(mContext, placement);
        viewPager.setAdapter(bannerAdapter);
        viewPager.setClipToPadding(false);
        viewPager.setPadding(24, 0, 24, 0);

        // 显示左右两侧部分banner的hack
        RecyclerView recyclerView = ((RecyclerView) viewPager.getChildAt(0));
        recyclerView.setClipToPadding(false);
        UserEventLogger.getInstance(context).addImpressionLogger(
                recyclerView,
                placement
        );

        mHandler = new Handler(Looper.getMainLooper()); // 指定主线程Looper,避免异常
        currentPage = 0;
        viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);
                currentPage = position; // 页面选中时才更新当前页,确保准确性
            }
        });

        // 绑定Fragment生命周期,控制滚动启停
        mLifecycleOwner.getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
                switch (event) {
                    case ON_RESUME:
                        startAutoScroll();
                        break;
                    case ON_PAUSE:
                        stopAutoScroll();
                        break;
                    case ON_DESTROY:
                        stopAutoScroll();
                        mHandler.removeCallbacksAndMessages(null); // 清理Handler任务,避免内存泄漏
                        break;
                }
            }
        });
    }

    /**
     * 启动自动滚动
     */
    private void startAutoScroll() {
        // 先停止已有任务,避免重复启动导致滚动加速
        stopAutoScroll();
        
        autoScrollTimer = new Timer();
        autoScrollTask = new TimerTask() {
            @Override
            public void run() {
                mHandler.post(() -> {
                    // 计算下一页,实现循环滚动
                    int nextPage = currentPage + 1;
                    if (nextPage >= bannerAdapter.getItemCount()) {
                        nextPage = 0;
                    }
                    viewPager.setCurrentItem(nextPage, true); // true表示带动画滚动
                });
            }
        };
        // 延迟1秒启动,之后每隔1秒滚动一次
        autoScrollTimer.schedule(autoScrollTask, AUTO_SCROLL_INTERVAL, AUTO_SCROLL_INTERVAL);
    }

    /**
     * 停止自动滚动
     */
    private void stopAutoScroll() {
        if (autoScrollTask != null) {
            autoScrollTask.cancel();
            autoScrollTask = null;
        }
        if (autoScrollTimer != null) {
            autoScrollTimer.cancel();
            autoScrollTimer.purge(); // 清除已取消的任务
            autoScrollTimer = null;
        }
    }
}

关键修改说明

  1. 封装滚动控制逻辑

    • 把自动滚动的启动/停止抽成startAutoScroll()和stopAutoScroll()方法,统一管理Timer和TimerTask,避免重复创建任务导致滚动加速。
  2. 绑定Fragment生命周期

    • 通过mLifecycleOwner监听Fragment的生命周期事件:
      • ON_RESUME:Fragment恢复可见时,从当前页面启动自动滚动。
      • ON_PAUSE:Fragment不可见时,立即停止滚动。
      • ON_DESTROY:彻底清理Timer和Handler任务,避免内存泄漏。
  3. 修正当前页记录

    • 将currentPage的更新从onPageScrolled移到onPageSelected,因为onPageScrolled会在滚动过程中多次触发,而onPageSelected仅在页面选中时触发,能准确记录当前显示的页码。
  4. 循环滚动处理

    • 滚动时判断下一页是否超出适配器条目数,超出则回到第0页,解决原代码越界导致的空白问题。

内容的提问来源于stack exchange,提问作者Paras

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 14:05:21