简单的轮播图,实现自定义轮播icon,带标题,自动轮播,无限轮播
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" />
网友评论