自定义轮播图-简单不需要引用第三方库

2018-10-18  本文已影响10人  suniney

简单的轮播图,实现自定义轮播icon,带标题,自动轮播,无限轮播

S81018-154428_看图王.jpg
S81018-154436_看图王.jpg

1、自定义属性attr.xml

    <declare-styleable name="BannerView">
        <!-- 是否支持循环, 默认 true -->
        <attr name="bvIsLoop" format="boolean"/>
        <!-- 是否支持自动滚动, 默认 true -->
        <attr name="bvIsAuto" format="boolean"/>
        <!-- 滚动延时, 默认5000ms -->
        <attr name="bvDelay" format="integer"/>
        <!-- 滚动间隔, 默认5000ms -->
        <attr name="bvInterval" format="integer"/>
        <!-- 高宽比(height/width)-->
        <attr name="bvAspectRatio" format="float"/>
        <!-- 底部背景条颜色, 默认透明 -->
        <attr name="bvBarColor" format="color"/>
        <!-- 底部背景条在滚动到最后一个item时是否可见, 默认 true -->
        <attr name="bvBarVisibleWhenLast" format="boolean"/>
        <!-- 底部背景条padding, 默认10dp -->
        <attr name="bvBarPaddingLeft" format="dimension"/>
        <attr name="bvBarPaddingTop" format="dimension"/>
        <attr name="bvBarPaddingRight" format="dimension"/>
        <attr name="bvBarPaddingBottom" format="dimension"/>
        <!-- 标题文字颜色, 默认 #ffffff -->
        <attr name="bvTitleColor" format="color"/>
        <!-- 标题文字大小, 默认 14sp -->
        <attr name="bvTitleSize" format="dimension"/>
        <!-- 标题是否可见, 默认 false  -->
        <attr name="bvTitleVisible" format="boolean"/>
        <!-- 指示器是否可见, 默认 auto  -->
        <attr name="bvIndicatorVisible" format="integer">
            <enum name="auto" value="0"/>
            <enum name="always" value="1"/>
            <enum name="never" value="2"/>
        </attr>
        <!-- 指示器位置, 默认 center-->
        <attr name="bvIndicatorGravity">
            <enum name="center" value="17"/>
            <enum name="left" value="3"/>
            <enum name="right" value="5"/>
        </attr>
        <!-- 指示器项的 宽度/高度/间距, 默认 6dp -->
        <attr name="bvIndicatorWidth" format="dimension"/>
        <attr name="bvIndicatorHeight" format="dimension"/>
        <attr name="bvIndicatorSelectedWidth" format="dimension"/>
        <attr name="bvIndicatorSelectedHeight" format="dimension"/>
        <attr name="bvIndicatorGap" format="dimension"/>
        <!-- 指示器未选中颜色, 默认 #88ffffff  -->
        <attr name="bvIndicatorColor" format="color"/>
        <!-- 指示器选中颜色, 默认 #ffffff -->
        <attr name="bvIndicatorColorSelected" format="color"/>
        <!-- 指示器未选中drawable资源 -->
        <attr name="bvIndicatorDrawable" format="reference"/>
        <!-- 指示器选中drawable资源 -->
        <attr name="bvIndicatorDrawableSelected" format="reference"/>
    </declare-styleable>

2、自定义BannerView

public class BannerView<Item> extends FrameLayout {
    public static boolean DEBUG = false;
    private static final String TAG = BannerView.class.getSimpleName();

    public interface ViewFactory<Item> {
        View create(Item item, int position, ViewGroup container);
    }

    public interface TitleAdapter<Item> {
        CharSequence getTitle(Item item);
    }

    public static final int VISIBLE_AUTO = 0;
    public static final int VISIBLE_ALWAYS = 1;
    public static final int VISIBLE_NEVER = 2;

    // 设备密度
    private DisplayMetrics mDm;

    private long mDelay;        // 多久后开始滚动
    private long mInterval;     // 滚动间隔
    private boolean mIsAuto;    // 是否自动滚动
    private boolean mBarVisibleWhenLast;    // 最后一条 item 是否显示背景条
    private int mCurrentPosition;

