高效轮播图

package cn.luxurygroup.mall.common.widget;

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.drawable.Drawable;

import android.graphics.drawable.GradientDrawable;

import android.graphics.drawable.LayerDrawable;

import android.os.Handler;

import android.os.Message;

import android.support.annotation.NonNull;

import android.support.v4.view.PagerAdapter;

import android.support.v4.view.ViewPager;

import android.util.AttributeSet;

import android.view.Gravity;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.view.animation.Interpolator;

import android.widget.ImageView;

import android.widget.LinearLayout;

import android.widget.RelativeLayout;

import android.widget.Scroller;


import cn.luxurygroup.mall.R;


import com.bumptech.glide.Glide;


import java.lang.reflect.Field;

import java.util.ArrayList;

import java.util.List;


public class BannerLayout extends RelativeLayout {


    private ViewPager pager;

    //指示器容器

    private LinearLayout indicatorContainer;


    private Drawable unSelectedDrawable;

    private Drawable selectedDrawable;


    private int WHAT_AUTO_PLAY = 1000;


    private boolean isAutoPlay = true;


    private int itemCount;


    private int selectedIndicatorColor = 0xffff0000;

    private int unSelectedIndicatorColor = 0x88888888;


    private Shape indicatorShape = Shape.oval;

    private int selectedIndicatorHeight = 6;

    private int selectedIndicatorWidth = 6;

    private int unSelectedIndicatorHeight = 6;

    private int unSelectedIndicatorWidth = 6;


    private Position indicatorPosition = Position.centerBottom;

    private int autoPlayDuration = 4000;

    private int scrollDuration = 900;


    private int indicatorSpace = 3;

    private int indicatorMargin = 10;


    private int defaultImage;


    private enum Shape {

        rect, oval

    }


    private enum Position {

        centerBottom,

        rightBottom,

        leftBottom,

        centerTop,

        rightTop,

        leftTop

    }


    private OnBannerItemClickListener onBannerItemClickListener;


    private Handler handler = new Handler(new Handler.Callback() {

        @Override

        public boolean handleMessage(Message msg) {

            if (msg.what == WHAT_AUTO_PLAY) {

                if (pager != null) {

                    pager.setCurrentItem(pager.getCurrentItem() + 1, true);

                    handler.sendEmptyMessageDelayed(WHAT_AUTO_PLAY, autoPlayDuration);

                }

            }

            return false;

        }

    });


    public BannerLayout(Context context) {

        super(context);

        init(null, 0);

    }


    public BannerLayout(Context context, AttributeSet attrs) {

        super(context, attrs);

        init(attrs, 0);

    }


    public BannerLayout(Context context, AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);

