轻松使用ViewPager,支持无限滑动和指示器

1.效果图

2.核心代码

(1).ViewPager的Adapter父类

/**
 * Created by wanghaibo on 2020/12/29.
 * 带缓存的ViewPager适配器
 * Data 数据
 * Holder viewHolder
 */

public abstract class BaseViewPagerAdapter<Data, Holder extends BaseViewPagerAdapter.ViewHolder> extends PagerAdapter implements View.OnClickListener, ViewPager.OnPageChangeListener {
    protected Stack<View> cacheViews = new Stack<>();//缓存
    protected boolean isLoop;//是否无限循环
    protected Context mContext;
    protected List<Data> datas = new ArrayList<>();//数据
    protected List<Holder> holders = new ArrayList<>();
    protected Holder curHolder;
    protected int curPosition;//当前下标
    protected DataItemInnerClickListener<Data> itemInnerClickListener;//内部点击事件
    protected Constructor holderConstructor;//holder的构造器

    public BaseViewPagerAdapter(Context mContext) {
        this.mContext = mContext;
        initHolderClass();
    }

    public BaseViewPagerAdapter(Context context, List<Data> datas) {
        this.mContext = context;
        this.datas.clear();
        if (datas != null) {
            this.datas.addAll(datas);
        }
        initHolderClass();
    }


    protected abstract int layoutId();

    protected abstract void bindData(Holder holder, Data itemData, int position);

    public void setDatas(List<Data> data, ViewPager viewPager) {
        this.datas.clear();
        if (data != null && data.size() > 0) {
            this.datas.addAll(data);
        }
        ViewGroup parent = (ViewGroup) viewPager.getParent();
        int i = parent.indexOfChild(viewPager);
        parent.removeView(viewPager);
        viewPager.addOnPageChangeListener(this);
        notifyDataSetChanged();
        viewPager.setCurrentItem(getStartIndex(), false);
        parent.addView(viewPager, i);
    }


    public List<Data> getDatas() {
        return datas;
    }

    public boolean isLoop() {
        return isLoop;
    }

    /**
     * 设置是否无限循环
     *
     * @param loop
     */
    public void setLoop(boolean loop) {
        isLoop = loop;
    }

    public Holder getCurHolder() {
        return curHolder;
    }

    public void setItemInnerClickListener(DataItemInnerClickListener<Data> itemInnerClickListener) {
        this.itemInnerClickListener = itemInnerClickListener;
    }

