自定义轮播图控件

由来:我们都知道我们做软件的时候,有些应用是有广告的轮番图的,而我们实现这个功能的时候大多数是采用:ViewPager + Fragment来实现的,而且指示器可能是采用RadioButton实现的,本人以前也是如此,但是有好几次碰到要写这个功能,嫌弃以前的麻烦,所以今天分享一下我自己自定义的广告轮番图的控件!

下一篇进行性能的优化和细节的优化

本篇博客效果图:



1.分析控件

        控件有多个图片水平排列

                    可以想到自定义控件应该是继承ViewGroup,这样子只需要安排孩子的位置即可

        控件可以用手指左右滑动

                    可以想到我们需要处理用户的触摸事件,从而来实现我们图片滚动,原理就是滚动画布

        控件可以通过方法选择哪一张图片被选中

                   其实就是滚动画布到指定的位置

        控件自带指示器,作用是告知用户当前是第几张图片

                   直接绘制n个小圆点到界面上,达到指示器的作用

        控件可以自动的图片滚动起来,如果是最后一张,下一张就是第一张

        控件的使用尽可能简单

2.代码的初步实现

2.1首先毋庸置疑的就是创建一个类,继承ViewGroup


2.2重写几个构造方法和实现onLayout()方法,和进行一些初始化的操作

    /**
    * 控件自身的宽度
    */
    private int mWidth;

    /**
    * 控件自身的高度
    */
    private int mHeight;
    /**
     * 安排孩子的位置,每一个孩子都是父容器的大小,手指滑动可以显示出下一个孩子
     *
     * @param changed
     * @param l
     * @param t
     * @param r
     * @param b
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mWidth = getWidth();
        mHeight = getHeight();
        //获取到孩子的个数
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
           View v = getChildAt(i);
           v.layout(mWidth * i, 0, mWidth * (i + 1), mHeight);
        }
    }


         
 onLayout里面的实现这里做一个解释:其实就是拿到ViewGroup里面的所有孩子,然后从左到右的排列好,也就是安排孩子们的位置,而孩子是谁呢?这里采用了ImageView作为孩子,因为显示图片我们平常用的就是ImageView控件 

2.3我们想先看到效果,所以这里先写好关于用户使用的方法

    /**
     * 填充父容器的布局对象
     */
    private ViewGroup.LayoutParams =new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    /**
     * 图片的个数
     */
    private int imageCount = 0;

    /**
     * 添加图片地址,让轮番图多一张图滚动
     *
     * @param imageUrl
     * @param defalutImageId 图片加载完成前显示的图片的资源id
     */
    public void addImageUrl(String imageUrl, int defalutImageId) {
        ImageView iv = new ImageView(context);
        iv.setLayoutParams(lp);
        iv.setImageResource(defalutImageId);
        this.addView(iv);
        requestLayout();
        imageCount++;
        ImageLoad.getInstance().asyncLoadImage(iv, imageUrl);
    }


        参数defalutImageId是图片默认显示的图片的资源地址,如果图片加载失败也显示这个图片
这里的代码也很简单,就是用户通过方法addImageUrl添加图片的网址,然后动态创建
ImageView控件添加到自身的ViewGroup中,ImageView控件是填充父容器的,通过
setLayoutParams方法设置,然后重新让容器布局,图片是异步加载的
这里我使用了自己封装的ImageLoad,亲们大可以更换成你们常用的图片加载器
比如官方的glide


2.4在布局文件中使用

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFF00"
    tools:context="com.example.cxj.adv.MainActivity">

    <com.example.cxj.adv.view.AdvView
        android:background="#FFFFFF"
        android:id="@+id/adv"
        android:layout_width="match_parent"
        android:layout_height="200dp">
    </com.example.cxj.adv.view.AdvView>

</RelativeLayout>


