实现安卓无限轮播组件Banner

Android----banner使用详解 Android----banner使用详解 昨天10.31 ,斗破苍穹的三年之约终于出来了,自己也等了很久很久,敬师长,敬家人,敬朋友,敬每一个前行路上正在奋战的自己,星光不问赶路人,时间不负有心人。 效果图: 添加依赖 implementation 'com.youth.banner:banner:2.1.0' 添加权限到你的 AndroidManifest.xml <!-- if you want to load images from the internet --> 阅读详情

前言

前些天需要使用到安卓的banner,也就是现在主流app主页的无限轮播的横幅,现在已经有很多好的开源项目可以直接使用,不过我还是想自己去实现一遍。因为是访问的网络数据,实际过程中还是有些坑的,所以还是记录一下。

具体实现

首先还是来看看最终的效果,gif是有些卡顿,跑起来还是很流畅的
BannViewDemo
了解到,现在实现这种横幅,基本上是2种方式,一种是使用RecyclerView的横向滚动去实现,因为横幅是从一个页面直接跳转到下一页,用RecyclerView需要监听滑动的过程,计算滑动的距离,然后进行跳转,后面官方考虑到这一点提供了PagerSnapHelper这个工具类来解决这个问题,这里就不多说了。
这篇博客主要就是写的就是第二种方式,使用ViewPager去实现。

首先,要用ViewPager实现无限轮播,可以使PagerAdapter的getCount方法返回Integer.MAX_VALUE。也就是让页面数量返回一个Integer的最大值,这样在滑动过程中产生一种无限循环的假象,首先写一个抽象基类,继承自PagerAdapter

定义适配器
public abstract class BannerViewBaseAdapter extends PagerAdapter {

    private List<View> mList;
    private View mView;

    public BannerViewBaseAdapter() {
        mList = new ArrayList<>();
    }

    /**
     * 返回Integer的最大值
     */
    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }

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

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Log.d("I am postion cx cx xcx", String.valueOf(position));
        if (getSize() != 0) {
            if (mList.size() <= (position % getSize())) {
                for (int i = mList.size();i <= position % getSize();++i) {
                    mList.add(getView(container,i));
                }
            }
            mView = mList.get(position % getSize());
            if (mView.getParent() != null) {
                container.removeView(mView);
            }
            container.addView(mView);
        }

        return mView;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        // 滑动下一张图时当前的图
        if (getSize() != 0 && position != 0) {
            container.removeView(mList.get(position % getSize()));
        }
    }

    /**
     *  获取要显示的View
     * @param container
     * @param position
     * @return
     */
    public abstract View getView(ViewGroup container,int position);

    /**
     *  获取实际ItemView的数量
     * @return
     */
    public abstract int getSize();

这里主要是重写instantiateItem方法,进行添加页面的逻辑,首先要判断getSize不为0,因为实际网络加载时可能是一个异步的耗时操作,如果执行到下面的计算时,除数为0肯定会报错的,其它类似地方也都是这样,然后注意到下面的position%getSize,这里是用当前位置对实际item的数量进行模运算取余,得到的值就是当前item的实际位置(前面说过无限轮播是不停的增加页面,造成轮播的假象,实际位置就是指在进行轮播的几个item中,当前处的位置),接下来就判断,如果item不在集合中,就把view添加到一个List集合里面,最后要防止同一个view的重复添加,所以每次添加前需要移除这个view。
接着重写destroyItem方法,每次循环跳转时都要销毁掉之前的view。下面两个抽象方法就是用来获取到具体的值了。

然后就是我们的具体视图的适配器

public class BannerViewAdapter extends BannerViewBaseAdapter {

    private List<TestBean> mBeansList;
    private Context mContext;

    public BannerViewAdapter(List<TestBean> bannerBeans) {
        this.mBeansList = bannerBeans;
    }