        init(attrs, defStyleAttr);

    }


    private void init(AttributeSet attrs, int defStyle) {


        TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.BannerLayoutStyle, defStyle, 0);

        selectedIndicatorColor = array.getColor(R.styleable.BannerLayoutStyle_selectedIndicatorColor, selectedIndicatorColor);

        unSelectedIndicatorColor = array.getColor(R.styleable.BannerLayoutStyle_unSelectedIndicatorColor, unSelectedIndicatorColor);


        int shape = array.getInt(R.styleable.BannerLayoutStyle_indicatorShape, Shape.oval.ordinal());

        for (Shape shape1 : Shape.values()) {

            if (shape1.ordinal() == shape) {

                indicatorShape = shape1;

                break;

            }

        }

        selectedIndicatorHeight = (int) array.getDimension(R.styleable.BannerLayoutStyle_selectedIndicatorHeight, selectedIndicatorHeight);

        selectedIndicatorWidth = (int) array.getDimension(R.styleable.BannerLayoutStyle_selectedIndicatorWidth, selectedIndicatorWidth);

        unSelectedIndicatorHeight = (int) array.getDimension(R.styleable.BannerLayoutStyle_unSelectedIndicatorHeight, unSelectedIndicatorHeight);

        unSelectedIndicatorWidth = (int) array.getDimension(R.styleable.BannerLayoutStyle_unSelectedIndicatorWidth, unSelectedIndicatorWidth);


        int position = array.getInt(R.styleable.BannerLayoutStyle_indicatorPosition, Position.centerBottom.ordinal());

        for (Position position1 : Position.values()) {

            if (position == position1.ordinal()) {

                indicatorPosition = position1;

            }

        }

        indicatorSpace = (int) array.getDimension(R.styleable.BannerLayoutStyle_indicatorSpace, indicatorSpace);

        indicatorMargin = (int) array.getDimension(R.styleable.BannerLayoutStyle_indicatorMargin, indicatorMargin);

        autoPlayDuration = array.getInt(R.styleable.BannerLayoutStyle_autoPlayDuration, autoPlayDuration);

        scrollDuration = array.getInt(R.styleable.BannerLayoutStyle_scrollDuration, scrollDuration);

        isAutoPlay = array.getBoolean(R.styleable.BannerLayoutStyle_isAutoPlay, isAutoPlay);

        defaultImage = array.getResourceId(R.styleable.BannerLayoutStyle_defaultImage,defaultImage);

        array.recycle();


        //绘制未选中状态图形

        LayerDrawable unSelectedLayerDrawable;

        LayerDrawable selectedLayerDrawable;

        GradientDrawable unSelectedGradientDrawable;

        unSelectedGradientDrawable = new GradientDrawable();


        //绘制选中状态图形

        GradientDrawable selectedGradientDrawable;

        selectedGradientDrawable = new GradientDrawable();

        switch (indicatorShape) {

            case rect:

                unSelectedGradientDrawable.setShape(GradientDrawable.RECTANGLE);

                selectedGradientDrawable.setShape(GradientDrawable.RECTANGLE);

                break;

            case oval:

                unSelectedGradientDrawable.setShape(GradientDrawable.OVAL);

                selectedGradientDrawable.setShape(GradientDrawable.OVAL);

                break;

        }

        unSelectedGradientDrawable.setColor(unSelectedIndicatorColor);

        unSelectedGradientDrawable.setSize(unSelectedIndicatorWidth, unSelectedIndicatorHeight);

        unSelectedLayerDrawable = new LayerDrawable(new Drawable[]{unSelectedGradientDrawable});

        unSelectedDrawable = unSelectedLayerDrawable;


        selectedGradientDrawable.setColor(selectedIndicatorColor);

        selectedGradientDrawable.setSize(selectedIndicatorWidth, selectedIndicatorHeight);

        selectedLayerDrawable = new LayerDrawable(new Drawable[]{selectedGradientDrawable});

        selectedDrawable = selectedLayerDrawable;


    }


    //添加本地图片路径

    public void setViewRes(List<Integer> viewRes) {

        List<View> views = new ArrayList<>();

        itemCount = viewRes.size();

        //主要是解决当item为小于3个的时候滑动有问题,这里将其拼凑成3个以上

        if (itemCount < 1) {//当item个数0

            throw new IllegalStateException("item count not equal zero");

        } else if (itemCount < 2) {//当item个数为1

            views.add(getImageView(viewRes.get(0), 0));

            views.add(getImageView(viewRes.get(0), 0));

            views.add(getImageView(viewRes.get(0), 0));

        } else if (itemCount < 3) {//当item个数为2

            views.add(getImageView(viewRes.get(0), 0));

            views.add(getImageView(viewRes.get(1), 1));

            views.add(getImageView(viewRes.get(0), 0));

            views.add(getImageView(viewRes.get(1), 1));

        } else {

            for (int i = 0; i < viewRes.size(); i++) {

                views.add(getImageView(viewRes.get(i), i));

            }

        }

        setViews(views);

    }


    @NonNull

    private ImageView getImageView(Integer res, final int position) {

        ImageView imageView = new ImageView(getContext());

        imageView.setOnClickListener(new OnClickListener() {

            @Override

            public void onClick(View v) {

                if (onBannerItemClickListener != null) {

                    onBannerItemClickListener.onItemClick(position);

                }

            }

        });

        imageView.setScaleType(ImageView.ScaleType.FIT_XY);

        Glide.with(getContext()).load(res).into(imageView);

        return imageView;

    }


    //添加网络图片路径

    public void setViewUrls(List<String> urls) {

        List<View> views = new ArrayList<>();

        itemCount = urls.size();

        //主要是解决当item为小于3个的时候滑动有问题,这里将其拼凑成3个以上

        if (itemCount < 1) {//当item个数0

            throw new IllegalStateException("item count not equal zero");

        } else if (itemCount < 2) { //当item个数为1

            views.add(getImageView(urls.get(0), 0));

            views.add(getImageView(urls.get(0), 0));

            views.add(getImageView(urls.get(0), 0));

        } else if (itemCount < 3) {//当item个数为2

            views.add(getImageView(urls.get(0), 0));

            views.add(getImageView(urls.get(1), 1));

            views.add(getImageView(urls.get(0), 0));

            views.add(getImageView(urls.get(1), 1));

        } else {

            for (int i = 0; i < urls.size(); i++) {

                views.add(getImageView(urls.get(i), i));

            }

        }

        setViews(views);

    }


    @NonNull

    private ImageView getImageView(String url, final int position) {

        ImageView imageView = new ImageView(getContext());

        imageView.setScaleType(ImageView.ScaleType.FIT_XY);

        imageView.setOnClickListener(new OnClickListener() {

            @Override

            public void onClick(View v) {

                if (onBannerItemClickListener != null) {

                    onBannerItemClickListener.onItemClick(position);

                }

            }

        });

        imageView.setScaleType(ImageView.ScaleType.FIT_XY);

        if (defaultImage != 0){

            Glide.with(getContext()).load(url).placeholder(defaultImage).into(imageView);

        }else {

            Glide.with(getContext()).load(url).into(imageView);

        }

        return imageView;

    }


    //添加任意View视图

    private void setViews(final List<View> views) {

        //初始化pager

        pager = new ViewPager(getContext());

        //添加viewpager到SliderLayout

        addView(pager);

        setSliderTransformDuration(scrollDuration);

        //初始化indicatorContainer

        indicatorContainer = new LinearLayout(getContext());

        indicatorContainer.setGravity(Gravity.CENTER_VERTICAL);

        RelativeLayout.LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);


        switch (indicatorPosition) {

            case centerBottom:

                params.addRule(RelativeLayout.CENTER_HORIZONTAL);

                params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);

                break;

            case centerTop:

                params.addRule(RelativeLayout.CENTER_HORIZONTAL);

                params.addRule(RelativeLayout.ALIGN_PARENT_TOP);

                break;

            case leftBottom:

                params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);

                params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);

                break;

            case leftTop:

                params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);

                params.addRule(RelativeLayout.ALIGN_PARENT_TOP);

                break;

            case rightBottom:

                params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);

                params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);

                break;

            case rightTop:

                params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);

                params.addRule(RelativeLayout.ALIGN_PARENT_TOP);

                break;

        }

        //设置margin

        params.setMargins(indicatorMargin, indicatorMargin, indicatorMargin, indicatorMargin);

        //添加指示器容器布局到SliderLayout

        addView(indicatorContainer, params);


        //初始化指示器,并添加到指示器容器布局

        for (int i = 0; i < itemCount; i++) {

            ImageView indicator = new ImageView(getContext());

            indicator.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));

            indicator.setPadding(indicatorSpace, indicatorSpace, indicatorSpace, indicatorSpace);

            indicator.setImageDrawable(unSelectedDrawable);

            indicatorContainer.addView(indicator);

        }

        LoopPagerAdapter pagerAdapter = new LoopPagerAdapter(views);

        pager.setAdapter(pagerAdapter);

        //设置当前item到Integer.MAX_VALUE中间的一个值,看起来像无论是往前滑还是往后滑都是ok的

        //如果不设置,用户往左边滑动的时候已经划不动了

        int targetItemPosition = Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % itemCount;

        pager.setCurrentItem(targetItemPosition);

        switchIndicator(targetItemPosition % itemCount);

        pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {

            @Override

            public void onPageSelected(int position) {

                switchIndicator(position % itemCount);

            }

        });

        startAutoPlay();


    }


    public void setSliderTransformDuration(int duration) {

        try {

            Field mScroller = ViewPager.class.getDeclaredField("mScroller");

            mScroller.setAccessible(true);

            FixedSpeedScroller scroller = new FixedSpeedScroller(pager.getContext(), null, duration);

            mScroller.set(pager, scroller);

        } catch (Exception e) {

            e.printStackTrace();


        }

    }


    /**

     * 开始自动轮播

     */

    public void startAutoPlay() {

        stopAutoPlay(); // 避免重复消息

        if (isAutoPlay) {

            handler.sendEmptyMessageDelayed(WHAT_AUTO_PLAY, autoPlayDuration);

        }

    }


    @Override

    protected void onWindowVisibilityChanged(int visibility) {

        super.onWindowVisibilityChanged(visibility);

        if (visibility == VISIBLE) {

            startAutoPlay();

        } else {

            stopAutoPlay();

        }

    }



    /**

     * 停止自动轮播

     */

    public void stopAutoPlay() {

        if (isAutoPlay) {

            handler.removeMessages(WHAT_AUTO_PLAY);

        }

    }


    @Override

    public boolean dispatchTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {

            case MotionEvent.ACTION_DOWN:

                stopAutoPlay();

                break;

            case MotionEvent.ACTION_CANCEL:

            case MotionEvent.ACTION_UP:

                startAutoPlay();

                break;

        }

        return super.dispatchTouchEvent(ev);

    }


    /**

     * 切换指示器状态

     *

     * @param currentPosition 当前位置

     */

    private void switchIndicator(int currentPosition) {

        for (int i = 0; i < indicatorContainer.getChildCount(); i++) {

            ((ImageView) indicatorContainer.getChildAt(i)).setImageDrawable(i == currentPosition ? selectedDrawable : unSelectedDrawable);

        }

    }



    public void setOnBannerItemClickListener(OnBannerItemClickListener onBannerItemClickListener) {

        this.onBannerItemClickListener = onBannerItemClickListener;

    }


    public interface OnBannerItemClickListener {

        void onItemClick(int position);

    }


    public class LoopPagerAdapter extends PagerAdapter {

        private List<View> views;


        public LoopPagerAdapter(List<View> views) {

            this.views = views;

        }


        @Override

        public int getCount() {

            //Integer.MAX_VALUE = 2147483647

            return Integer.MAX_VALUE;

        }


        @Override

        public boolean isViewFromObject(View view, Object object) {

            return view == object;

        }


        @Override

        public Object instantiateItem(ViewGroup container, int position) {

            if (views.size() > 0) {

                //position % view.size()是指虚拟的position会在[0,view.size())之间循环

                View view = views.get(position % views.size());

                if (container.equals(view.getParent())) {

                    container.removeView(view);

                }

                container.addView(view);

                return view;

            }

            return null;

        }


        @Override

        public void destroyItem(ViewGroup container, int position, Object object) {

        }

    }


    public class FixedSpeedScroller extends Scroller {


        private int mDuration = 1000;


        public FixedSpeedScroller(Context context) {

            super(context);

        }


        public FixedSpeedScroller(Context context, Interpolator interpolator) {

            super(context, interpolator);

        }


        public FixedSpeedScroller(Context context, Interpolator interpolator, int duration) {

            this(context, interpolator);

            mDuration = duration;

        }


        @Override

        public void startScroll(int startX, int startY, int dx, int dy, int duration) {

            // Ignore received duration, use fixed one instead

            super.startScroll(startX, startY, dx, dy, mDuration);

        }


        @Override

        public void startScroll(int startX, int startY, int dx, int dy) {

            // Ignore received duration, use fixed one instead

            super.startScroll(startX, startY, dx, dy, mDuration);

        }

    }

}