    private boolean mIsStarted = false;
    private boolean mIsVisible = false;
    private boolean mIsResumed = true;
    private boolean mIsRunning = false;
    private final Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            if (DEBUG) {
                Log.e("yanxu", "running=" + mIsRunning + ",pos=" + mCurrentPosition);
            }
            if (mIsRunning) {
                vViewPager.setCurrentItem(mCurrentPosition + 1);
                if (isLoop() || mCurrentPosition + 1 < mDataList.size()) {
                    postDelayed(mRunnable, mInterval);
                } else {
                    mIsRunning = false;
                }
            }
        }
    };

    // 内容宽高
    private int mItemWidth;
    private int mItemHeight = LayoutParams.WRAP_CONTENT;

    private ViewPager vViewPager;
    private LinearLayout vBottomBar;
    private TextView vTitleBar;
    private ViewPagerIndicator vIndicator;

    private int mIndicatorVisible;

    private List<Item> mDataList = new ArrayList();
    private ViewPager.OnPageChangeListener mOnPageChangeListener;
    private ViewFactory mViewFactory;
    private TitleAdapter mTitleAdapter = new TitleAdapter() {
        @Override
        public CharSequence getTitle(Object o) {
            return o.toString();
        }
    };

    public BannerView(Context context) {
        this(context, null, 0);
    }

    public BannerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @SuppressWarnings("all")
    public BannerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mDm = context.getResources().getDisplayMetrics();

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BannerView);

        boolean hasAspectRatio = ta.hasValue(R.styleable.BannerView_bvAspectRatio);
        float aspectRatio = ta.getFloat(R.styleable.BannerView_bvAspectRatio, 0f);
        boolean isLoop = ta.getBoolean(R.styleable.BannerView_bvIsLoop, true);
        mDelay = ta.getInt(R.styleable.BannerView_bvDelay, 5000);
        mInterval = ta.getInt(R.styleable.BannerView_bvInterval, 5000);
        mIsAuto = ta.getBoolean(R.styleable.BannerView_bvIsAuto, true);

        mBarVisibleWhenLast = ta.getBoolean(R.styleable.BannerView_bvBarVisibleWhenLast, true);

        int indicatorGravity = ta.getInt(R.styleable.BannerView_bvIndicatorGravity, Gravity.CENTER);
        int barColor = ta.getColor(R.styleable.BannerView_bvBarColor, Color.TRANSPARENT);
        float barPaddingLeft = ta.getDimension(R.styleable.BannerView_bvBarPaddingLeft, dp2px(10));
        float barPaddingTop = ta.getDimension(R.styleable.BannerView_bvBarPaddingTop, dp2px(10));
        float barPaddingRight = ta.getDimension(R.styleable.BannerView_bvBarPaddingRight, dp2px(10));
        float barPaddingBottom = ta.getDimension(R.styleable.BannerView_bvBarPaddingBottom, dp2px(10));

        int titleColor = ta.getColor(R.styleable.BannerView_bvTitleColor, Color.WHITE);
        float titleSize = ta.getDimension(R.styleable.BannerView_bvTitleSize, sp2px(14f));
        boolean titleVisible = ta.getBoolean(R.styleable.BannerView_bvTitleVisible, false);

        // auto, aways, never
        mIndicatorVisible = ta.getInteger(R.styleable.BannerView_bvIndicatorVisible, VISIBLE_AUTO);
        Drawable indicatorDrawable = ta.getDrawable(R.styleable.BannerView_bvIndicatorDrawable);
        Drawable indicatorDrawableSelected = ta.getDrawable(R.styleable.BannerView_bvIndicatorDrawableSelected);

        int indicatorWidth = ta.getDimensionPixelSize(R.styleable.BannerView_bvIndicatorWidth, indicatorDrawable.getIntrinsicWidth());
        int indicatorHeight = ta.getDimensionPixelSize(R.styleable.BannerView_bvIndicatorHeight, indicatorDrawable.getIntrinsicHeight());
        int indicatorSelectedWidth = ta.getDimensionPixelSize(R.styleable.BannerView_bvIndicatorSelectedWidth, indicatorDrawableSelected.getIntrinsicWidth());
        int indicatorSelectedHeight = ta.getDimensionPixelSize(R.styleable.BannerView_bvIndicatorSelectedHeight, indicatorDrawableSelected.getIntrinsicHeight());
        int indicatorGap = ta.getDimensionPixelSize(R.styleable.BannerView_bvIndicatorGap, dp2px(0));
        int indicatorColor = ta.getColor(R.styleable.BannerView_bvIndicatorColor, 0x88ffffff);
        int indicatorColorSelected = ta.getColor(R.styleable.BannerView_bvIndicatorColorSelected, Color.WHITE);

        ta.recycle();


        //create ViewPager
        vViewPager = isLoop ? new LoopViewPager(context) : new ViewPager(context);
        vViewPager.setOffscreenPageLimit(1);

        int[] systemAttrs = {android.R.attr.layout_width, android.R.attr.layout_height};
        TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs);
        mItemWidth = a.getLayoutDimension(0, mDm.widthPixels);
        mItemHeight = a.getLayoutDimension(1, mItemHeight);
        a.recycle();

        if (mItemWidth < 0) {
            mItemWidth = mDm.widthPixels;
        }

        if (aspectRatio > 0) {
            if (aspectRatio > 1) {
                aspectRatio = 1;
            }
            mItemHeight = (int) (mItemWidth * aspectRatio);
        }

        Log.e(TAG, "w = " + mItemWidth + ", h = " + mItemHeight);
        LayoutParams lp = new LayoutParams(mItemWidth, mItemHeight);
        addView(vViewPager, lp);

        // bottom bar
        vBottomBar = new LinearLayout(context);
        vBottomBar.setBackgroundColor(barColor);
        vBottomBar.setPadding((int) barPaddingLeft, (int) barPaddingTop, (int) barPaddingRight, (int) barPaddingBottom);
        vBottomBar.setClipChildren(false);
        vBottomBar.setClipToPadding(false);
        vBottomBar.setOrientation(LinearLayout.VERTICAL);
        vBottomBar.setGravity(Gravity.CENTER);
        addView(vBottomBar, new LayoutParams(mItemWidth, LayoutParams.WRAP_CONTENT, Gravity.BOTTOM));

        vIndicator = new ViewPagerIndicator(context);
        vIndicator.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
        vIndicator.setItemSize(indicatorWidth, indicatorHeight);
        vIndicator.setItemSelectedSize(indicatorSelectedWidth, indicatorSelectedHeight);
        vIndicator.setItemGap(indicatorGap);

        if (indicatorDrawable != null && indicatorDrawableSelected != null) {
            vIndicator.setItemDrawable(indicatorDrawable, indicatorDrawableSelected);
        } else {
            vIndicator.setItemColor(indicatorColor, indicatorColorSelected);
        }

        // title
        vTitleBar = new TextView(context);
        vTitleBar.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
        vTitleBar.setSingleLine(true);
        vTitleBar.setTextColor(titleColor);
        vTitleBar.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleSize);
        vTitleBar.setEllipsize(TextUtils.TruncateAt.END);
        vTitleBar.setVisibility(titleVisible ? VISIBLE : INVISIBLE);

        if (indicatorGravity == Gravity.CENTER) {
            vBottomBar.addView(vTitleBar);
            vBottomBar.addView(vIndicator);
            vTitleBar.setPadding(0, 0, 0, dp2px(10));
            vTitleBar.setGravity(Gravity.CENTER);
        } else if (indicatorGravity == Gravity.RIGHT) {
            vBottomBar.addView(vTitleBar);
            vBottomBar.addView(vIndicator);
            vTitleBar.setPadding(0, 0, dp2px(10), 0);
            vTitleBar.setGravity(Gravity.LEFT);
        } else if (indicatorGravity == Gravity.LEFT) {
            vBottomBar.addView(vIndicator);
            vBottomBar.addView(vTitleBar);
            vTitleBar.setPadding(dp2px(10), 0, 0, 0);
            vTitleBar.setGravity(Gravity.RIGHT);
        }


    }

    public void setDelay(long delay) {
        this.mDelay = delay;
    }

    public void setInterval(long interval) {
        this.mInterval = interval;
    }

    public void setIsAuto(boolean isAuto) {
        this.mIsAuto = isAuto;
    }

    public void setIndicatorVisible(int value) {
        mIndicatorVisible = value;
    }

    public void setBarVisibleWhenLast(boolean value) {
        this.mBarVisibleWhenLast = value;
    }

    public void setBarColor(int barColor) {
        vBottomBar.setBackgroundColor(barColor);
    }

    public void setBarPadding(float left, float top, float right, float bottom) {
        vBottomBar.setPadding(dp2px(left), dp2px(top), dp2px(right), dp2px(bottom));
    }

    public void setTitleColor(int textColor) {
        vTitleBar.setTextColor(textColor);
    }

    public void setTitleSize(float sp) {
        vTitleBar.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp);
    }

    public void setTitleVisible(boolean isTitleVisible) {
        vTitleBar.setVisibility(isTitleVisible ? VISIBLE : INVISIBLE);
    }


    public boolean isLoop() {
        return vViewPager instanceof LoopViewPager;
    }

    public ViewPager getViewPager() {
        return vViewPager;
    }

    public ViewPagerIndicator getIndicator() {
        return vIndicator;
    }

    public void setViewFactory(@NonNull ViewFactory factory) {
        mViewFactory = factory;
    }

    public void setTitleAdapter(@NonNull TitleAdapter adapter) {
        mTitleAdapter = adapter;
    }

    public void setDataList(@NonNull List<Item> list) {
        mDataList = list;
    }

    public void setOnPageChangeListener(@NonNull ViewPager.OnPageChangeListener listener) {
        mOnPageChangeListener = listener;
    }


    void initViewPager() {
        vViewPager.setAdapter(mInternalPagerAdapter);
        vViewPager.removeOnPageChangeListener(mInternalPageListener);
        vViewPager.addOnPageChangeListener(mInternalPageListener);
        vViewPager.setOffscreenPageLimit(mDataList.size());
        mInternalPagerAdapter.notifyDataSetChanged();
        try {
            if (isLoop()) {
                setDuration(vViewPager, 500);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    void initIndicator() {
        vIndicator.setupWithViewPager(vViewPager);
        boolean visible = mIndicatorVisible == VISIBLE_ALWAYS || (mIndicatorVisible == VISIBLE_AUTO && mDataList.size() > 1);
        vIndicator.setVisibility(visible ? VISIBLE : INVISIBLE);
        vIndicator.setPosition(mCurrentPosition);
    }

    void setCurrentTitle(int position) {
        vTitleBar.setText(mTitleAdapter.getTitle(mDataList.get(position)));
    }


    boolean isValid() {
        if (vViewPager == null) {
            Log.e(TAG, "ViewPager is not exist!");
            return false;
        }
        if (mViewFactory == null) {
            Log.e(TAG, "ViewFactory must be not null!");
            return false;
        }
        if (mTitleAdapter == null) {
            Log.e(TAG, "TitleAdapter must be not null!");
            return false;
        }
        if (mDataList == null || mDataList.size() == 0) {
            Log.e(TAG, "DataList must be not empty!");
            return false;
        }
        return true;
    }

    public void start() {
        if (!isValid()) {
            return;
        }

        if (mCurrentPosition > mDataList.size() - 1) {
            mCurrentPosition = 0;
        }
        initViewPager();
        initIndicator();

        setCurrentTitle(mCurrentPosition);
        mIsStarted = true;
        update();
    }

    void update() {
        if (!isValid()) {
            return;
        }
        boolean running = mIsVisible && mIsResumed && mIsStarted && mIsAuto && mDataList.size() > 1 && (isLoop() || mCurrentPosition + 1 < mDataList.size());
        if (running != mIsRunning) {
            if (running) {
                postDelayed(mRunnable, mDelay);
            } else {
                removeCallbacks(mRunnable);
            }
            mIsRunning = running;
        }
        if (DEBUG) {
            Log.e("ezy", "update:running=" + mIsRunning + ",visible=" + mIsVisible + ",started=" + mIsStarted + ",resumed=" + mIsResumed);
            Log.e("ezy", "update:auto=" + mIsAuto + ",loop=" + isLoop() + ",size=" + mDataList.size() + ",current=" + mCurrentPosition);
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mIsVisible = false;
        update();
    }

    @Override
    protected void onWindowVisibilityChanged(int visibility) {
        super.onWindowVisibilityChanged(visibility);
        mIsVisible = visibility == VISIBLE;
        update();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mIsResumed = false;
                update();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mIsResumed = true;
                update();
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    private int dp2px(float dp) {
        return (int) (dp * mDm.density + 0.5f);
    }

    private float sp2px(float sp) {
        return sp * mDm.scaledDensity;
    }

    private ViewPager.OnPageChangeListener mInternalPageListener = new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if (mOnPageChangeListener != null) {
                mOnPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
            }
        }

        @Override
        public void onPageSelected(int position) {

            if (DEBUG) {
                Log.e("ezy", "onPageSelected, pos=" + mCurrentPosition);
            }
            mCurrentPosition = position % mDataList.size();
            setCurrentTitle(mCurrentPosition);
            vBottomBar.setVisibility(mCurrentPosition == mDataList.size() - 1 && !mBarVisibleWhenLast ? GONE : VISIBLE);

            if (mOnPageChangeListener != null) {
                mOnPageChangeListener.onPageSelected(position);
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            if (mOnPageChangeListener != null) {
                mOnPageChangeListener.onPageScrollStateChanged(state);
            }
        }
    };

    private PagerAdapter mInternalPagerAdapter = new PagerAdapter() {
        @Override
        public int getCount() {
            return mDataList.size();
        }

        @Override
        public Object instantiateItem(ViewGroup container, final int position) {
            View inflate = mViewFactory.create(mDataList.get(position), position, container);
            container.addView(inflate);
            return inflate;
        }

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

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

        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }
    };

    private static void setDuration(ViewPager pager, int duration) {
        try {
            FixedSpeedScroller scroller = new FixedSpeedScroller(pager.getContext(), new AccelerateDecelerateInterpolator(), duration);
            Field field = ViewPager.class.getDeclaredField("mScroller");
            field.setAccessible(true);
            field.set(pager, scroller);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static class FixedSpeedScroller extends Scroller {
        private int mDuration = 450;

        public FixedSpeedScroller(Context context) {
            super(context);
        }

        public FixedSpeedScroller(Context context, Interpolator interpolator, int duration) {
            super(context, interpolator);
            this.mDuration = duration;
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            super.startScroll(startX, startY, dx, dy, this.mDuration);
        }
    }
}

3、自定义指示器

public class ViewPagerIndicator extends View {

    private float mPositionOffset = 0;
    private int mPosition;

    private int mItemCount;
    private int mItemWidth;
    private int mItemHeight;
    private int mItemSelectedWidth;
    private int mItemSelectedHeight;
    private int mItemGap;

    private Drawable mItemDrawable;
    private Drawable mItemDrawableSelected;


    public ViewPagerIndicator(Context context) {
        super(context);
        init(context, null);
    }

    public ViewPagerIndicator(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public ViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
    }

    int mWidth = 0;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mItemCount > 1) {
            mWidth = (mItemSelectedWidth - mItemWidth + mItemGap) * mItemCount - mItemGap + mItemWidth;
        } else if (mItemCount == 1) {
            mWidth = mItemWidth;
        } else {
            mWidth = 0;
        }
        setMeasuredDimension(mWidth, mItemHeight);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int flags = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas
                .CLIP_TO_LAYER_SAVE_FLAG;
        int sc = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, flags);

        int wg = mItemSelectedWidth - mItemWidth + mItemGap;
        int x = (getWidth() - mWidth) / 2;
        int y = (getHeight() - mItemHeight) / 2;

        mItemDrawable.setBounds(0, 0, mItemWidth, mItemHeight);
        mItemDrawableSelected.setBounds(0, 0, mItemSelectedWidth, mItemSelectedHeight);

        for (int i = 0; i < mItemCount; i++) {
            canvas.save();
            canvas.translate(x + i * wg, y);
            mItemDrawable.draw(canvas);
            canvas.restore();
        }

        canvas.save();
        canvas.translate(x + (mPosition + mPositionOffset) * wg, y);
        mItemDrawableSelected.draw(canvas);
        canvas.restore();

        canvas.restoreToCount(sc);
    }

    public void setupWithViewPager(ViewPager pager) {
        mItemCount = pager.getAdapter().getCount();
        pager.removeOnPageChangeListener(onPageChangeListener);
        pager.addOnPageChangeListener(onPageChangeListener);
        requestLayout();
    }

    public void setPosition(int position) {
        mPosition = position;
        invalidate();
    }


    public ViewPagerIndicator setItemSize(int width, int height) {
        this.mItemWidth = width;
        this.mItemHeight = height;
        return this;
    }

    public ViewPagerIndicator setItemSelectedSize(int width, int height) {
        this.mItemSelectedWidth = width;
        this.mItemSelectedHeight = height;
        return this;
    }

    public ViewPagerIndicator setItemGap(int gap) {
        this.mItemGap = gap;
        return this;
    }

    public ViewPagerIndicator setItemColor(@ColorInt int color, @ColorInt int selected) {
        this.mItemDrawable = genDrawable(color);
        this.mItemDrawableSelected = genDrawable(selected);
        return this;
    }

    public ViewPagerIndicator setItemDrawable(@NonNull Drawable normal, @NonNull Drawable selected) {
        this.mItemDrawable = normal;
        this.mItemDrawableSelected = selected;
        return this;
    }

    Drawable genDrawable(int color) {
        ShapeDrawable drawable = new ShapeDrawable(new OvalShape());
        drawable.getPaint().setColor(color);
        drawable.getPaint().setAntiAlias(true);
        return drawable;
    }

    ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            mPosition = position;
            mPositionOffset = positionOffset;
            invalidate();
        }

        @Override
        public void onPageSelected(int position) {
            mPosition = position;
            mPositionOffset = 0;
            invalidate();
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    };
}