    /**
     * 初始化Holder的泛型Class以及构造器
     */
    private void initHolderClass() {
        //从一个泛型类型中获取泛型参数的类型类数组。
        Type[] actualTypeArguments = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments();
        Class<? extends BaseViewPagerAdapter.ViewHolder> c = (Class<? extends BaseViewPagerAdapter.ViewHolder>) actualTypeArguments[1];
        try {
            /*以下调用带参的、私有构造函数*/
            LOG.e("-------------class----------" + c.getSimpleName());
            holderConstructor = c.getConstructor(new Class[]{View.class});
            holderConstructor.setAccessible(true);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    /**
     * bindData中给iteme的子View设置点击事件,对应外部的 {@link #setItemInnerClickListener(DataItemInnerClickListener)}
     *
     * @param view
     * @param position
     */
    protected void setItemInnerClickForView(View view, int position) {
        view.setOnClickListener(this);
        view.setTag(R.id.inner_view_position_tag, position);
    }

    /**
     * 获取初始化的坐标
     *
     * @return
     */
    public int getStartIndex() {
        int size = datas.size();
        if (isLoop && size > 1) {
            return Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % datas.size();
        } else {
            return size;
        }
    }

    /**
     * 获得真实数据下标
     *
     * @param index
     * @return
     */
    public int getRealPosition(int index) {
        int size = datas.size();
        if (isLoop && size > 1) {
            return index % size;
        } else {
            return index;
        }
    }

    @Override
    public int getCount() {
        int size = datas.size();
        if (isLoop && size > 1) {
            return Integer.MAX_VALUE;
        } else {
            return size;
        }
    }

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

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Holder holder = null;
        View view = null;
        if (cacheViews.empty()) {
            view = LayoutInflater.from(mContext).inflate(layoutId(), container, false);
            try {
                holder = (Holder) holderConstructor.newInstance(new Object[]{view});
                holders.add(holder);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            view.setTag(holder);
        } else {
            view = cacheViews.pop();
            holder = (Holder) view.getTag();
        }

        position = getRealPosition(position);
        if (position == curPosition) {
            curHolder = holder;
        }
        holder.position = position;
        bindData(holder, datas.get(position), position);
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        View view = (View) object;
        container.removeView(view);
        cacheViews.push(view);
    }

    @Override
    public int getItemPosition(Object object) {
        View view = (View) object;
        Holder holder = (Holder) view.getTag();
        if (holder != null) {
            final int curPos = holder.position;
            //只刷新当前页面
            if (curPosition != curPos) {
                return POSITION_UNCHANGED;
            }
        }
        return POSITION_NONE;
    }

    @Override
    public void onClick(View v) {
        Object innerTag = v.getTag(R.id.inner_view_position_tag);
        if (innerTag != null) {
            int position = getRealPosition((int) innerTag);
            if (itemInnerClickListener != null) {
                Data item = null;
                if (datas.size() > position) {
                    item = datas.get(position);
                }
                itemInnerClickListener.onItemInnerClick(item, v, position);
            }
        }
    }

    /**
     * 清理缓存资源
     */
    public void clear() {
        stopAutoScroll();
        cacheViews.clear();
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        curPosition = getRealPosition(position);
        for (int i = 0; i < holders.size(); i++) {
            Holder holder = holders.get(i);
            if (holder.position == curPosition) {
                curHolder = holder;
                break;
            }
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }

    private static TimeHandler handler;

    /**
     * 开启自动轮播
     */
    public void startAutoScroll(ViewPager viewPager) {
        if (handler == null) {
            handler = new TimeHandler(viewPager);
        }
    }

    /**
     * 停止自动轮播
     */
    public void stopAutoScroll() {
        if (handler != null) {
            handler.cancel();
            handler = null;
        }
    }

    static class TimeHandler extends Handler {
        WeakReference<ViewPager> viewPagerWeakReference;
        Thread thread;

        //间隔时间
        private int SPACE = 2;
        //自动滚动信号
        private final int SCROLL = 100002;
        private boolean isCancel;

        public TimeHandler(ViewPager viewPager) {
            this.viewPagerWeakReference = new WeakReference<>(viewPager);
            thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (!isCancel) {
                        try {
                            Thread.sleep(SPACE * 1000);
                            if (handler != null) {
                                handler.sendEmptyMessage(SCROLL);
                            }
                        } catch (InterruptedException e) {
                        }
                    }
                }
            });
            thread.start();
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == SCROLL)
                if (viewPagerWeakReference != null && viewPagerWeakReference.get() != null) {
                    ViewPager viewPager = viewPagerWeakReference.get();
                    BaseViewPagerAdapter adapter = (BaseViewPagerAdapter) viewPager.getAdapter();
                    if (viewPager != null && adapter != null) {
                        int size = adapter.getCount();
                        int cur = viewPager.getCurrentItem();
                        if (size > 0) {
                            if (cur < size - 1) {
                                viewPager.setCurrentItem(cur + 1);
                            } else {
                                viewPager.setCurrentItem(0);
                            }
                        }
                    }
                } else {
                    thread.interrupt();
                }
        }

        public void cancel() {
            this.isCancel = true;
            this.thread.interrupt();
        }
    }

    /**
     * viewHolder父类,BaseViewPagerAdapter子类使用holder必须集成该类
     */
    public static class ViewHolder {
        protected View itemView;
        protected int position;

        public ViewHolder(View itemView) {
            this.itemView = itemView;
        }
    }
}

(2).自定义指示器

/**
 * Created by wanghaibo on 2020/12/30.
 * ViewPager指示器
 */
