ViewPager无限循环实现画廊式banner

先看一下效果

效果图

两边显示上一个和下一个item部分布局,可以自动滚动

实现:

布局

主要属性:android:clipChildren="false" //允许子布局超出父布局显示

xml代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:clipChildren="false"
              android:background="@color/bg_gray"
              android:layout_width="match_parent"
              android:paddingBottom="8dp"
              android:paddingTop="8dp"
              android:layout_height="wrap_content">

    <androidx.viewpager.widget.ViewPager
            android:id="@+id/demo_vp_short_video_top"
           android:layout_width="match_parent"
            android:layout_marginLeft="32dp"
            android:layout_marginRight="32dp"
            android:clipChildren="false"
            android:layout_height="@dimen/size_160dp"/>
    
</LinearLayout>

Adapter

没什么特别的只要 getCount()返回一个很大的值如:return Integer.MAX_VALUE;

适配器代码:

package com.guzhc.module_demo;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import com.bumptech.glide.Glide;

import java.util.ArrayList;
import java.util.List;

/**
 * @author : GuZhC
 * @date :  2019/6/1 9:46
 * @description : 顶部banner viewPager 适配器
 */
public class ShortViewoViewPagerAdapter extends PagerAdapter {
    private final Context context;
    private final List<String> mData;
    private PagerClick pagerClick;

    public ShortViewoViewPagerAdapter(List<String> mData, Context context) {
        this.mData = mData;
        this.context = context;
    }



    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }

    @Override
    public void destroyItem(ViewGroup container, int position,
                            Object object) {
        //Warning:不要在这里调用removeView
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        position %= mData.size();
        final String data = mData.get(position);
        View view =  View.inflate(container.getContext(),R.layout.demo_item_short_video_viewpager, null);
        ImageView img = view.findViewById(R.id.demo_img_short_video_item);
        TextView tvContent = view.findViewById(R.id.demo_tv_short_video_item);
        tvContent.setText(data);
        Glide.with(context)
                .load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1559367407524&di=2a7d6a1a12707287e908d61922a637c2&imgtype=0&src=http%3A%2F%2Fpic72.nipic.com%2Ffile%2F20150715%2F9448607_192612583000_2.jpg")
                .into(img);
        //对ViewPager页号求模取出View列表中要显示的项
        if (position < 0) {
            position = mData.size() + position;
        }
        //如果View已经在之前添加到了一个父组件,则必须先remove,否则会抛出IllegalStateException。
        ViewParent vp = view.getParent();
        if (vp != null) {
            ViewGroup parent = (ViewGroup) vp;
            parent.removeView(view);
        }
        container.addView(view);      
        return view;
    }
  
}

调用

注意:两边的item滑动没有效果吗,需要将容器的触摸事件反馈给ViewPager

    //设置banner
        shortViewoViewPagerAdapter = new ShortViewoViewPagerAdapter(mData, getContext());
        View bannerView = LayoutInflater.from(getContext()).inflate(R.layout.demo_layout_short_video_banner, null);
        viewPagerBanner = bannerView.findViewById(R.id.demo_vp_short_video_top);
        LinearLayout mViewPagerContainer = bannerView.findViewById(R.id.demo_ll_short_video_vp_root);
        viewPagerBanner.setAdapter(shortViewoViewPagerAdapter);
        viewPagerBanner.addOnPageChangeListener(this);
        //将容器的触摸事件反馈给ViewPager
        mViewPagerContainer.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return viewPagerBanner.dispatchTouchEvent(event);
            }

        });

 

无限循环:方式很多,这里用的Handler实现

设置viewPager.addOnPageChangeListener(this)实现接口重写方法:实现滑动时候暂停自动滑动,停止的时候开启

重写方法代码:

@Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        handler.sendMessage(Message.obtain(handler, ImageHandler.MSG_PAGE_CHANGED, position, 0));
    }

    @Override
    public void onPageSelected(int position) {
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        switch (state) {
            //滑动中
            case ViewPager.SCROLL_STATE_DRAGGING:
                handler.sendEmptyMessage(ImageHandler.MSG_KEEP_SILENT);
                break;
            //未滑动
            case ViewPager.SCROLL_STATE_IDLE:
                handler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE, ImageHandler.MSG_DELAY);
                break;
            default:
                break;
        }
    }

Handler代码:

public class ImageHandler extends Handler {

    /**
     * 请求更新显示的View。
     */
    protected static final int MSG_UPDATE_IMAGE  = 1;
    /**
     * 请求暂停轮播。
     */
    protected static final int MSG_KEEP_SILENT   = 2;
    /**
     * 请求恢复轮播。
     */
    protected static final int MSG_BREAK_SILENT  = 3;
    /**
     * 记录最新的页号,当用户手动滑动时需要记录新页号,否则会使轮播的页面出错。
     * 例如当前如果在第一页,本来准备播放的是第二页,而这时候用户滑动到了末页,
     * 则应该播放的是第一页,如果继续按照原来的第二页播放,则逻辑上有问题。
     */
    protected static final int MSG_PAGE_CHANGED  = 4;

    //轮播间隔时间
    protected static final long MSG_DELAY = 5000;

    //使用弱引用避免Handler泄露.
    private WeakReference<ShortVedioFragmet> weakReference;
    private int currentItem = 0;

    protected ImageHandler(WeakReference<ShortVedioFragmet> wk){
        weakReference = wk;
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        ShortVedioFragmet shortVedioFragmet = weakReference.get();
        if (shortVedioFragmet==null){
            //Activity已经回收,无需再处理UI了
            return ;
        }
        //检查消息队列并移除未发送的消息,这主要是避免在复杂环境下消息出现重复等问题。
        if (shortVedioFragmet.handler.hasMessages(MSG_UPDATE_IMAGE)){
            shortVedioFragmet.handler.removeMessages(MSG_UPDATE_IMAGE);
        }
        switch (msg.what) {
            case MSG_UPDATE_IMAGE:
                currentItem++;
                shortVedioFragmet.viewPagerBanner.setCurrentItem(currentItem);
                //准备下次播放
                shortVedioFragmet.handler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE, MSG_DELAY);
                break;
            case MSG_KEEP_SILENT:
                //只要不发送消息就暂停了
                break;
            case MSG_BREAK_SILENT:
                shortVedioFragmet.handler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE, MSG_DELAY);
                break;
            case MSG_PAGE_CHANGED:
                //记录当前的页号,避免播放的时候页面显示不正确。
                currentItem = msg.arg1;
                break;
            default:
                break;
        }
    }
}

如果是viewpager嵌套Fragment的界面中使用可以通过setUserVisibleHint(boolean isVisibleToUser)方法这样开启和暂停:

setUserVisibleHint()方法会在fragment显示和隐藏的时候被调用

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if(isVisibleToUser) {
            //相当于OnResume(),可以做相关逻辑
            //开始轮播效果
            handler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE, ImageHandler.MSG_DELAY);
        }else {
            //相当于OnPause()
            //暂停轮播效果
            handler.sendEmptyMessage(ImageHandler.MSG_KEEP_SILENT);
        }
    }

在Activity使用 可以在onResum() 和onPause()开启可暂停。

至此完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值