2.5在activity中对控件添加几个图片的地址

   private AdvView adv = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        adv = (AdvView) findViewById(R.id.adv);
        adv.addImageUrl("http://pic4.zhimg.com//4a6c792c5074742bd62269858b187757.jpg",R.mipmap.ic_launcher);
        adv.addImageUrl("http://pic2.zhimg.com//6c40c40c443dd2fe672880f1c42936d5.jpg",R.mipmap.ic_launcher);
        adv.addImageUrl("http://pic4.zhimg.com//e90b17d4c6b77c5c102965dc5711c1b7.jpg",R.mipmap.ic_launcher);
        adv.addImageUrl("http://pic2.zhimg.com//c59d95e6e3a4946f17e7f11d311a22d9.jpg",R.mipmap.ic_launcher);
        adv.addImageUrl("http://pic2.zhimg.com//7bcc9b1178f7959183e70f79bddf3b31.jpg",R.mipmap.ic_launcher);
    }

2.6初步的效果图



可以看到第一张图片的地址上的图片已经显示在界面上了,但是我们在activity的oncreate方法中添加了很多的图片,这些图片在哪里呢?

这里简单的画了一下原理图,也就是说除了第一张图片,后面的图片其实就是在屏幕的右边,
看不见而已,所以这里要看到他们,我们可以让画布往右滚动,也就是图片往左移动到屏幕上来了

2.7重写onTouchEvent方法

在手指按下的时候记录当前的坐标,手指滑动的时候让画布跟着手指移动

    private int currentX;
    private int currentY;
    private int finalX;
    private int finalY;

    /**
     * 手指是否移动
     */
    private boolean isMove = false;

    /**
     * 是否是我的事件
     */
    private boolean isMyEvent = false;

    /**
     * 是否已经判断是谁的事件
     */
    private boolean isJudge = false;

    /**
     * 手指是否触摸了屏幕
     */
    private boolean isTouchScreen = false;

    @Override
    public boolean onTouchEvent(MotionEvent e) {

        vt.addMovement(e);

        //获取是什么状态,按下还是移动还是抬起
        int action = e.getAction();

        if (action == MotionEvent.ACTION_DOWN) { //按下
            count = 0;
            isJudge = false;
            isMove = false;
            isTouchScreen = true;
            velocityX = 0;
            currentX = (int) e.getX();
            currentY = (int) e.getY();
            return true;
        } else if (action == MotionEvent.ACTION_MOVE) { //移动
            count = 0;
            finalX = (int) e.getX();
            finalY = (int) e.getY();
            int dx = finalX - currentX;
            int dy = finalY - currentY;
            if (!isJudge) {
                if (dx == 0 && dy == 0) {
                    return super.onTouchEvent(e);
                } else {
                    if (Math.abs(dy) > Math.abs(dx)) {
                        isMyEvent = false;
                        return false;
                    } else {
                        isMyEvent = true;
                        requestDisallowInterceptTouchEvent(true);
                    }
                }
            }

            //已经判断过了,这次的事件该是谁的
            isJudge = true;

            if (isMyEvent) {
                scrollBy(-dx, 0);
                currentX = (int) e.getX();
                currentY = (int) e.getY();
                if (onMoveStateListener != null) {
                    onMoveStateListener.onMoveState(MOVING);
                }
                isMove = true;
                return true;
            } else {
                return super.onTouchEvent(e);
            }
        } else if (action == MotionEvent.ACTION_UP) { //抬起

            if (!isMove) { //如果没有移动
                View v = getChildAt(currIndex);
                this.onClick(v);
                return true;
            }

            //计算速度
            vt.computeCurrentVelocity(1000, Integer.MAX_VALUE);
            //水平方向的速度
            float xVelocity = vt.getXVelocity();
            count = 0;
            isTouchScreen = false;
            if (onMoveStateListener != null) {
                onMoveStateListener.onMoveState(STOPED);
            }
            //说明飞溅了
            if (Math.abs(xVelocity) > 500) {
                if (xVelocity < 0) {
                    currIndex++;
                    setCurrentImage(currIndex);
                } else {
                    currIndex--;
                    setCurrentImage(currIndex);
                }
                return true;
            }
            //拿到现在的画布偏移量
            int scrollX = getScrollX();
            //拿到现在显示的图片的下标
            int index = scrollX / mWidth;
            //判断是左边还是右边多一点,从而应该判断应该往左还是往右
            if (scrollX % mWidth > mWidth / 2) {
                index++;
            }
            setCurrentImage(index);
            return true;
        }
        return super.onTouchEvent(e);
    }



