自定义的广告轮播---(二)(无限循环)

准备工作

  • 自定义的水平滚动类
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));
        // sendScrollMessage((long) (interval + scroller.getDuration()/
        // autoScrollFactor * swipeScrollFactor));
    }

    /**
     * 开始自动滚动
     */
    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);
                    // sendScrollMessage(interval + scroller.getDuration());
                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送数据
        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;
    }
}
  • 适配器的辅助类–1
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") // Argument potentially used by subclasses.
    public int getItemViewType(int position) {
        return 0;
    }


    public abstract View getView(int position, View convertView, ViewGroup container);
}
  • 适配器的辅助类–2
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");
        }
        //noinspection unchecked
        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) {
            // See if we still have a view for this position.
            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;
        }
    }
}

到这里就基本完成了,欢迎查看,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值