准备工作
package widget;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
import java.lang.reflect.Field;
/**
* 自动滚动视图
* startAutoScroll() 开始自动滚动
* startAutoScroll(int) 开始自动滚动延迟
* stopAutoScroll() 停止自动滚动
* setInterval(long) 设置自动滚动时间以毫秒为单位, 默认DEFAULT_INTERVAL
* setDirection(int) 设置滚动方向
* setCycle(boolean) 设置是否自动循环时自动滚动到达最后一个或第一项,默认是真的
* setSlideBorderMode(int) 设置滑动时如何处理最后或第一项
* setStopScrollWhenTouch(boolean) 设置是否停止自动滚动--触摸时,默认是true
*/
public class AutoScrollViewPager extends ViewPager {
public static final int DEFAULT_INTERVAL = 1500;
public static final int LEFT = 0;
public static final int RIGHT = 1;
/**
* 当滑动在最后还是第一项
**/
public static final int SLIDE_BORDER_MODE_NONE = 0;
/**
* ycle当滑动在最后或第一项
**/
public static final int SLIDE_BORDER_MODE_CYCLE = 1;
/**
* 提供事件父当滑动在最后或第一项
**/
public static final int SLIDE_BORDER_MODE_TO_PARENT = 2;
/**
* 自动滚动时间以毫秒为单位,默认是{ DEFAULT_INTERVAL }
**/
private long interval = DEFAULT_INTERVAL;
/**
* 自动滚动的方向,默认是{ RIGHT}
**/
private int direction = RIGHT;
/**
* 是否自动循环自动滚动到最后一个或第一项时,
* default is true
**/
private boolean isCycle = true;
/**
* 是否停止自动滚动接触时, default is true
**/
private boolean stopScrollWhenTouch = true;
/**
* 如何处理当滑动在最后或第一项,默认 SLIDE_BORDER_MODE_NONE}
**/
private int slideBorderMode = SLIDE_BORDER_MODE_NONE;
/**
* 动画时是否自动滚动在最后或第一项
**/
private boolean isBorderAnimation = true;
/**
* 滚动因素 自动滚动动画,默认是1.0
**/
private double autoScrollFactor = 1.0;
/**
* 滚动因素 滑动滚动动画,默认是1.0
**/
private double swipeScrollFactor = 1.0;
private Handler handler;
private boolean isAutoScroll = false;
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();
}
/**
* 开始自动滚动,滚动延迟时间是{ getInterval()}
*/
public void startAutoScroll() {
isAutoScroll = true;
sendScrollMessage((long) (interval));
}
/**
* 开始自动滚动
*/
public void startAutoScroll(int delayTimeInMills) {
isAutoScroll = true;
sendScrollMessage(delayTimeInMills);
}
/**
* 停止自动滚动
*/
public void stopAutoScroll() {
isAutoScroll = false;
handler.removeMessages(SCROLL_WHAT);
}
/**
* 设置滑动动画的持续时间的因素会改变
*/
public void setSwipeScrollDurationFactor(double scrollFactor) {
swipeScrollFactor = scrollFactor;
}
/**
* 设置滑动动画的持续时间的因素会改变而自动滚动
*/
public void setAutoScrollDurationFactor(double scrollFactor) {
autoScrollFactor = scrollFactor;
}
private void sendScrollMessage(long delayTimeInMills) {
/**删除消息之前,保留一份消息正在运行 **/
handler.removeMessages(SCROLL_WHAT);
handler.sendEmptyMessageDelayed(SCROLL_WHAT, delayTimeInMills);
}
/**
* 当滑动时:viewpage照片卷轴改变动画持续时间
*/
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);
}
}
/**
* 如果stopScrollWhenTouch是真的
* 如果事件 down,停止自动滚动
* 如果事件 up, 重新开始自动滚动
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = MotionEventCompat.getActionMasked(ev);
if (stopScrollWhenTouch) {
if ((action == 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();
/**
* 当前指数第一次 和 幻灯片或当前指数最后一个 和 滑到左。
* 如果滑动边界模式是父控件,然后requestDisallowInterceptTouchEvent假。
* 其他滚动到最后一个时,当前的项目是第一个,滚动第一个当当前项目是最后一个。
*/
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.dispatchTouchEvent(ev);
}
}
getParent().requestDisallowInterceptTouchEvent(true);
return super.dispatchTouchEvent(ev);
}
private class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SCROLL_WHAT:
scroller.setScrollDurationFactor(autoScrollFactor);
scrollOnce();
scroller.setScrollDurationFactor(swipeScrollFactor);
sendScrollMessage(interval);
default:
break;
}
}
}
/**
* 得到滚动时间以毫秒为单位,默认{ DEFAULT_INTERVAL}
*/
public long getInterval() {
return interval;
}
/**
* 设置滚动时间以毫秒为单位{ DEFAULT_INTERVAL}
*/
public void setInterval(long interval) {
this.interval = interval;
}
/**
* 得到滚动方向default is {@link #RIGHT}
*/
public int getDirection() {
return (direction == LEFT) ? LEFT : RIGHT;
}
/**
* 设置自动滚动方向 default is {@link #RIGHT}
*/
public void setDirection(int direction) {
this.direction = direction;
}
/**
* 是否自动循环自动滚动到最后一个或第一项时,默认是 true
*/
public boolean isCycle() {
return isCycle;
}
/**
* 设置是否自动循环时自动滚动到最后还是第一次项,默认是 true
*/
public void setCycle(boolean isCycle) {
this.isCycle = isCycle;
}
/**
* 是否停止自动滚动接触时,默认的是 true
*/
public boolean isStopScrollWhenTouch() {
return stopScrollWhenTouch;
}
/**
* 设置是否停止自动滚动接触时,默认 true
*/
public void setStopScrollWhenTouch(boolean stopScrollWhenTouch) {
this.stopScrollWhenTouch = stopScrollWhenTouch;
}
/**
* 得到滑动在最后或第一项
*
* @return the slideBorderMode {@link #SLIDE_BORDER_MODE_NONE},
* {@link #SLIDE_BORDER_MODE_TO_PARENT},
* {@link #SLIDE_BORDER_MODE_CYCLE}, default is
* {@link #SLIDE_BORDER_MODE_NONE}
*/
public int getSlideBorderMode() {
return slideBorderMode;
}
/**
* 设置滑动在最后或第一项
*
* @param slideBorderMode {@link #SLIDE_BORDER_MODE_NONE},
* {@link #SLIDE_BORDER_MODE_TO_PARENT},
* {@link #SLIDE_BORDER_MODE_CYCLE}, default is
* {@link #SLIDE_BORDER_MODE_NONE}
*/
public void setSlideBorderMode(int slideBorderMode) {
this.slideBorderMode = slideBorderMode;
}
/**
* 动画是否自动滚动在最后或第一项时,默认的是 true
*/
public boolean isBorderAnimation() {
return isBorderAnimation;
}
/**
* 设置动画是否自动滚动在最后或第一项时,默认的是true
*/
public void setBorderAnimation(boolean isBorderAnimation) {
this.isBorderAnimation = isBorderAnimation;
}
}
package widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.animation.Interpolator;
import android.widget.Scroller;
public class CustomDurationScroller extends Scroller {
private double scrollFactor = 1;
public CustomDurationScroller(Context context) {
super(context);
}
public CustomDurationScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
/**
* not exist in android 2.3
*
* @param context
* @param interpolator
* @param flywheel
*/
@SuppressLint("NewApi")
public CustomDurationScroller(Context context, Interpolator interpolator, boolean flywheel){
super(context, interpolator, flywheel);
}
/**
* 设置因素的持续时间将会改变
*/
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));
}
}
主程序的布局
<?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.example.administrator.viewpagercarousel.MainActivity">
<widget.AutoScrollViewPager
android:id="@+id/view_pager"
android:layout_width="fill_parent"
android:layout_height="150dip"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/view_pager"
android:layout_gravity="bottom"
android:background="@color/back"
android:gravity="center"
android:orientation="vertical"
android:padding="5dip">
<TextView
android:id="@+id/view_pager_index"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/view_pager"
android:layout_centerHorizontal="true"
android:text="1/4"
android:textColor="@color/colorAccent"
android:textSize="14sp"/>
</LinearLayout>
</RelativeLayout>
主程序代码实现
package com.example.administrator.viewpagercarousel;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.widget.TextView;
import java.util.ArrayList;
import adapter.ImageAdapter;
import widget.AutoScrollViewPager;
public class MainActivity extends Activity {
private AutoScrollViewPager viewPager;
private TextView indexText;
private ArrayList<Integer> imageList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViewpager();
}
private void initViewpager() {
viewPager = (AutoScrollViewPager) findViewById(R.id.view_pager);
indexText = (TextView) findViewById(R.id.view_pager_index);
imageList = new ArrayList<Integer>();
imageList.add(R.mipmap.b);
imageList.add(R.mipmap.c);
imageList.add(R.mipmap.d);
imageList.add(R.mipmap.e);
viewPager.setAdapter(new ImageAdapter(this, imageList).setInfiniteLoop(true));
viewPager.setInterval(2000);
viewPager.startAutoScroll();
viewPager.setCurrentItem(Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2
% imageList.size());
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
indexText.setText(new StringBuilder()
.append((position) % imageList.size() + 1).append("/")
.append(imageList.size()));
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
}
所需要的适配器
package adapter;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.example.administrator.viewpagercarousel.R;
import com.example.administrator.viewpagercarousel.StepActivity;
import java.util.List;
import butterknife.InjectView;
/**
* 适配图片
*/
public class ImageAdapter extends RecyclingPagerAdapter {
@InjectView(R.id.image)
ImageView mImage;
private Context context;
private List<Integer> imageIdList;
private boolean isInfiniteLoop;
public ImageAdapter(Context context, List<Integer> imageIdList) {
this.context = context;
this.imageIdList = imageIdList;
isInfiniteLoop = false;
}
public ImageAdapter(RecycleBin recycleBin, Context context, List<Integer> imageIdList) {
super(recycleBin);
this.context = context;
this.imageIdList = imageIdList;
}
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
/**
* 得到真正的position
*/
private int getPosition(int position) {
return isInfiniteLoop ? position % imageIdList.size() : position;
}
@Override
public View getView(final int position, View convertView, ViewGroup container) {
Viewhodler h = null;
if (convertView == null) {
h = new Viewhodler();
convertView = View.inflate(context, R.layout.item_image, null);
h.images = (ImageView) convertView.findViewById(R.id.image);
convertView.setTag(h);
} else {
h = (Viewhodler) convertView.getTag();
}
h.images.setImageResource(imageIdList.get(getPosition(position)));
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(context, StepActivity.class);
intent.putExtra("image_id", imageIdList.get(getPosition(position)));
context.startActivity(intent);
}
});
return convertView;
}
class Viewhodler {
private ImageView images;
}
public boolean isInfiniteLoop() {
return isInfiniteLoop;
}
public ImageAdapter setInfiniteLoop(boolean isInfiniteLoop) {
this.isInfiniteLoop = isInfiniteLoop;
return this;
}
}
package adapter;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
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;
}
@SuppressWarnings("UnusedParameters")
public int getItemViewType(int position) {
return 0;
}
public abstract View getView(int position, View convertView, ViewGroup container);
}
package adapter;
import android.os.Build;
import android.util.SparseArray;
import android.view.View;
/**
* RecycleBin促进重用视图的布局。RecycleBin两个级别的
* 存储:ActiveViews ScrapViews。ActiveViews这些视图在屏幕上开始布局。通过建设,他们是显示当前信息。
* 结束的时候布局,所有视图在ActiveViews ScrapViews降级。
* ScrapViews旧观点可能使用的适配器,以避免不必要的分配意见。
*/
public class RecycleBin {
/**
* 视图在屏幕的布局。这个数组填充的
* 布局,布局activeViews所有的视图都是年底搬到scrapViews。
* 意见activeViews代表一个连续的一系列观点,第一的位置
* 在mFirstActivePosition查看商店。
*/
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;
}
/**
* 一个视图从ScrapViews集合。这些都是无序的。
*/
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;
}
/**
* 把一个视图ScrapViews列表。这些观点是无序的。
*/
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);
}
}
/**
*剩余所有视图在activeViews scrapViews移动。
*/
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();
}
/**
* 确保scrapViews的大小不超过activeViews的大小。
*(这可能发生,如果一个适配器不回收其观点)。
*/
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;
}
}
}
到这里就基本完成了,欢迎查看,谢谢。