《attrs》

<!--轮播图 -->

    <declare-styleable name="BannerLayoutStyle">

        <attr name="selectedIndicatorColor" format="color|reference" />

        <attr name="unSelectedIndicatorColor" format="color|reference" />

        <attr name="indicatorShape" format="enum">

            <enum name="rect" value="0" />

            <enum name="oval" value="1" />

        </attr>


        <attr name="selectedIndicatorHeight" format="dimension|reference" />

        <attr name="selectedIndicatorWidth" format="dimension|reference" />


        <attr name="unSelectedIndicatorHeight" format="dimension|reference" />

        <attr name="unSelectedIndicatorWidth" format="dimension|reference" />


        <attr name="indicatorPosition" format="enum">

            <enum name="centerBottom" value="0" />

            <enum name="rightBottom" value="1" />

            <enum name="leftBottom" value="2" />

            <enum name="centerTop" value="3" />

            <enum name="rightTop" value="4" />

            <enum name="leftTop" value="5" />

        </attr>


        <attr name="indicatorSpace" format="dimension|reference" />

        <attr name="indicatorMargin" format="dimension|reference" />

        <attr name="autoPlayDuration" format="integer|reference" />

        <attr name="scrollDuration" format="integer|reference" />

        <attr name="isAutoPlay" format="boolean"/>

        <attr name="defaultImage" format="integer|reference"/>

    </declare-styleable>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容