public class ViewPagerIndicator extends LinearLayout implements ViewPager.OnPageChangeListener {
    private int indicatorDrawableRes;//选择和未选择图片资源
    private int indicatorWH;//指示器宽度
    private int indicatorSpace;//指示器间距
    private ViewPager viewPager;
    private BaseViewPagerAdapter adapter;

    public ViewPagerIndicator(Context context) {
        this(context, null);
    }

    public ViewPagerIndicator(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public ViewPagerIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public ViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView(attrs);
    }

    private void initView(AttributeSet attrs) {
        setGravity(Gravity.CENTER);
        setOrientation(HORIZONTAL);
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator);
        indicatorWH = typedArray.getDimensionPixelSize(R.styleable.ViewPagerIndicator_indicatorWH, 10);
        indicatorSpace = typedArray.getDimensionPixelSize(R.styleable.ViewPagerIndicator_indicatorSpace, 10);
        indicatorDrawableRes = typedArray.getResourceId(R.styleable.ViewPagerIndicator_indicatorDrawable, R.drawable.bg_view_pager_indicator_selector);
        typedArray.recycle();

    }

    public void bindViewPager(ViewPager viewPager, BaseViewPagerAdapter adapter) {
        this.viewPager = viewPager;
        this.adapter = adapter;
        this.viewPager.addOnPageChangeListener(this);
        ViewTreeObserver viewTreeObserver = viewPager.getViewTreeObserver();
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                initIndicatorViews();
            }
        });
    }

    private void initIndicatorViews() {
        int size = adapter.getDatas().size();
        if (getChildCount() == size) {
            return;
        }
        removeAllViews();
        for (int i = 0; i < size; i++) {
            View view = new View(getContext());
            LayoutParams layoutParams = new LayoutParams(indicatorWH, indicatorWH);
            if (i == 0) {
                view.setSelected(true);
            } else {
                layoutParams.setMargins(indicatorSpace, 0, 0, 0);
            }
            view.setBackgroundResource(indicatorDrawableRes);
            addView(view, layoutParams);
        }
    }

    @Override
    public void onPageScrolled(int i, float v, int i1) {

    }

    @Override
    public void onPageSelected(int i) {
        changeIndicator(adapter.getRealPosition(i));
    }

    @Override
    public void onPageScrollStateChanged(int i) {

    }

    int oldSelectedPosition = 0;

    private void changeIndicator(int position) {
        if (adapter != null && adapter.getCount() > 0) {
            getChildAt(oldSelectedPosition).setSelected(false);
            getChildAt(position).setSelected(true);
            oldSelectedPosition = position;
        }
    }
}

(3).指示器自定义属性,values/attrs.xml里添加

<?xml version="1.0" encoding="utf-8"?>
<resources>    
    <declare-styleable name="ViewPagerIndicator">
        <attr name="indicatorDrawable" format="reference" />
        <attr name="indicatorWH" format="dimension" />
        <attr name="indicatorSpace" format="dimension" />
    </declare-styleable>
</resources>

(4).点击监听器

/**
 * 列表中的item被点击事件
 */

public interface DataItemInnerClickListener<T> {
    void onItemInnerClick(T data, View v, int position);
}

2.使用示例

(1).继承adapter父类实现

/**
 * Created by wanghaibo50 on 2021/3/3.
 */
public class RecommendViewPagerAdapter extends BaseViewPagerAdapter<AdvertisementVo, RecommendViewPagerAdapter.RecommendViewHolder> {

    RequestOptions options;

    public RecommendViewPagerAdapter(Context mContext) {
        super(mContext);
    }

    public RecommendViewPagerAdapter(Context context, List<AdvertisementVo> datas) {
        super(context, datas);
    }

    @Override
    protected int layoutId() {
        return R.layout.layout_recommend_image_view;
    }

    @Override
    protected void bindData(RecommendViewHolder holder, final AdvertisementVo itemData, int position) {
        //图片圆角
        if (options == null) {
            options = RequestOptions.bitmapTransform(new RoundedCorners(mContext.getResources().getDimensionPixelSize(R.dimen.home_round_corners)));
        }
        setItemInnerClickForView(holder.llContent, position);
        Glide.with(mContext).load(itemData.getImgUrl()).apply(options).placeholder(R.drawable.ic_img_def).into(holder.imageView);
    }