上述代码中,在按下的时候记录下了手指在屏幕中的坐标,在手指移动的时候,记录下移动后的坐标,然后计算出和按下的时候的水平的间距dx,然后调用
scrollBy(-dx,0)来滚动画布!这里做一下重点解释dx是两点的水平距离,如果手指是向右滑动的,那么dx是大于零,而要让视图也跟着移动,就要让画布往右移动,所以这里调用方法scrollBy(-dx,0)的时候添加了一个负号

2.8目前的效果图



上面的动态图可以看到我们的图片可以左右的移动了,但是我们发现我们松手的时候并不能像
ViewPager一样平滑的滑动到指定的位置,那是因为我们没有在手指抬起的时候让画笔平滑的
滚动到指定位置

2.9编写平滑的滚动到指定位置的代码

    /**
     * 平滑的移动到指定位置
     */
    private void smoothTo(int finalX) {
        scroller.startScroll(getScrollX(), 0, finalX - getScrollX(), 0, defalutDuring);
        scrollTo(scroller.getCurrX(), 0);
    }

    /**
     * 平滑的移动dx的距离
     *
     * @param dx
     */
    private void smoothBy(int dx) {
        scroller.startScroll(getScrollX(), 0, dx, 0, defalutDuring);
    }

    /**
     * 现在选中的下标
     */
    private int currIndex = -1;

    /**
     * 设置被选中的下标
     *
     * @param index
     */
    public void setCurrentImage(int index) {
        if (index < 0) {
            index = 0;
        }
        if (index > imageCount - 1) {
            index = imageCount - 1;
        }
        currIndex = index;
        smoothTo(index * mWidth);
    }

    @Override
    public void computeScroll() {
        if (scroller.computeScrollOffset()) {
            removeRepeatData();
            scrollTo(scroller.getCurrX(), 0);
        }
        requestLayout();
    }


这里用到一个类Scroller,请参看我另一篇博客:http://blog.csdn.net/u011692041/article/details/50835670


setCurrentImage(index index)方法就是让画布滚动到指定的图片处

平滑滚动的原理:调用smoothTo(int finalX)方法,根据参数finalX得出目标横坐标和目前横坐标之间的间隔距离dx,然后调用scroller.startScroll方法计算出轨迹,然后使用类View中的
scrollTo方法,滚动到轨迹的第一个点,滚动完毕后,computerScroll方法会被调用,所以这里继续得到第二个点,让view滚动到第二个点,一直滚动到最后一个点,这样子在眼睛看来就是平滑的滚动,其实就是很多次的不间断的微小的移动!

2.10效果图



目前的效果可以达到了图片基本的显示,接下来让我们来实现指示器功能

2.11为轮播图添加指示器



要实现上述的小圆点的指示器,其实非常简单
我们可以自己绘制n个小圆点,让整体左右居中,距离顶部的距离top也可以固定下来
或者使用百分比,这里笔者建议使用百分比,这样子就省去了适配的过程

