Android--ViewPager----完美轮播

效果图:

这里写图片描述
一:代码使用
MainActivity:

public class MainActivity extends AppCompatActivity {
    String url = "https://img1.doubanio.com/view/photo/photo/public/p2328130909.jpg";

List<String> urls = new ArrayList<>();
AutoScrollViewPager viewPager;
LinearLayout container;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initImage();
}


public void initImage() {
viewPager = (AutoScrollViewPager) findViewById(R.id.viewpager);
container = (LinearLayout) findViewById(R.id.container);
urls.add(url);
urls.add(url);
urls.add(url);
urls.add(url);
showTimeWheel(urls);
}


public void showTimeWheel(List<String> urls) {
viewPager.setAdapter(new TimePagerAdapter(this, urls));
viewPager.setOnPointIndex(urls.size(), container);   
        //开始滚动
viewPager.startAutoScroll();
}


@Override
public void onPause() {
super.onPause();
viewPager.stopAutoScroll();
}

@Override
public void onResume() {
super.onResume();
viewPager.startAutoScroll();
}

}

activity_main:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.erhu.myviewpager.MainActivity">

    <com.erhu.view.AutoScrollViewPager
android:id="@+id/viewpager"
android:src="@mipmap/ic_launcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

    <LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="40px"
android:layout_alignParentBottom="true"
android:gravity="center"
android:orientation="horizontal" />
</RelativeLayout>

TimePagerAdapter:

public class TimePagerAdapter extends ImagePagerAdapter<String> {
    Context context;

    public TimePagerAdapter(Context context, List<String> urls) {
super(context, urls);
        this.context = context;
}

@Override
public void setImageView(ImageView imageView, String coupon) {    
        // 使用ImageLoader进行图片下载
        ImageLoader.getInstance().displayImage(coupon, imageView);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
              //针对每个view的图片操作
            }
        });


}
}

二:实现

RecycleGBin:

public class RecycleBin {

private View[] activeViews = new View[0];
    private int[] activeViewTypes = new int[0];

    private SparseArray<View>[] scrapViews;

    private int viewTypeCount;

    private SparseArray<View> currentScrapViews;

    public void setViewTypeCount(int viewTypeCount) {
if (viewTypeCount < 1) {
throw new IllegalArgumentException("Can't have a viewTypeCount < 1");
}
        SparseArray<View>[] scrapViews = new SparseArray[viewTypeCount];
        for (int i = 0; i < viewTypeCount; i++) {
            scrapViews[i] = new SparseArray<View>();
}
this.viewTypeCount = viewTypeCount;
currentScrapViews = scrapViews[0];
        this.scrapViews = scrapViews;
}

protected boolean shouldRecycleViewType(int viewType) {
return viewType >= 0;
}

    View getScrapView(int position, int viewType) {
if (viewTypeCount == 1) {
return retrieveFromScrap(currentScrapViews, position);
} else if (viewType >= 0 && viewType < scrapViews.length) {
return retrieveFromScrap(scrapViews[viewType], position);
}
return null;
}

void addScrapView(View scrap, int position, int viewType) {
if (viewTypeCount == 1) {
currentScrapViews.put(position, scrap);
} else {
scrapViews[viewType].put(position, scrap);
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            scrap.setAccessibilityDelegate(null);
}
    }

void scrapActiveViews() {
final View[] activeViews = this.activeViews;
        final int[] activeViewTypes = this.activeViewTypes;
        final boolean multipleScraps = viewTypeCount > 1;

SparseArray<View> scrapViews = currentScrapViews;
        final int count = activeViews.length;
        for (int i = count - 1; i >= 0; i--) {
final View victim = activeViews[i];
            if (victim != null) {
int whichScrap = activeViewTypes[i];

activeViews[i] = null;
activeViewTypes[i] = -1;

                if (!shouldRecycleViewType(whichScrap)) {
continue;
}

if (multipleScraps) {
                    scrapViews = this.scrapViews[whichScrap];
}
                scrapViews.put(i, victim);

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    victim.setAccessibilityDelegate(null);
}
            }
        }

        pruneScrapViews();
}

private void pruneScrapViews() {
final int maxViews = activeViews.length;
        final int viewTypeCount = this.viewTypeCount;
        final SparseArray<View>[] scrapViews = this.scrapViews;
        for (int i = 0; i < viewTypeCount; ++i) {
final SparseArray<View> scrapPile = scrapViews[i];
            int size = scrapPile.size();
            final int extras = size - maxViews;
size--;
            for (int j = 0; j < extras; j++) {
                scrapPile.remove(scrapPile.keyAt(size--));
}
        }
    }