    @Override
    public View getView(ViewGroup container, int position) {
        AppCompatImageView imageView;
        TextView title;

        if (mContext == null) {
            mContext = container.getContext();
        }
        View mView = LayoutInflater.from(mContext).inflate(R.layout.banner_item_layout,null);

        final TestBean bean = mBeansList.get(position);
        imageView = mView.findViewById(R.id.image);
        title = mView.findViewById(R.id.banner_title);
        title.setText(bean.getTitle());
        Glide.with(mContext).load(bean.getImageId())
                .error(R.drawable.ic_launcher_background)
                .into(imageView);
        notifyDataSetChanged();

        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(mContext,"你点击了"+bean.getTitle(),Toast.LENGTH_SHORT).show();
            }
        });
        return mView;
    }

    @Override
    public int getSize() {
        return mBeansList.size();
    }
}

这里基础抽象基类,逻辑比较简单,没什么好讲的。

视图绘制

然后重点就是自定义的BannerView类了


public class BannerView extends FrameLayout implements ViewPager.OnPageChangeListener {

    private ViewPager mViewPager;

    /**
     *  圆点布局
     */
    private LinearLayout mPointContainer;

    private BannerViewBaseAdapter mAdapter;

    /**
     *  圆点数量
     */
    private int mPointCount;

    /**
     *  圆点图片
     */
    private ImageView[] mPoints;

    /**
     *  最后一个圆点
     */
    private int mLastPos;

    /**
     *  当前是否触摸
     */
    private boolean isTouch = false;