明确一下我们这个自定义控件继承的是ViewGroup,但是ViewGroup也是继承了View,所以必然有draw(Canvas canvas)方法用来绘制.
那么我们就可以利用这个方法来绘制我们需要绘制的n个小圆点,先给出一个图

    /**
     * 指示器的画笔
     */
    private Paint p = new Paint();

    /**
     * 指示器的水平间距
     */
    private int indicatorHorizontalSpacing = 10;

    /**
     * 指示器的半径
     */
    private int indicatorRadius = 10;
    /**
     * 集合中存放的是指示器的几个小圆点的坐标
     */
    private List<Point> indicatorCirclePoints = new ArrayList<Point>();

    /**
     * 计算指示器有关的数据
     * 1.n个小圆点的圆心坐标
     */
    private void computerIndicatorData() {
        if (indicatorCirclePoints.size() == 0) { //判断是为了防止在多次调用的情况下去重复计算数据
            int mTop = mHeight * 4 / 5;
            int tmpLeft = (mWidth - imageCount * 2 * indicatorRadius - (imageCount - 1) * indicatorHorizontalSpacing) / 2;
            for (int i = 0; i < imageCount; i++) {
                indicatorCirclePoints.add(new Point(tmpLeft + indicatorRadius,mTop));
                tmpLeft = tmpLeft + indicatorRadius * 2 + indicatorHorizontalSpacing;
            }
        }
    }



    /**
     * 绘制的方法
     * @param canvas
     */
    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        //计算指示器有关的数据
        computerIndicatorData();
        for (int i = 0; i < imageCount; i++) {
            if (currIndex == -1 || i == currIndex) {
                currIndex = i;
                p.setColor(Color.RED);
            } else {
                p.setColor(Color.WHITE);
            }
            int x = indicatorCirclePoints.get(i).x;
            int y = indicatorCirclePoints.get(i).y;
            c.drawCircle(getScrollX() + x, y, indicatorRadius, p);
        }
    }

这里笔者采用指示器距离顶部的距离为整个控件高度的4/5
这里预先定义好了圆点之间的间距和圆点的半径
然后算出第一个小圆点的距离控件左边的距离,然后利用循环,
计算出剩下的圆点距离控件左边的距离,从而画出n个圆点
重点解释:
1.判断中有判断currIndex == -1的情况,这是因为currentIndex默认是-1

draw方法在那些共有方法之前被调用的,所以这里不得不考虑这个情况,如果当前要绘制的小圆点的下标刚好是图片显示的下标,就让画笔的颜色变成其他不一样的颜色,这里就使用了红色,效果就是下面的效果图所示
2.画圆的时候,横坐标的值还加上了一个getScrollX()的值,这个值是整个控件的画布偏移量,也就是控件被手指左右滑动过去的偏移量,不加上这个值,你会发现你的指示器随着手指的滑动,指示器也会跟着动,所以这里为了让指示器永远的固定,就要加上这个值,保证滑动以后还是在原来的位置!

到这里我们就完成了指示器的绘制,我们在实践的过程中却发现了一个问题,指示器根本没有显示出来,这是为什么?
解答:draw方法在绘制孩子之前被调用,所以先绘制了指示器,后绘制了几个图片,这就导致绘制的指示器被图片給遮盖了!
那么我们就必须在绘制孩子之后绘制我们的指示器,那么我们需要重写dispatchDraw(Canvas c)方法,这个方法是分发绘制的意思,也就是绘制每一个孩子,所以这里我们就可以在这个方法调用之后绘制我们的指示器
把之前写在draw的代码移植到这个方法里面来:

    /**
     * 绘制孩子
     *
     * @param c
     */
    @Override
    protected void dispatchDraw(Canvas c) {
        super.dispatchDraw(c);
        //计算指示器有关的数据
        computerIndicatorData();
        for (int i = 0; i < imageCount; i++) {
            if (currIndex == -1 || i == currIndex) {
                currIndex = i;
                p.setColor(Color.RED);
            } else {
                p.setColor(Color.WHITE);
            }
            int x = indicatorCirclePoints.get(i).x;
            int y = indicatorCirclePoints.get(i).y;
            c.drawCircle(getScrollX() + x, y, indicatorRadius, p);
        }
    }


2.12目前的效果图



接下来我们还要实现点击这几个小圆点的点击事件,由于这几个小圆点是我们绘制上去的,所以这里只能自己做判断,根据用户触摸的坐标是不是在某一个小圆点的范围内

2.13为指示器添加点击事件