4、轮播的viewpager

public class LoopViewPager extends ViewPager {

    private InnerLoopAdapter mAdapter;

    static int toRealPosition(int position, int count) {
        if (count <= 1) {
            return 0;
        }
        return (position - 1 + count) % count;
    }

    static int toInnerPosition(int real) {
        return real + 1;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int count = getChildCount();

        if (count > 0) {
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = MeasureSpec.getSize(heightMeasureSpec);
            View child = getChildAt(0);
            child.measure(widthMeasureSpec, heightMeasureSpec);

            if (width == ViewGroup.LayoutParams.WRAP_CONTENT || width == 0) {
                widthMeasureSpec = MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(), MeasureSpec.EXACTLY);
            }
            if (height == ViewGroup.LayoutParams.WRAP_CONTENT || height == 0) {
                heightMeasureSpec = MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(), MeasureSpec.EXACTLY);
            }
        }

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    public void setAdapter(PagerAdapter adapter) {
        mAdapter = adapter == null ? null : new InnerLoopAdapter(adapter);
        super.setAdapter(mAdapter);
        setCurrentItem(0, false);
    }

    @Override
    public PagerAdapter getAdapter() {
        return mAdapter != null ? mAdapter.pa : null;
    }

    @Override
    public int getCurrentItem() {
        return mAdapter != null ? mAdapter.getRealPosition(super.getCurrentItem()) : 0;
    }

    @Override
    public void setCurrentItem(int item, boolean smoothScroll) {
        super.setCurrentItem(toInnerPosition(item), smoothScroll);
    }

    @Override
    public void setCurrentItem(int item) {
        super.setCurrentItem(toInnerPosition(item), true);
    }

    @Override
    public void setOnPageChangeListener(OnPageChangeListener listener) {
        removeOnPageChangeListener(listener);
        addOnPageChangeListener(listener);
    }

    List<OnPageChangeListener> mOnPageChangeListeners;
    @Override
    public void addOnPageChangeListener(OnPageChangeListener listener) {
        if (mOnPageChangeListeners == null) {
            mOnPageChangeListeners = new ArrayList<>();
        }
        mOnPageChangeListeners.add(listener);
    }
    @Override
    public void removeOnPageChangeListener(OnPageChangeListener listener) {
        if (mOnPageChangeListeners != null) {
            mOnPageChangeListeners.remove(listener);
        }
    }
    @Override
    public void clearOnPageChangeListeners() {
        if (mOnPageChangeListeners != null) {
            mOnPageChangeListeners.clear();
        }
    }

    private void dispatchOnPageScrolled(int position, float offset, int offsetPixels) {
        if (mOnPageChangeListeners != null) {
            for (int i = 0, z = mOnPageChangeListeners.size(); i < z; i++) {
                OnPageChangeListener listener = mOnPageChangeListeners.get(i);
                if (listener != null) {
                    listener.onPageScrolled(position, offset, offsetPixels);
                }
            }
        }
    }

    private void dispatchOnPageSelected(int position) {
        if (mOnPageChangeListeners != null) {
            for (int i = 0, z = mOnPageChangeListeners.size(); i < z; i++) {
                OnPageChangeListener listener = mOnPageChangeListeners.get(i);
                if (listener != null) {
                    listener.onPageSelected(position);
                }
            }
        }
    }

    private void dispatchOnScrollStateChanged(int state) {
        if (mOnPageChangeListeners != null) {
            for (int i = 0, z = mOnPageChangeListeners.size(); i < z; i++) {
                OnPageChangeListener listener = mOnPageChangeListeners.get(i);
                if (listener != null) {
                    listener.onPageScrollStateChanged(state);
                }
            }
        }
    }

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

    public LoopViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        super.addOnPageChangeListener(mInnerListener);
    }

    private OnPageChangeListener mInnerListener = new OnPageChangeListener() {
        private float mPreviousOffset = -1;
        private float mPreviousPosition = -1;

        @Override
        public void onPageSelected(int position) {

            int real = mAdapter.getRealPosition(position);
            if (mPreviousPosition == real) {
                return;
            }
            mPreviousPosition = real;

            dispatchOnPageSelected(real);
        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if (mAdapter == null) {
                mPreviousOffset = positionOffset;
                if (positionOffset > .5) {
                    dispatchOnPageScrolled(0, 0, 0);
                } else {
                    dispatchOnPageScrolled(position, 0, 0);
                }
                return;
            }
            int realPosition = mAdapter.getRealPosition(position);
            int lastPosition = mAdapter.getCount() - 1;

            if (positionOffset == 0 && mPreviousOffset == 0 && lastPosition != 0 && (position == 0 || position == lastPosition)) {
                setCurrentItem(realPosition, false);
            }

            mPreviousOffset = positionOffset;

            if (realPosition != mAdapter.getRealCount() - 1) {
                dispatchOnPageScrolled(realPosition, positionOffset, positionOffsetPixels);
            } else if (positionOffset > .5) {
                dispatchOnPageScrolled(0, 0, 0);
            } else {
                dispatchOnPageScrolled(realPosition, 0, 0);
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            if (mAdapter != null) {
                int position = LoopViewPager.super.getCurrentItem();
                if (state == ViewPager.SCROLL_STATE_IDLE && (position == 0 || position == mAdapter.getCount() - 1)) {
                    setCurrentItem(mAdapter.getRealPosition(position), false);
                }
            }
            dispatchOnScrollStateChanged(state);
        }
    };

    private static class InnerLoopAdapter extends PagerAdapter {

        final PagerAdapter pa;

        private SparseArray<Object> recycler = new SparseArray<Object>();


        InnerLoopAdapter(PagerAdapter adapter) {
            this.pa = adapter;
        }

        @Override
        public void notifyDataSetChanged() {
            recycler = new SparseArray<Object>();
            super.notifyDataSetChanged();
        }

        int getRealPosition(int position) {
            return toRealPosition(position, pa.getCount());
        }

        int getRealCount() {
            return pa.getCount();
        }

        @Override
        public int getCount() {
            int realCount = getRealCount();
            return realCount > 1 ? (realCount + 2) : realCount;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            int real = getRealPosition(position);

            Object destroy = recycler.get(position);
            if (destroy != null) {
                recycler.remove(position);
                return destroy;
            }
            return pa.instantiateItem(container, real);
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            int first = 1, last = getRealCount();

            if (position == first || position == last) {
                recycler.put(position, object);
            } else {
                pa.destroyItem(container, getRealPosition(position), object);
            }
        }

        @Override
        public void finishUpdate(ViewGroup container) {
            pa.finishUpdate(container);
        }

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

        @Override
        public void restoreState(Parcelable bundle, ClassLoader classLoader) {
            pa.restoreState(bundle, classLoader);
        }

        @Override
        public Parcelable saveState() {
            return pa.saveState();
        }

        @Override
        public void startUpdate(ViewGroup container) {
            pa.startUpdate(container);
        }

        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            pa.setPrimaryItem(container, position, object);
        }
    }

}