static View retrieveFromScrap(SparseArray<View> scrapViews, int position) {
int size = scrapViews.size();
        if (size > 0) {
for (int i = 0; i < size; i++) {
int fromPosition = scrapViews.keyAt(i);
View view = scrapViews.get(fromPosition);
                if (fromPosition == position) {
                    scrapViews.remove(fromPosition);
                    return view;
}
            }
int index = size - 1;
View r = scrapViews.valueAt(index);
scrapViews.remove(scrapViews.keyAt(index));
            return r;
} else {
return null;
}
    }
}

CustomDurationScoller:

public class CustomDurationScroller extends Scroller {

private double scrollFactor =2;

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

public CustomDurationScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}


public void setScrollDurationFactor(double scrollFactor) {
this.scrollFactor = scrollFactor;
}

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

RecyclingPagerAdapter:

public abstract class RecyclingPagerAdapter extends PagerAdapter {
static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE;

    private final RecycleBin recycleBin;

    public RecyclingPagerAdapter() {
this(new RecycleBin());
}

    RecyclingPagerAdapter(RecycleBin recycleBin) {
this.recycleBin = recycleBin;
recycleBin.setViewTypeCount(getViewTypeCount());
}

@Override
public void notifyDataSetChanged() {
recycleBin.scrapActiveViews();
        super.notifyDataSetChanged();
}

@Override
public final Object instantiateItem(ViewGroup container, int position) {
int viewType = getItemViewType(position);
View view = null;
        if (viewType != IGNORE_ITEM_VIEW_TYPE) {
            view = recycleBin.getScrapView(position, viewType);
}
        view = getView(position, view, container);
container.addView(view);
        return view;
}

@Override
public final void destroyItem(ViewGroup container, int position, Object object) {
        View view = (View) object;
container.removeView(view);
        int viewType = getItemViewType(position);
        if (viewType != IGNORE_ITEM_VIEW_TYPE) {
recycleBin.addScrapView(view, position, viewType);
}
    }

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


public int getViewTypeCount() {
return 1;
}


public int getItemViewType(int position) {
return 0;
}

public abstract View getView(int position, View convertView, ViewGroup container);
}

ImagePagerApater:

public abstract class ImagePagerAdapter<T> extends RecyclingPagerAdapter {

private Context context;
    private List<T> listDatas;

    private int size;
    private boolean isInfiniteLoop;//是否开启无限循环

public ImagePagerAdapter(Context context, List<T> listDatas) {
this.context = context;
        this.listDatas = listDatas;
        this.size = ListUtil.getCount(listDatas);
//大于1时,启动轮播
isInfiniteLoop = !(ListUtil.isNotEmpty(listDatas) && listDatas.size() == 1);
}

/**
     * @param isInfiniteLoop 是否开启无限循环  默认>1时开启
     */
public ImagePagerAdapter(Context context, List<T> listDatas, boolean isInfiniteLoop) {
this.context = context;
        this.listDatas = listDatas;
        this.size = ListUtil.getCount(listDatas);
        this.isInfiniteLoop = isInfiniteLoop;
}

@Override
public int getCount() {
return isInfiniteLoop ? Integer.MAX_VALUE : ListUtil.getCount(listDatas);
}

private int getPosition(int position) {
return isInfiniteLoop ? position % size : position;
}

@Override
public View getView(int position, View view, ViewGroup container) {
        ViewHolder holder;
        if (view == null) {
            holder = new ViewHolder();
view = holder.imageView = new ImageView(context);
holder.imageView.setScaleType(ImageView.ScaleType.FIT_XY);
view.setTag(holder);
} else {
            holder = (ViewHolder) view.getTag();
}
        setImageView(holder.imageView, listDatas.get(getPosition(position)));
        return view;
}

public abstract void setImageView(ImageView imageView, T t);

    private static class ViewHolder {
        ImageView imageView;
}

public Context getContext() {
return context;
}

public void setContext(Context context) {
this.context = context;
}
}

AutoScrollViewPager:

public class AutoScrollViewPager extends ViewPager {

public static final int DEFAULT_INTERVAL = 4000;//默认的时间间隔

public static final int LEFT = 0;
    public static final int RIGHT = 1;

    public static final int SLIDE_BORDER_MODE_NONE = 0;

    public static final int SLIDE_BORDER_MODE_CYCLE = 1;

    public static final int SLIDE_BORDER_MODE_TO_PARENT = 2;


    private long interval = DEFAULT_INTERVAL;

    private int direction = RIGHT;

    private boolean isCycle = true;

    private boolean stopScrollWhenTouch = true;

    private int slideBorderMode = SLIDE_BORDER_MODE_NONE;

    private boolean isBorderAnimation = true;

    private Handler handler;
    private boolean isAutoScroll = true;
    private boolean isStopByTouch = false;
    private float touchX = 0f, downX = 0f;
    private CustomDurationScroller scroller = null;

    public static final int SCROLL_WHAT = 0;