开发一个方法,判断触摸的时候的坐标是不是在某一个小圆点里面
    /**
     * 判断一个点是不是在一个圆里面,包括边界
     *
     * @param circleCenter
     *            圆心
     * @param radius
     *            半径
     * @param anotherPoint
     *            另一个点
     * @return
     */
    public static boolean isCircleContainsPoint(Point circleCenter, double radius, Point anotherPoint) {

        if (radius < 0) {
            throw new IllegalAccessError("半径不能小于0");
        }
        return (Math.pow(circleCenter.x - anotherPoint.x, 2) + Math.pow(circleCenter.y - anotherPoint.y, 2))
                - radius * radius > 0 ? false : true;
    }

    /**
     * 根据坐标获取选择的指示器的下标,
     *
     * @param p 触摸的坐标
     * @return 如果点击的不是指示器就返回-1
     */
    private int getSelectIndicatorIndex(Point p) {
        for (int i = 0; i < indicatorCirclePoints.size(); i++) {
            //获取每一个小圆点的圆心坐标
            Point point = indicatorCirclePoints.get(i);
            if (isCircleContainsPoint(point, indicatorRadius, p)) {
                return i;
            }
        }
        return -1;
    }

这样子就写好了获取触摸的坐标是不是在某一个小圆点的方法,-1表示触摸的坐标没有在小圆点上
让控件实现View.OnclickListener接口
然后在点击回掉方法中获取点击指示器的下标,并且让图片平滑的滑动到指定的位置


    @Override
    public void onClick(View v) {
        //获取用户触摸的指示器的下标,-1表示触摸的不是指示器
        int selectIndicatorIndex = getSelectIndicatorIndex(new Point(currentX, currentY));
        if (selectIndicatorIndex != -1) { //如果触摸的是指示器
            setCurrentImage(selectIndicatorIndex);
            setCurrentImage(selectIndicatorIndex);
        }
    }

可以看到这里我调用了两次setCurrentImage方法,但是笔者也调试了几个小时没弄明白为什么一次的时候就是不行,两次调用就没有问题,这个问题你们拿到源码之后可以研究研究,弄懂了之后请留言告诉笔者,万分感谢!
为了让控件的点击事件能生效,这里需要更改一下我们的触摸的方法里面的代码,因为点击事件是View类中已经处理好的一个事件,而我们重写之后就失去了View中写好的代码,所以这里对触摸事件做一下更改:

2.14为使用者提供一些更改ui显示效果的方法

    /**
     * 设置指示器的小圆点的半径
     * @param indicatorRadius
     */
    public void setIndicatorRadius(int indicatorRadius) {
        this.indicatorRadius = indicatorRadius;
        invalidate();
    }

    /**
     * 设置小圆点之间的间距
     * @param indicatorHorizontalSpacing
     */
    public void setIndicatorHorizontalSpacing(int indicatorHorizontalSpacing) {
        this.indicatorHorizontalSpacing = indicatorHorizontalSpacing;
        invalidate();
    }

    /**
     * 指示器被选中的小圆点的颜色
     */
    private int selectIndicatorColor = Color.RED;

    /**
     * 指示器没有被选中的小圆点的颜色
     */
    private int unSelectIndicatorColor = Color.WHITE;

    /**
     * 设置指示器选中的那个小圆点的颜色,默认是红色的
     *
     * @param color
     */
    public void setSelectIndicatorColor(int color) {
        selectIndicatorColor = color;
        invalidate();
    }

    /**
     * 设置指示器没有选中的小圆点的颜色
     *
     * @param color
     */
    public void setUnSelectIndicatorColor(int color) {
        unSelectIndicatorColor = color;
        invalidate();
    }

2.15优化加载图片功能

为了和加载图片这个功能降低耦合性,加载图片功能留给用户,所以采用设置接口的方式:
    /**
     * 加载图片的监听
     */
    public interface OnLoadImageListener {
        /**
         * 加载图片
         *
         * @param imageView
         */
        public void loadImage(ImageView imageView,String imageUrl);
    }


    /**
     * 图片加载接口对象
     */
    private OnLoadImageListener onLoadImageListener = null;

    /**
     * 设置图片加载的接口
     *
     * @param onLoadImageListener
     */
    public void setOnLoadImageListener(OnLoadImageListener onLoadImageListener) {
        this.onLoadImageListener = onLoadImageListener;
    }