    private ScheduledExecutorService executorService;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            mViewPager.setCurrentItem(mViewPager.getCurrentItem()+1);
                        }
                    },1000);
                    break;
                default:
                    break;
            }
        }
    };

    public BannerView(@NonNull Context context, AttributeSet attributeSet) {
        super(context,attributeSet);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        initView();
    }

    private void initView() {
        mViewPager = findViewById(R.id.views_container);
        mPointContainer = findViewById(R.id.point_container);
        mViewPager.addOnPageChangeListener(this);
    }

    public void setAdapter(BannerViewAdapter adapter) {
        this.mAdapter = adapter;
        mPointCount = mAdapter.getSize();
        mViewPager.setAdapter(mAdapter);
        Log.d("sddsccdsvdsvdv", String.valueOf(mPointCount*100));
        initPoint();
        /**
         *  防止第二次刷新后 显示空白页面
         */
        mViewPager.setCurrentItem(mPointCount*100+3);
        startScroll();
    }

    /**
     *  加载圆点
     */
    private void initPoint() {
       if (mPointCount == 0) {
           return;
       }

       mPoints = new ImageView[mPointCount];
       // 清chu所有圆点
       mPointContainer.removeAllViews();
       for (int i=0;i < mPointCount;i++) {
           ImageView view = new ImageView(getContext());
           view.setImageResource(R.drawable.point_normal);
           mPointContainer.addView(view);
           mPoints[i] = view;
       }
       if (mPoints[0] != null) {
           mPoints[0].setImageResource(R.drawable.point_selected);
       }
       mLastPos = 0;
    }
    /**
     * 改变圆点位置
     */
    private void changePoint(int currentPoint) {
        if (mLastPos == currentPoint) {
            return;
        }
        mPoints[currentPoint].setImageResource(R.drawable.point_selected);
        mPoints[mLastPos].setImageResource(R.drawable.point_normal);
        mLastPos = currentPoint;
    }

    public void startScroll() {

        executorService = new ScheduledThreadPoolExecutor(1);
        executorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                if (isTouch) {
                    return;
                }
                handler.sendEmptyMessage(0);
            }
        },1000,3000, TimeUnit.MILLISECONDS);
    }

    public void cancelScroll() {
        if (executorService != null) {
            executorService.shutdown();
        }
    }

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

    }

    @Override
    public void onPageSelected(int position) {
        if (mPointCount != 0) {
            changePoint(position % mPointCount);
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isTouch = true;
                break;
            case MotionEvent.ACTION_UP:
                isTouch = false;
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
}

BannerView继承FrameLayout,实现滑动监听的接口,这里先看看initView方法,这里给viewpager设置了适配器,然后接着就是加载圆点指示器的方法,逻辑也比较简单,加载前注意先移除掉之前的圆点,防止刷新后点的数量重复添加。然后就是第一次加载时,时ViewPager跳转到mPoinCoun*100+x的位置,也是为了防止首次加载无法向左滑动,就不是无限循环的假象了。然后就让我们的ViewPager执行定时滑动任务,定时任务有很多的实现方式,可以使用Timer+handler的方式,可以使用CountDownTimer类来实现,这里的话,我使用的是线程池来进行的定时任务,后面分别传入预加载与跳转周期,然后里面需要进行判断当前是否触摸屏幕,所以要重写dispatchEvent方法,监听当前的动作,然后向handler发送消息,再进行页面滑动,这里可能会有疑惑,线程池已经设置了定时任务,为什么还要向handler去发送消息,进行延时处理,handler里面才是真正的滚动延时,除了是非Ui线程不进行Ui更新的操作 也是因为在我们刷新后,线程池会造成阻塞,无法正常执行。我使用了其它几种方式,还是出现了各种问题,这里就不多说了。

整个BannerView的流程就走完了
再看看布局文件 banner_item_layout


<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <android.support.v7.widget.AppCompatImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitXY"/>

    <TextView
        android:id="@+id/banner_title"
        android:text="我是圈子名字"
        android:textSize="15sp"
        android:textColor="@android:color/white"
        android:layout_width="match_parent"
        android:gravity="center_vertical"
        android:paddingLeft="10dp"
        android:layout_gravity="bottom"
        android:background="@color/transparency"
        android:layout_height="35dp" />
</android.support.design.widget.CoordinatorLayout>

banner_view_layout

<com.legend.bannerviewdemo.banner.BannerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/my_slide_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v4.view.ViewPager
        android:id="@+id/views_container"
        android:layout_width="match_parent"
        android:layout_height="180dp"></android.support.v4.view.ViewPager>

    <LinearLayout
        android:id="@+id/indicator"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:layout_marginBottom="5dp"
        android:orientation="vertical"
        android:visibility="visible">

        <LinearLayout
            android:id="@+id/point_container"
            android:layout_width="match_parent"
            android:layout_height="11dp"
            android:gravity="center_horizontal"
            android:orientation="horizontal" />
    </LinearLayout>

</com.legend.bannerviewdemo.banner.BannerView>

使用的话就直接给adapter添加数据,然后实例化给BannerView设置adapter就可以了。这里很要注意一点,就是每次刷新之前记得手动关闭线程池,也就是调用BannView中的cancelScroll()方法,不然会造成进行网络加载,第二次刷新加载数据时,banner直接出现空白页面,这肯定不是我们想要的。 另外,配合RecyclerView使用时,可以把BannerView动态添加到RecyclerView的头部,直接放到布局中,如果要实现RecyclerView上滑时,banner跟着一起滚动的话,可以使用NestedScrollView,但是会造成嵌套滑动冲突,这一点也没看到好的解决办法,设置了NestedScrollingEnable属性,但是会导致RecyclerView无法上拉加载,如果一次性加载完数据的话,RecyclerView的复用和回收机制就没起到作用了,很容易出现OOM,这也不是我们想看到的,所以最好还是配合RecyclerView使用。

总结

总的来说,实现一个并不困难,难在实际过程中会出现各种各样的问题,也正是常说的,debug时间远远多于写代码的是时间(说到底还是经验不足的,理解不够深的缘故)。废话不多说,最后该Demo地址github

Android Banner(无限轮播图)控件的简单使用(网络数据OkHttp3) 一言不合就上图 okhttp请求数据,用Glid加载的网络图片 再用banner设置一下就好了 阅读详情

相关推荐

2022-04-06 RK3566 上调试百兆以太网卡YT8512C 调试记录

一、原理图 二、dts &gmac1_clkin{ clock-frequency = <50000000>; status = "okay"; }; &gmac1 { phy-mode = "rmii"; clock_in_out = "input"; snps,reset-gpio = <&gpio4 RK_PC2 GPIO_ACTIVE_LOW>; snps,reset-active-low; sn...

海月汐辰 1万+

Android Studio导入第三方包(资源)方法,ViewPager+TabLayout的使用,ViewPager单独使用实现无限循环

工作内容: 1.再次熟悉回调函数 2.ViewPager的使用 3.Android第三方包(资源的引入) 学习分享:

风吹草低见牛羊 3480

在没有实验数据的情况下,如何高效快速发表高影响因子论文

最新基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法

glldxh的博客 371

android TabLayout自动轮播

TabLayout和单选框一样只能选中一个,有时候有需求就是自动轮播,自动切换,代码很简单 tabLayout.getTabAt(index).select(); 写个定时自动调用这行代码,index代表第几个 这样就不用那么麻烦的去写ViewPager了,跟点击效果一样的 ...

红色与青色 631

STM32开发者必看:如何在正点原子探索者开发板上快速移植CANopenNode协议栈

本文为STM32开发者提供了在正点原子探索者开发板上快速移植CANopenNode协议栈的实战指南。文章详细介绍了从环境准备、硬件抽象层适配到协议栈初始化与测试的全过程,并分享了PDO配置与性能优化等关键技巧,帮助开发者高效实现CANopen标准化通信。

weixin_29173777的博客 462

在UI界面中播放视频_unity基础开发教程

之前我写过一篇在场景中播放视频的文章,但是在开发中有时候也会在UI的界面中播放视频,这期我们做一下在UI的界面中播放视频。操作步骤比较简单,到这里就完成了,如果有问题的话可以在评论区留言,下期见,拜拜!

为者常成,行者常至! 2006

自定义TabLayout,神奇效果竟是这么简单!

/ 今日科技快讯 /近日,据统计,抖音6月在苹果和谷歌两大系统中的营收继续稳居全球第一,当月实现营收逾9070万美元,是去年同期的8.3倍,其中约89%来自于国内市场,约6%来自...

郭霖 1250

英飞凌 AURIX 系列单片机的HSM详解(1)——何为HSM

1. 概述 随着汽车上通信系统越来越复杂,云端远程通信的场景越来越多,信息安全变得越来越重要,在通信领域常用的AES、SHA、RSA等加密算法被越来越多地应用到汽车上。但通常这类加解密算法都需要大量的数学运算,需要消耗很多CPU时间和资源,汽车上的ECU又有比较高的实时性要求,为了节省主CPU的资源,HSM应运而生。 HSM(Hardware Security Module),是MCU上专门用于实现加解密算法的一个外设,它一般会有一个独立的CPU,专门用来进行加解密运算,还有一些针对特定算法的硬件加速器(如

weixin_42967006的博客 4万+

【Android】ViewPager2+TabLayout实现无限轮播图

本文手把手教您如何通过ViewPager2 + TabLayout实现一个无限轮播图组件

gxhuhuhu的博客 2756

DeepSeek + 微信:手把手教你把 AI 接入个人微信,秒变“高情商”聊天助手(防封指南)

将 DeepSeek 接入微信,本质上是给你的微信装了一个**“最强外挂”**。它不仅能帮你回消息,还能帮你写周报、查资料、甚至陪聊解闷。工具是服务于人的,不要让 AI 完全替代了你的真情实感。毕竟,真正的高情商,是屏幕背后那个在乎对方的你。先申请一个小号,按照步骤跑通流程。然后试着调整 Prompt,训练一个属于你自己的“嘴替”吧!

BUG猿的博客 957

5G Multicast/Broadcast Services(MBS) (七) MBS广播DRX

当处于RRC_IDLE或RRC_INACTIVE或RRC_CONNECTED 状态时,如果为 G-RNTI 配置了broadcast DRX,则允许MAC entity使用broadcast DRX 操作不连续地监听此G-RNTI的PDCCH;此 G-RNTI 的 drx-onDurationTimerPTM 或 drx-InactivityTimerPTM 正在运行的时间,也就是。long DRX周期drx-LongCycle-PTM和drx-StartOffset-PTM定义DRX周期开始的子帧。

asd199086的博客 391

Android使用Banner组件结合Glide实现图片无限轮播

本篇文章记录一下使用Banner组件结合Glide框架实现本地图片无限轮播的广告效果,Glide是谷歌推荐图片框架,Glide的介绍可以异步到这位博主的文章:【Android】Glide架构简介_Tech Ranger的博客-优快云博客_android glide简介 首先需要引入两个框架: //Banner轮播图 implementation 'com.youth.banner:banner:1.4.10' //Glide框架 implementation "com.github.bump

m0_57487205的博客 2058

Windows 11 安装 JDK 25:下载、安装、配置环境变量、验证

本文详细介绍了在 Windows 11 系统上安装 JDK 25 的完整流程,包括从 Oracle 官网下载压缩包、解压至自定义目录、配置 JAVA_HOME 与 Path 环境变量,并验证安装是否成功。文章推荐使用 ZIP 压缩包而非 EXE 安装程序,以实现绿色便携、多版本共存和灵活管理。最后通过一个使用 Java 25 新特性的示例程序,验证 JDK 的编译与运行环境。

寒水馨 · 轻量级技术文档 · hanshuixin.org 7659

Tablayout左右滑动和Banner无限轮播的配合使用

import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import and

zhaochuang4858529的博客 1083

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

banner 无限轮播

//添加 banner 依赖包 和 imageLoader 依赖包 com.youth.banner:banner:1.4.9 //添加权限 uses-permission android:name="android.permission.INTERNET">uses-permission> android:name=".MyApplication" activity

blgktlp的博客 337

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Banner无限轮播

Banner 无限轮播public class BannerViewPager extends FrameLayout implements View.OnClickListener { private ItemClickListener itemClickListener; /** * 图片内容 */ private List<HomeData.Banne

donghui_的博客 295

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

推荐Android中两个很好用的banner,可无限轮播,可使用第三方图片加载框架加载网络图...

推荐Android中两个很好用的banner,可无限轮播,可使用第三方图片加载框架加载网络图 转载于:https://www.cnblogs.com/zhujiabin/p/7308270.html

weixin_30600197的博客 155

Banner框架

Banner是一个框架,此框架是用于实现在Android中,ViewPager的图片无限轮播功能。在使用Banner框架时我们需要添加它的远程依赖:compile ‘com.youth.banner:banner:1.4.9’compile 'com.youth.banner:banner:1.4.9'11、添加依赖 (1)、点击代码编辑页面右边的Grable;然后选择要添加远程依赖的项目...

大伟伟的博客 1191

android 自定义banner样式_Android App Banner,用它就够了。无限轮播、简单易用、扩展性强的BannerView...

按照惯例先上效果图:还有各种效果体验Demo点击下载或扫码下载DemoApk写在前面GitHub上有更加详细的使用介绍的,如果你想直接看GitHub上的也可以直接点击后面的传送门去往GitHub。我是传送门本文的内容可能有点长,如果你想要直接但Demo的源码的,可以直接跳到最后,最后有完整的代码(包括Java代码和XML代码)。前言今天给大家推荐一款支持无限轮播的,简单易用、扩展性强且超级稳定的轮...

weixin_39769627的博客 995

Android无限广告轮播 - 自定义BannerView

1.概述 点击打开链接   这其实是我第一篇想写的博客,可能是因为我遇到了太多的坑,那个时候刚入行下了很多Demo发现怎么也改不动,可能是能力有限,这次就做一个具体的实现和彻底的封装。   上次讲了Android无限广告轮播-ViewPager源码分析,有了源码分析我们对ViewPager就有了一个大概的了解,那么再来封装成自定义View,就会简单许多,附视频讲解地址:http:

pochenpiji159的博客 653

RecyclerBanner常见问题解答:从集成到上线的避坑指南

RecyclerBanner是一款基于RecyclerView实现的无限轮播图组件,支持普通版和3D版轮播效果,广泛应用于Android应用的首页Banner、广告轮播等场景。本文整理了开发者在集成和使用RecyclerBanner过程中最常见的问题及解决方案,帮助你快速避坑,顺利上线。 ## 一、环境配置与依赖问题 ### 1.1 项目无法编译通过怎么办? 确保你的项目满足以下环境要求: -

gitblog_00151的博客 299

Android——支持图片加视频无限轮播的banner

基于https://github.com/youth5201314/banner扩展,图片+视频无限轮播banner Demo地址 https://gitee.com/saqino/pic-video-banner-demo.git 说明 使用大佬的banner控件是很方便的,但是对视频+图片无限轮播的支持较弱,所以决定重写几个类实现功能。 不重写无法实现的原因如下: 无限轮播模式下,item大于1时, adapter会自动增加两个item,一个在最前,一个在最后,这样子做...

Saqino的博客 9886

Android开发自定义Banner实现图片无限轮播效果

之前做过的很多项目都用到了 Banner,不过每次项目做完都忘了总结导致每次要实现 Banner 效果都要上网查,网上的文章真的是鱼龙混杂,因此今天花点时间好好总结一下实现 Banner 的原理。 首先我们来看看要实现的效果: 实现 Banner 的思路很简单,其本质就是封装了一个 ViewPager,然后用定时任务来控制 ViewPager 的位置,再给 ViewPager 设置一个监听器,当页面改变时控制下面指示器的变化即可。 因此我们分为两个大的步骤:用 ViewPager 实现轮播效果 和 添加底

weixin_44965650的博客 2020

android banner停止轮播,android如何实现banner轮播图无限轮播效果

android如何实现banner轮播图无限轮播效果发布时间:2021-04-16 12:47:03来源:亿速云阅读:106作者:小新小编给大家分享一下android如何实现banner轮播图无限轮播效果,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!具体内容如下效果展示第一步(权限配置)第二步(添加依赖)compile'com.squareup.okio:okio:1.5.0'...

weixin_42373103的博客 964

banner项目源码解析:揭秘ViewPager2无限轮播的实现原理

在Android开发中,轮播图是App首页、活动页等场景的常见组件。banner项目作为一个专注于ViewPager2无限轮播功能的开源库,提供了极其简单的使用方式,支持自定义Indicator、一屏三页和仿魅族banner效果。本文将深入解析其核心实现原理,帮助开发者快速掌握ViewPager2无限轮播的设计思路。 ## 核心实现方案:数据循环与位置映射 ViewPager2本身并不直接支持

gitblog_00844的博客 4万+

告别繁琐!banner项目让ViewPager2实现无限轮播就这么简单

banner项目是一个专注于为Android开发者提供ViewPager和ViewPager2无限轮播功能的开源库,它支持自定义Indicator、一屏三页显示以及仿魅族banner效果,以极其简单的使用方式帮助开发者快速实现专业的轮播效果。 ## 🚀 核心功能亮点 banner项目之所以能让轮播实现变得简单,源于其丰富而实用的核心功能: ### 无限轮播轻松实现 无需复杂的代码逻辑,通过

gitblog_00624的博客 986
上一篇: 浅谈Android中的MVP架构
下一篇: Okhttp3的封装 搞定常用的请求
丶legend
博客等级 码龄10年 34粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值