ViewPager是Android中使用频率相对较高的view组件,同时对滑动过程中的事件进行了处理,因此非常适合轮播图。关于轮播图的实现,有很多方法,使用HorizontalView或者RecylerView也可以实现,但是需要处理fling操作,这里我们用ViewPager避免这些工作。
网上有很多关于ViewPager轮播的轮播实现,其原理大多数给PagerAdapter的getCount 放大N倍,N大于100,1000等。这里我们使用另一种思路,数据映射。
数据映射方案:
假设原始数据有N张图片数据,我们将数据N+2,然后将原来的第一张图片放到新的 索引为N+1的位置,原来的最后一张图片放到第一张图片,这样构建了一个新的数据。
当图片滑动到 position==0 时,我们使用viewPager.setCurrentItem(N,false) ,当position=N+1时,我们使用viewPager.setCurrentItem(1,false);便可实无限滑动。
当然,以上方案可行,也很简单,但是却破坏了原始数据,我们可以通过算法实现原始数据不被破坏的实现方式,计算出真实的数据索引。
private int getRealPosition(int position) {
int realPosition = position;
if(InnerWrapperPagerAdapter.this.getCount()>1){
if(position==0){
realPosition = (getCount()-2)-1;
}else if(position==getCount()-1){
realPosition = 0;
}else{
realPosition = position-1;
}
}
return realPosition;
}
public class AutoBannerView extends ViewPager implements Handler.Callback {
private OnPagerChangeListener mOpageChangeListener;
public static long TIME_WAIT = 3000; //每3秒轮播一次
private boolean isPlaying = false;
private OnPagerSelectedListener mOnPagerSelectedListener;
private boolean lastStateIsPlaying = false; //停止轮播之前的状态
//private static AutoBannerRunnable autoRunnable = null;
private final Handler mTaskHandler;
private static final int ACTION_PLAY = 1024*1024;
public AutoBannerView(Context context) {
this(context,null);
}
public AutoBannerView(Context context, AttributeSet attrs) {
super(context, attrs);
setOverScrollMode(OVER_SCROLL_NEVER);
setOffscreenPageLimit(5);
if(mOpageChangeListener==null){
mOpageChangeListener = new OnPagerChangeListener(this);
}
mTaskHandler = new Handler(Looper.getMainLooper(),this);
}
public void setOnPagerSelectedListener(OnPagerSelectedListener mOnPagerSelectedListener) {
this.mOnPagerSelectedListener = mOnPagerSelectedListener;
}
@Override
public boolean addViewInLayout(View child, int index, ViewGroup.LayoutParams params) {
return super.addViewInLayout(child, index, params);
}
@Override
protected boolean addViewInLayout(View child, int index, ViewGroup.LayoutParams params, boolean preventRequestLayout) {
return super.addViewInLayout(child, index, params, preventRequestLayout);
}
@Override
public void setAdapter(PagerAdapter adapter) {
if (null != getAdapter()) {
removeOnPageChangeListener(mOpageChangeListener);
}
if (null == adapter) {
super.setAdapter(null);
} else {
super.setAdapter(new InnerWrapperPagerAdapter(adapter,this));
addOnPageChangeListener(mOpageChangeListener);
if(adapter.getCount()>1){
setCurrentItem(1,false); //getCount>1 ,初始化时默认显示原始数据的第0位,也就是新的PagerAdapter的第二位
startPlay();
}else if(adapter.getCount()>0){
mOpageChangeListener.onPageSelected(0);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
finishResetPosition();
final ViewParent parent = this.getParent();
switch (ev.getActionMasked()){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
//解决ViewPager嵌套ViewPager导致无法滑动的问题
}
if(isPlaying){
stopPlay();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(false);
//解决ViewPager嵌套ViewPager导致无法滑动的问题
}
if(lastStateIsPlaying){
startPlay();
}
break;
}
return super.onTouchEvent(ev);
}
public PagerAdapter getRealAdapter() {
final PagerAdapter adapter = getAdapter();
if( adapter instanceof InnerWrapperPagerAdapter){
return ((InnerWrapperPagerAdapter) adapter).getTargetPagerAdapter();
}
return adapter;
}
public static class AdapterDataSetObserver extends DataSetObserver{
private InnerWrapperPagerAdapter innerWrapperPagerAdapter;
private AutoBannerView autoBannerView;
public AdapterDataSetObserver(InnerWrapperPagerAdapter innerWrapperPagerAdapter,AutoBannerView autoBannerView) {
this.innerWrapperPagerAdapter = innerWrapperPagerAdapter;
this.autoBannerView = autoBannerView;
}
@Override
public void onChanged() {
super.onChanged();
innerWrapperPagerAdapter.notifyDataSetChanged();
if(innerWrapperPagerAdapter.getCount()>1){
final int currentItem = this.autoBannerView.getCurrentItem();
if(currentItem==0){
this.autoBannerView.setCurrentItem(1,false);
}
if(this.autoBannerView.isPlaying || this.autoBannerView.lastStateIsPlaying){
this.autoBannerView.startPlay();
}
}
if(innerWrapperPagerAdapter.getCount()>0 &&this.autoBannerView.mOpageChangeListener!=null) {
this.autoBannerView.mOpageChangeListener.onPageSelected(this.autoBannerView.getCurrentItem());
}
}
}
/**
* 包装PagerAdapter,实现数据映射
*/
private static class InnerWrapperPagerAdapter extends PagerAdapter{
private final AdapterDataSetObserver adapterDataSetObserver;
private PagerAdapter mPagerAdapter;
public InnerWrapperPagerAdapter(PagerAdapter pagerAdapter,AutoBannerView autoBannerView) {
this.mPagerAdapter = pagerAdapter;
this.adapterDataSetObserver = new AdapterDataSetObserver(this,autoBannerView);
if(this.mPagerAdapter!=null){
this.mPagerAdapter.registerDataSetObserver(this.adapterDataSetObserver);
}
}
public PagerAdapter getTargetPagerAdapter() {
return mPagerAdapter;
}
@Override
public int getCount() {
if(mPagerAdapter!=null) { //如果数据大于1,说明可以轮播
return mPagerAdapter.getCount() > 1 ? mPagerAdapter.getCount() + 2 : mPagerAdapter.getCount();
}
return 0;
}
@Override
public boolean isViewFromObject(View view, Object object) {
if(mPagerAdapter!=null) {
return mPagerAdapter.isViewFromObject(view, object);
}
return false;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if(mPagerAdapter!=null) {
int realPosition = getRealPosition(position);
return mPagerAdapter.instantiateItem(container, realPosition);
}
return super.instantiateItem(container,position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if(mPagerAdapter!=null) {
int realPosition = getRealPosition(position);
mPagerAdapter.destroyItem(container, realPosition, object);
}else{
super.destroyItem(container,position,object);
}
}
private int getRealPosition(int position) {
int realPosition = position;
if(InnerWrapperPagerAdapter.this.getCount()>1){
if(position==0){
realPosition = (getCount()-2)-1;
}else if(position==getCount()-1){
realPosition = 0;
}else{
realPosition = position-1;
}
}
return realPosition;
}
@Override
public int getItemPosition(Object object) {
if(mPagerAdapter!=null){
return mPagerAdapter.getItemPosition(object);
}
return super.getItemPosition(object);
}
@Override
public CharSequence getPageTitle(int position) {
if(mPagerAdapter!=null) {
int realPosition = getRealPosition(position);
return mPagerAdapter.getPageTitle(realPosition);
}else{
return super.getPageTitle(position);
}
}
@Override
public float getPageWidth(int position) {
if(mPagerAdapter!=null){
int realPosition = getRealPosition(position);
return mPagerAdapter.getPageWidth(realPosition);
}
return super.getPageWidth(position);
}
@Override
public void startUpdate(ViewGroup container) {
if(mPagerAdapter!=null) {
mPagerAdapter.startUpdate(container);
}else{
super.startUpdate(container);
}
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
if(mPagerAdapter!=null) {
int realPosition = getRealPosition(position);
mPagerAdapter.setPrimaryItem(container, realPosition, object);
}else{
super.setPrimaryItem(container,position,object);
}
}
@Override
public void finishUpdate(ViewGroup container) {
if(mPagerAdapter!=null)
{
mPagerAdapter.finishUpdate(container);
}else{
super.finishUpdate(container);
}
}
@Override
public Parcelable saveState() {
if(mPagerAdapter!=null)
{
return mPagerAdapter.saveState();
}
return super.saveState();
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
if(mPagerAdapter!=null) {
mPagerAdapter.restoreState(state, loader);
}else{
super.restoreState(state,loader);
}
}
public void setPagerAdapter(PagerAdapter pagerAdapter) {
this.mPagerAdapter = pagerAdapter;
}
}
public int getClientWidth(){
return getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
}
private static class OnPagerChangeListener implements ViewPager.OnPageChangeListener{
private final AutoBannerView mAutoBannerView;
public OnPagerChangeListener(AutoBannerView autoBannerView) {
this.mAutoBannerView = autoBannerView;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(shouldCancelHandle()) return;
}
@Override
public void onPageSelected(int position) {
if(shouldCancelHandle()) return;
notifyUpdateIndictor(position);
}
public void notifyUpdateIndictor(int position) {
final int realPosition = getRealPosition(position);
if(this.mAutoBannerView.mOnPagerSelectedListener!=null){
final PagerAdapter adapter = this.mAutoBannerView.getAdapter();
final int count = adapter.getCount();
if(count>1) {
this.mAutoBannerView.mOnPagerSelectedListener.onPagerItemSelected(realPosition);
}else if(count==1){
this.mAutoBannerView.mOnPagerSelectedListener.onPagerItemSelected(1);
}else{
this.mAutoBannerView.mOnPagerSelectedListener.onPagerItemSelected(0);
}
}
}
private int getRealPosition(int position) {
int realPosition = position;
if(this.mAutoBannerView .getAdapter().getCount()>1){
PagerAdapter adapter = this.mAutoBannerView.getAdapter(); //1
if(adapter instanceof InnerWrapperPagerAdapter){
adapter = ((InnerWrapperPagerAdapter) adapter).getTargetPagerAdapter();
}
if(position==0){
realPosition = adapter.getCount();
}else if(position==adapter.getCount()+1){
realPosition = 1;
}
}
return realPosition;
}
@Override
public void onPageScrollStateChanged(int state) {
//在该方法中处理首尾切换,其他方法会产生动画中断问题
if(shouldCancelHandle()) return;
if(state!=SCROLL_STATE_IDLE){ //当动画执行完,立即切换
this.mAutoBannerView.finishResetPosition();
}
}
private boolean shouldCancelHandle() {
return this.mAutoBannerView==null || mAutoBannerView.getAdapter()==null;
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if(lastStateIsPlaying){ //如果之前是轮播的,那么继续轮播
startPlay();
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if(isPlaying) {
stopPlay();// 如果从window中移除掉,停止轮播
}
onInvisibleToUser();
}
private void onInvisibleToUser() {
final int currentItem = getCurrentItem();
PagerAdapter adapter = getAdapter();
if(adapter instanceof InnerWrapperPagerAdapter){
adapter = ((InnerWrapperPagerAdapter) adapter).getTargetPagerAdapter();
}
if(adapter!=null && adapter.getCount()>1 && currentItem>0) {
setCurrentItem(currentItem - 1);
setCurrentItem(currentItem);
}
}
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (visibility == VISIBLE) {
if(lastStateIsPlaying){ //如果之前是轮播的,那么继续轮播
startPlay();
}
} else if (visibility == INVISIBLE || visibility == GONE) {
if(isPlaying) {
stopPlay();// 如果从window中移除掉,停止轮播
}
onInvisibleToUser();
}
}
public interface OnPagerSelectedListener{
//用于监听真实的滑动位置,方便外部使用
public void onPagerItemSelected(int position);
}
public void startPlay(){
stopPlay();
isPlaying = true;
/* postDelayed(autoRunnable,TIME_WAIT);*/
mTaskHandler.sendEmptyMessageDelayed(ACTION_PLAY,TIME_WAIT);
}
public void stopPlay() {
lastStateIsPlaying = isPlaying==true;
isPlaying = false;
mTaskHandler.removeMessages(ACTION_PLAY);
}
@Override
public boolean handleMessage(Message msg) {
if(msg==null) return false;
int action = msg.what;
switch (action){
case ACTION_PLAY:
this.showNext();
return true;
}
return false;
}
private long lastExecuteTimestramp = 0;
private boolean finishResetPosition() {
if(!(this.getAdapter() instanceof InnerWrapperPagerAdapter)) return false;
int currentItem = this.getCurrentItem();
if(this.getAdapter().getCount()>1){
InnerWrapperPagerAdapter adapter = (InnerWrapperPagerAdapter) this.getAdapter();
if(currentItem==0 ){
//this.setCurrentItem(adapter.getCount()-2,false);
scrollToItem(adapter.getCount()-2,adapter.getCount());
return true;
}else if(currentItem==adapter.getCount()-1){
scrollToItem(1,adapter.getCount());
/* this.setCurrentItem(1,false)*/;
return true;
}
}
return false;
}
public void showNext() {
if(Looper.myLooper()!=Looper.getMainLooper()) return; //要求在主线程工作
final long currentTimestramp = System.currentTimeMillis();
final long diff = (currentTimestramp - lastExecuteTimestramp);
lastExecuteTimestramp = currentTimestramp;
PagerAdapter adapter = this.getAdapter();
if(null==adapter || adapter.getCount()<=1) return;
if(!this.isPlaying) return; //停止执行
int currentItem = this.getCurrentItem();
if (currentItem > 0 && currentItem < (adapter.getCount() - 1)) {
if(currentItem==1){
scrollToItem(1,adapter.getCount());
}
this.setCurrentItem(currentItem + 1, true);
}
if(diff
用法很简单我,按照ViewPager的用法即可,但是需要注意的一点是,我们仍然需要进一步封装,因此仅仅依靠自定义的轮播图,可能让人产生误解,因此我们可以进一步封装
public class SlidingBanner extends RelativeLayout implements AutoBannerView.OnPagerSelectedListener {
private AutoBannerView mAutoPlayViewPager;
private TextView mPositionTextView;
private OnPagerItemClickListener onPagerItemClickListener;
private ImageView.ScaleType scaleType = ImageView.ScaleType.FIT_XY;
private RotationPageTransformer pageTransformer;
private int offscreenPageLimit;
private int pageMargin;
public SlidingBanner(Context context) {
this(context,null);
}
public SlidingBanner(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public SlidingBanner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setScaleType(ImageView.ScaleType.FIT_XY);
}
public void setOnPagerItemClickListener(OnPagerItemClickListener onPagerItemClickListener) {
this.onPagerItemClickListener = onPagerItemClickListener;
}
public void setImageList(List imageList){
if(imageList==null){
imageList = new ArrayList<>();
}
if( !(mAutoPlayViewPager.getRealAdapter() instanceof SlidingPagerAdapter) ){
setPagerAdapter(new SlidingPagerAdapter(this, imageList));
}else{
SlidingPagerAdapter slidingPagerAdapter = (SlidingPagerAdapter) mAutoPlayViewPager.getRealAdapter();
slidingPagerAdapter.updateDatasource(imageList);
}
}
public boolean isEmptyBanner(){
if(mAutoPlayViewPager==null || mAutoPlayViewPager.getRealAdapter()==null){
return true;
}
return false;
}
public void hidePositionIndictor(){
if(mPositionTextView!=null) {
mPositionTextView.setVisibility(GONE);
}
}
public void showPositionIndictor(){
if(mPositionTextView!=null) {
mPositionTextView.setVisibility(VISIBLE);
}
}
public void setPagerAdapter(PagerAdapter pagerAdapter) {
if(mAutoPlayViewPager!=null){
mAutoPlayViewPager.setAdapter(pagerAdapter);
}
}
public PagerAdapter getPagerAdapter( ) {
return mAutoPlayViewPager.getRealAdapter();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if(mAutoPlayViewPager==null) {
mAutoPlayViewPager = createAutoPlayViewPager();
addView(mAutoPlayViewPager,0);
}
if(mPositionTextView ==null){
mPositionTextView = createPositionTextView();
addView(mPositionTextView,1);
}
mAutoPlayViewPager.setOnPagerSelectedListener(this);
}
private TextView createPositionTextView() {
TextView tv = new AppCompatTextView(this.getContext());
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.addRule(ALIGN_PARENT_BOTTOM);
lp.addRule(ALIGN_PARENT_RIGHT);
lp.rightMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,8,getResources().getDisplayMetrics());
lp.bottomMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,4,getResources().getDisplayMetrics());
PaintDrawable shapeDrawable = new PaintDrawable(0xAA000000);
shapeDrawable.setCornerRadius(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,8,getResources().getDisplayMetrics()));
tv.setBackground(shapeDrawable);
final int px = DisplayUtil.dp2px(getContext(), 8);
tv.setPadding(px,0,px,0);
tv.setLayoutParams(lp);
tv.setTextColor(Color.WHITE);
tv.setTextSize(12);
return tv;
}
private AutoBannerView createAutoPlayViewPager() {
AutoBannerView autoPlayViewPager = new AutoBannerView(getContext());
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
autoPlayViewPager.setLayoutParams(lp);
if(this.pageTransformer!=null){
autoPlayViewPager.setPageTransformer(true,this.pageTransformer);
}
if(this.offscreenPageLimit!=0){
autoPlayViewPager.setOffscreenPageLimit(this.offscreenPageLimit);
}
autoPlayViewPager.setPageMargin(this.pageMargin);
return autoPlayViewPager;
}
@Override
public void onPagerItemSelected(int position) {
if(mAutoPlayViewPager==null || mAutoPlayViewPager.getRealAdapter()==null) return;
final PagerAdapter adapter = mAutoPlayViewPager.getRealAdapter();
updateIndictor(position,adapter.getCount());
}
private void updateIndictor(int position,int count) {
if(mPositionTextView==null) return;
mPositionTextView.setText(String.format("%s/%s",position,count));
}
public ImageView.ScaleType getScaleType() {
return scaleType;
}
public void setScaleType(ImageView.ScaleType scaleType) {
this.scaleType = scaleType;
}
public void startPlay() {
if(mAutoPlayViewPager!=null){
mAutoPlayViewPager.startPlay();
}
}
public void stopPlay(){
if(mAutoPlayViewPager!=null){
mAutoPlayViewPager.stopPlay();
}
}
public void setPageTransformer(RotationPageTransformer pageTransformer) {
this.pageTransformer = pageTransformer;
if(mAutoPlayViewPager!=null){
mAutoPlayViewPager.setPageTransformer(true,pageTransformer);
}
}
public void setOffscreenPageLimit(int offscreenPageLimit) {
this.offscreenPageLimit = offscreenPageLimit;
if(mAutoPlayViewPager!=null){
mAutoPlayViewPager.setOffscreenPageLimit(this.offscreenPageLimit);
}
}
public void setPageMargin(int pageMargin) {
this.pageMargin = pageMargin;
if(mAutoPlayViewPager!=null){
mAutoPlayViewPager.setPageMargin(20);
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// notifyImageViewInvalidate();
}
private void notifyImageViewInvalidate() {
if(mAutoPlayViewPager==null) return;
final List imageViews = AppUtils.getViews(mAutoPlayViewPager, ImageView.class);
if(imageViews==null || imageViews.size()==0) return;
for (ImageView imageView : imageViews){
if(imageView==null || imageView.getVisibility()==GONE) continue;
final Drawable drawable = imageView.getDrawable();
if(drawable==null){
imageView.setImageResource(R.drawable.defualt_img);
}else {
if (!drawable.isVisible()) {
drawable.setVisible(true, false);
}else {
drawable.invalidateSelf();
}
}
}
}
public final static class SlidingPagerAdapter extends PagerAdapter{
private final SlidingBanner slidingBanner;
private List imagelst;
public SlidingPagerAdapter(SlidingBanner slidingBanner, List images){
this.slidingBanner = slidingBanner;
this.imagelst = new ArrayList<>();
this.imagelst.addAll(images);
}
@Override
public void startUpdate(ViewGroup container) {
super.startUpdate(container);
container.setEnabled(false);
}
@Override
public void finishUpdate(ViewGroup container) {
super.finishUpdate(container);
container.requestLayout();
container.invalidate();
container.setEnabled(true);
}
@Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
@Override
public int getCount() {
return imagelst.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view==object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = getView(container, position);
if(view.getParent()!= null){
final ViewGroup parent = ((ViewGroup)view.getParent());
parent.removeViewInLayout(view);
}
if(container instanceof AutoBannerView) {
((AutoBannerView) container).addViewInLayout(view,-1,view.getLayoutParams());
}else{
container.addView(view);
}
addOnClickListenerToView(view,position,container);
return view;
}
private void addOnClickListenerToView(View view,int position ,ViewGroup container) {
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int childIndex = position;
if(slidingBanner.onPagerItemClickListener!=null) {
slidingBanner.onPagerItemClickListener.onPagerItemClick(childIndex,view,container);
}
}
});
}
private View getView(ViewGroup container,int position){
final LayoutInflater inflater = LayoutInflater.from(container.getContext());
final ImageView view = getImageView(inflater, position);
Glide.with(view).diskCacheStrategy(DiskCacheStrategy.ALL).load(imagelst.get(position)).placeholder(R.drawable.xsj_default_product_img).into(view);
return view;
}
private ImageView getImageView(LayoutInflater inflater, int position) {
ImageView imageView = new AppImageView(inflater.getContext());
imageView.setImageResource(R.drawable.xsj_default_product_img);
ViewPager.LayoutParams lp = new ViewPager.LayoutParams();
imageView.setLayoutParams(lp);
if(slidingBanner.getScaleType()!=null){
imageView.setScaleType(slidingBanner.getScaleType());
}
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeViewInLayout((View) object);
}
public void updateDatasource(List imageDataset) {
if(imageDataset==null || imageDataset.size()==0){
if(this.imagelst.size()>0){
this.imagelst.clear();
notifyDataSetChanged();
}
return;
}
if(this.imagelst.size()!=imageDataset.size()){
this.imagelst.clear();
this.imagelst.addAll(imageDataset);
notifyDataSetChanged();
return;
}
boolean isNeedUpdate = false;
for (int i=0;i
使用方法:
slidingBanner.setImageList(entity);
slidingBanner.setOnPagerItemClickListener(this);
slidingBanner.startPlay();