然后在加载图片的时候,回掉这个接口中的方法

到此,轮播图控件制作完毕,笔者暂时没有解决的问题,请浏览者也思考思考,如果知道怎么回事,请留言!


  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Android自定义轮播控件可以使用ViewPager和Handler实现: 1. 首先创建一个自定义的ViewPager类,并重写onTouchEvent()方法,实现手势滑动效果。 ``` public class MyViewPager extends ViewPager { private float startX; private float startY; private OnItemClickListener onItemClickListener; public MyViewPager(Context context) { super(context); } public MyViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: startX = ev.getX(); startY = ev.getY(); break; case MotionEvent.ACTION_UP: float endX = ev.getX(); float endY = ev.getY(); if (startX == endX && startY == endY) { if (onItemClickListener != null) { onItemClickListener.onItemClick(getCurrentItem()); } } break; } return super.onTouchEvent(ev); } public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } public interface OnItemClickListener { void onItemClick(int position); } } ``` 2. 创建一个自定义轮播控件类,继承自LinearLayout,并在该类中初始化ViewPager和指示器,并设置自动轮播。 ``` public class MyBanner extends LinearLayout { private Context mContext; private MyViewPager mViewPager; private LinearLayout mIndicatorLayout; private List<ImageView> mIndicatorViews; private List<String> mImageUrls; private int mCurrentItem = 0; private Handler mHandler = new Handler(); public MyBanner(Context context) { super(context); initView(context); } public MyBanner(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } private void initView(Context context) { mContext = context; View view = LayoutInflater.from(mContext).inflate(R.layout.my_banner_layout, this); mViewPager = (MyViewPager) view.findViewById(R.id.viewpager); mIndicatorLayout = (LinearLayout) view.findViewById(R.id.indicator_layout); } public void setImageUrls(List<String> imageUrls) { mImageUrls = imageUrls; initIndicator(); mViewPager.setAdapter(new MyBannerAdapter()); mViewPager.setCurrentItem(Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2 % mImageUrls.size())); startAutoScroll(); } private void initIndicator() { mIndicatorViews = new ArrayList<>(); for (int i = 0; i < mImageUrls.size(); i++) { ImageView indicatorView = new ImageView(mContext); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); params.rightMargin = 20; indicatorView.setLayoutParams(params); if (i == 0) { indicatorView.setImageResource(R.drawable.indicator_selected); } else { indicatorView.setImageResource(R.drawable.indicator_normal); } mIndicatorLayout.addView(indicatorView); mIndicatorViews.add(indicatorView); } } private void startAutoScroll() { mHandler.postDelayed(new Runnable() { @Override public void run() { mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1); mHandler.postDelayed(this, 2000); } }, 2000); } private class MyBannerAdapter extends PagerAdapter { @Override public int getCount() { return Integer.MAX_VALUE; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } @Override public Object instantiateItem(ViewGroup container, final int position) { ImageView imageView = new ImageView(mContext); imageView.setScaleType(ImageView.ScaleType.FIT_XY); Glide.with(mContext).load(mImageUrls.get(position % mImageUrls.size())).into(imageView); container.addView(imageView); imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(mContext, "点击了第" + (position % mImageUrls.size() + 1) + "张图片", Toast.LENGTH_SHORT).show(); } }); return imageView; } } } ``` 3. 在布局文件中使用自定义轮播控件。 ``` <com.example.myapplication.MyBanner android:id="@+id/banner" android:layout_width="match_parent" android:layout_height="200dp" /> ``` 4. 在代码中设置轮播的图片地址。 ``` List<String> imageUrls = new ArrayList<>(); imageUrls.add("http://img2.imgtn.bdimg.com/it/u=202085641,1798154443&fm=27&gp=0.jpg"); imageUrls.add("http://img5.imgtn.bdimg.com/it/u=2746360890,4221331673&fm=27&gp=0.jpg"); imageUrls.add("http://img0.imgtn.bdimg.com/it/u=3054917406,3471798182&fm=27&gp=0.jpg"); mBanner.setImageUrls(imageUrls); ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值