    public AutoScrollViewPager(Context paramContext) {
super(paramContext);
init();
}

public AutoScrollViewPager(Context paramContext, AttributeSet paramAttributeSet) {
super(paramContext, paramAttributeSet);
init();
}

private void init() {
handler = new MyHandler();
setViewPagerScroller();
}


public void startAutoScroll() {
isAutoScroll = true;
sendScrollMessage(interval);
}


public void startAutoScroll(int delayTimeInMills) {
isAutoScroll = true;
sendScrollMessage(delayTimeInMills);
}


public void stopAutoScroll() {
isAutoScroll = false;
handler.removeMessages(SCROLL_WHAT);
}


public void setScrollDurationFactor(double scrollFactor) {
scroller.setScrollDurationFactor(scrollFactor);
}

private void sendScrollMessage(long delayTimeInMills) {
handler.removeMessages(SCROLL_WHAT);
handler.sendEmptyMessageDelayed(SCROLL_WHAT, delayTimeInMills);
}


private void setViewPagerScroller() {
try {
            Field scrollerField = ViewPager.class.getDeclaredField("mScroller");
scrollerField.setAccessible(true);
Field interpolatorField = ViewPager.class.getDeclaredField("sInterpolator");
interpolatorField.setAccessible(true);

scroller = new CustomDurationScroller(getContext(), (Interpolator) interpolatorField.get(null));
scrollerField.set(this, scroller);
} catch (Exception e) {
            e.printStackTrace();
}
    }


public void scrollOnce() {
        PagerAdapter adapter = getAdapter();
        int currentItem = getCurrentItem();
        int totalCount;
        if (adapter == null || (totalCount = adapter.getCount()) <= 1) {
return;
}

int nextItem = (direction == LEFT) ? --currentItem : ++currentItem;
        if (nextItem < 0) {
if (isCycle) {
                setCurrentItem(totalCount - 1, isBorderAnimation);
}
        } else if (nextItem == totalCount) {
if (isCycle) {
                setCurrentItem(0, isBorderAnimation);
}
        } else {
            setCurrentItem(nextItem, true);
}
    }


@Override
public boolean onTouchEvent(MotionEvent ev) {
if (stopScrollWhenTouch) {
if (ev.getAction() == MotionEvent.ACTION_DOWN && isAutoScroll) {
isStopByTouch = true;
stopAutoScroll();
} else if (ev.getAction() == MotionEvent.ACTION_UP && isStopByTouch) {
                startAutoScroll();
}
        }

if (slideBorderMode == SLIDE_BORDER_MODE_TO_PARENT || slideBorderMode == SLIDE_BORDER_MODE_CYCLE) {
touchX = ev.getX();
            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
downX = touchX;
}
int currentItem = getCurrentItem();
PagerAdapter adapter = getAdapter();
            int pageCount = adapter == null ? 0 : adapter.getCount();

            if ((currentItem == 0 && downX <= touchX) || (currentItem == pageCount - 1 && downX >= touchX)) {
if (slideBorderMode == SLIDE_BORDER_MODE_TO_PARENT) {
                    getParent().requestDisallowInterceptTouchEvent(false);
} else {
if (pageCount > 1) {
                        setCurrentItem(pageCount - currentItem - 1, isBorderAnimation);
}
                    getParent().requestDisallowInterceptTouchEvent(true);
}
return super.onTouchEvent(ev);
}
        }
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.onTouchEvent(ev);
}

public class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
            switch (msg.what) {
case SCROLL_WHAT:
                    scrollOnce();
sendScrollMessage(interval);
                    break;
                default:
break;
}
        }
    }


public long getInterval() {
return interval;
}


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


public int getDirection() {
return (direction == LEFT) ? LEFT : RIGHT;
}


public void setDirection(int direction) {
this.direction = direction;
}


public boolean isCycle() {
return isCycle;
}


public void setCycle(boolean isCycle) {
this.isCycle = isCycle;
}


public boolean isStopScrollWhenTouch() {
return stopScrollWhenTouch;
}


public void setStopScrollWhenTouch(boolean stopScrollWhenTouch) {
this.stopScrollWhenTouch = stopScrollWhenTouch;
}


public int getSlideBorderMode() {
return slideBorderMode;
}


public void setSlideBorderMode(int slideBorderMode) {
this.slideBorderMode = slideBorderMode;
}


public boolean isBorderAnimation() {
return isBorderAnimation;
}

public void setBorderAnimation(boolean isBorderAnimation) {
this.isBorderAnimation = isBorderAnimation;
}

private LinearLayout container;//点的父布局
private LinearLayout.LayoutParams paramsSmall;//小点属性
private List<View> points;//点集合
private int size;// 实际item个数
private int pointNormal;//没有选中的点drawable
private int pointSelect;//选中的点drawable