    //这里注意holder必须为公共静态类
    public static class RecommendViewHolder extends BaseViewPagerAdapter.ViewHolder {
        public ImageView imageView;
        public LinearLayout llContent;

        public RecommendViewHolder(View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.iv_recommend);
            llContent = itemView.findViewById(R.id.ll_content);
        }
    }
}

 (2).ViewPager子View布局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/rl_recomment"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="10dp"
    android:orientation="vertical">

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/vp_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.jdjr.smartrobot.ui.views.widget.ViewPagerIndicator
        android:id="@+id/vpi_indicator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="10dp"
        app:indicatorDrawable="@drawable/bg_view_pager_indicator_selector"
        app:indicatorSpace="6dp"
        app:indicatorWH="5dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

(3).指示器样式资源bg_view_pager_indicator_selector

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true">
        <shape android:shape="oval">
            <solid android:color="@color/white" />
        </shape>
    </item>
    <item android:state_selected="false">
        <shape android:shape="oval">
            <solid android:color="@color/color_4DFFFFFF" />
        </shape>
    </item>
    <item>
        <shape android:shape="oval">
            <solid android:color="@color/color_4DFFFFFF" />
        </shape>
    </item>
</selector>

(3). 调用

public class MainActivity extends AppCompatActivity {
    private List<AdvertisementVo> advertisementVos;
    private ViewPager viewPager;
    private ViewPagerIndicator vpiIndicator;
    private RecommendViewPagerAdapter adapter;    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        inttData();
    }

    protected void initView() {
        viewPager = findViewById(R.id.vp_layout);
        vpiIndicator = findViewById(R.id.vpi_indicator);
        adapter = new RecommendViewPagerAdapter(this);
        viewPager.setAdapter(adapter);
        adapter.setLoop(true);
        adapter.setItemInnerClickListener(this);
        vpiIndicator.bindViewPager(viewPager, adapter);
    }

    protected void initData() {
        //此处省略了获取数据的过程
        adapter.setDatas(advertisementVos, viewPager);
        adapter.startAutoScroll(viewPager);
    }
}

完结撒花 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要实现ViewPager的自动滑动和手动滑动加点击切换,可以按以下步骤进行操作: 1. 在layout文件中添加ViewPager控件: ``` <android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="wrap_content"/> ``` 2. 在Activity或Fragment中初始化ViewPager并设置Adapter: ``` ViewPager viewPager = findViewById(R.id.view_pager); viewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager())); ``` 3. 实现自动滑动功能,可以使用Handler和Runnable来实现: ``` private Handler handler = new Handler(); private Runnable runnable = new Runnable() { @Override public void run() { int currentItem = viewPager.getCurrentItem(); int count = viewPager.getAdapter().getCount(); if (currentItem < count - 1) { viewPager.setCurrentItem(currentItem + 1); } else { viewPager.setCurrentItem(0); } handler.postDelayed(runnable, 3000); } }; // 在onResume()方法中启动自动滑动 @Override protected void onResume() { super.onResume(); handler.postDelayed(runnable, 3000); } // 在onPause()方法中停止自动滑动 @Override protected void onPause() { super.onPause(); handler.removeCallbacks(runnable); } ``` 4. 实现手动滑动和点击切换功能,可以在ViewPager的OnPageChangeListener中处理: ``` viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} @Override public void onPageSelected(int position) { // 处理页面切换事件 } @Override public void onPageScrollStateChanged(int state) { // 处理滑动状态变化事件 } }); ``` 在onPageSelected()方法中可以处理页面切换事件,比如更新页面指示器的状态。在onPageScrollStateChanged()方法中可以处理滑动状态变化事件,比如停止自动滑动或重新开始自动滑动。 以上就是实现ViewPager自动滑动和手动滑动加点击切换的基本步骤,具体实现可以根据需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值