5、代码中引用

  public static String[] titles = new String[]{
            "每周7件Tee不重样",
            "俏皮又知性 适合上班族的漂亮衬衫",
            "名侦探柯南",
            "境界之轮回",
            "我的英雄学院",
            "全职猎人",
    };
    public static String[] urls = new String[]{//750x500
            "https://s2.mogucdn.com/mlcdn/c45406/170422_678did070ec6le09de3g15c1l7l36_750x500.jpg",
            "https://s2.mogucdn.com/mlcdn/c45406/170420_1hcbb7h5b58ihilkdec43bd6c2ll6_750x500.jpg",
            "http://s18.mogucdn.com/p2/170122/upload_66g1g3h491bj9kfb6ggd3i1j4c7be_750x500.jpg",
            "http://s18.mogucdn.com/p2/170204/upload_657jk682b5071bi611d9ka6c3j232_750x500.jpg",
            "http://s16.mogucdn.com/p2/170204/upload_56631h6616g4e2e45hc6hf6b7g08f_750x500.jpg",
            "http://s16.mogucdn.com/p2/170206/upload_1759d25k9a3djeb125a5bcg0c43eg_750x500.jpg"};

    public static class BannerItem {
        public String image;
        public String title;

        @Override
        public String toString() {
            return title;
        }
    }

    public static class BannerViewFactory implements BannerView.ViewFactory<BannerItem> {
        @Override
        public View create(final BannerItem item, int position, final ViewGroup container) {
            ImageView iv = new ImageView(container.getContext());
            iv.setScaleType(ImageView.ScaleType.CENTER_CROP);
            RequestOptions options = new RequestOptions().diskCacheStrategy(DiskCacheStrategy.DATA);
            Glide.with(container.getContext().getApplicationContext()).load(item.image).apply(options).into(iv);
            iv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    ToastUtil.showToast(container.getContext(), item.title, 0);
                }
            });
            return iv;
        }
    }
  @Override
    protected void initViews(View view) {
        List<BannerItem> list = new ArrayList<>();
        for (int i = 0; i < urls.length; i++) {
            BannerItem item = new BannerItem();
            item.image = urls[i];
            item.title = titles[i];

            list.add(item);
        }

        banner.setViewFactory(new BannerViewFactory());
        banner.setDataList(list);
        banner.start();
    }

6、xml布局文件

<com.xxxx.banner.BannerView
  android:id="@+id/banner"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:background="@android:color/holo_red_dark"
  app:bvAspectRatio="0.5625"
  app:bvIndicatorDrawable="@mipmap/ic_banner_normal"
  app:bvIndicatorDrawableSelected="@mipmap/ic_banner_selected"
  app:bvIndicatorGravity="center"
  app:bvTitleVisible="true" />
上一篇 下一篇

猜你喜欢

热点阅读