public void setOnPointIndex(int size, LinearLayout container, int pointNormal, int pointSelect) {
this.size = size;
        this.container = container;
        this.pointNormal = pointNormal;
        this.pointSelect = pointSelect;
//大于1,才显示point 进行轮播
if (this.container == null) {
            stopAutoScroll();
            return;
}
if (this.size <= 1) {
            stopAutoScroll();
            this.container.setVisibility(GONE);
            return;
}
points = new ArrayList<>();
paramsSmall = new LinearLayout.LayoutParams(20, 20);
paramsSmall.setMargins(10, 10, 10, 10);
setPoint();
addOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }

@Override
public void onPageSelected(int position) {
                initPointColor(getCurrentItem());
}

@Override
public void onPageScrollStateChanged(int state) {
            }
        });
}

public void setOnPointIndex(int size, LinearLayout container) {
        setOnPointIndex(size, container, R.mipmap.ic_point_pre_3x, R.mipmap.ic_point_3x);
}


private void setPoint() {
container.removeAllViews();
points.clear();
        for (int i = 0; i < size; i++) {
            View view = new View(getContext());//点
view.setLayoutParams(paramsSmall);
container.addView(view);
points.add(view);
}
        initPointColor(0);
}

//初始化底部指示点颜色
public void initPointColor(int index) {
for (int i = 0; i < size; i++) {
points.get(i).setBackgroundResource(pointNormal);
points.get(i).setLayoutParams(paramsSmall);
}
points.get(index % size).setBackgroundResource(pointSelect);
points.get(index % size).setLayoutParams(paramsSmall);
}
}

ListUtil:工具类:

/**
 * List工具类
 */
public class ListUtil {
/**
     * 判断集合list数据是否为空
     */
public static boolean isEmpty(List<?> list) {
if (list == null || list.size() == 0)
return true;
        return false;
}

/**
     * 判断集合list数据是否为非空
     */
public static <T> boolean isNotEmpty(List<T> list) {
return !isEmpty(list);
}

/**
     * 清空集合
     */
public static void clearList(List<?> list) {
if (!isEmpty(list)) {
            list.clear();
}
    }

/**
     * 获取集合list数据长度
     */
public static <T> int getCount(List<T> list) {
return list == null ? 0 : list.size();
}
}

三:实现:
1–:并没有使用线程池或者定时器定时执行任务状态,而是通过Handler发送消息来完成滚动,在完成滚动之后,再发送一个消息delay:

public class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case SCROLL_WHAT:
                scrollOnce();
                sendScrollMessage(interval);
                break;
            default:
                break;
        }
    }
}

public void scrollOnce() {
    PagerAdapter adapter = getAdapter();
    int currentItem = getCurrentItem();
    int totalCount;
    if (adapter == null || (totalCount = adapter.getCount()) <= 1) {
        return;
    }

    int nextItem = (direction == LEFT) ? --currentItem : ++currentItem;
    if (nextItem < 0) {
        if (isCycle) {
            setCurrentItem(totalCount - 1, isBorderAnimation);
        }
    } else if (nextItem == totalCount) {
        if (isCycle) {
            setCurrentItem(0, isBorderAnimation);
        }
    } else {
        setCurrentItem(nextItem, true);
    }
}

private void sendScrollMessage(long delayTimeInMills) {
    handler.removeMessages(SCROLL_WHAT);
    handler.sendEmptyMessageDelayed(SCROLL_WHAT, delayTimeInMills);
}

public void startAutoScroll(int delayTimeInMills) {
    isAutoScroll = true;
    sendScrollMessage(delayTimeInMills);
}

2–:对于ViewPager嵌套导致子ViewPager无法触摸问题通过在子ViewPager中:

getParent().requestDisallowInterceptTouchEvent(true);

禁止父控件对TouchEvent控制的。

3–:ViewPager的滑动是通过反射方式重新设置Scroller,改变startScroll的间隔时间完成的。
调用如下方法可以完成设置:

public void setScrollDurationFactor(double scrollFactor) {
    scroller.setScrollDurationFactor(scrollFactor);
}

四:设置

setInterval(long) 设置自动滚动的间隔时间,单位为毫秒
setDirection(int) 设置自动滚动的方向,默认向右
setCycle(boolean) 是否自动循环轮播,默认为true
setScrollDurationFactor(double) 设置ViewPager滑动动画间隔时间的倍率,达到减慢动画或改变动画速度的效果
setStopScrollWhenTouch(boolean) 当手指碰到ViewPager时是否停止自动滚动,默认为true
setSlideBorderMode(int) 滑动到第一个或最后一个Item的处理方式,支持没有任何操作、轮播以及传递到父View三种模式
setBorderAnimation(boolean) 设置循环滚动时滑动到从边缘滚动到下一个是否需要动画,默认为true
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值