经常我们会在应用中看到一个可以自动滚动,并且无限滚动的一个ViewPager,百度谷歌上面也有很多关于这方面的教程,但是感觉都略显麻烦,而且封装的都不是很彻底。所以试着封装一个比较好用的ViewPager

效果如下:

android 自动上划 安卓自动滑动_ide

简单的说一下实现思路,要实现无限滚动的话就要在PagerAdapter上面做一些手脚,在PagerAdapter的getCount的函数的返回值设置成Integer.MXA_VALUE就可以实现向右无限滚动,但是要实现向左无限滚动呢?就是一开始的时候setCurrentItem的时候设置一个非常大的值(大到你向左滚动了一万年还是有东西)

@Override
        public int getCount() {
            return Integer.MAX_VALUE;
        }


mPager.setCurrentItem(10000 * mDatas.size());//一开始设置成这样的话就可以向左无限滚动了


然后另外一个就是底部的游标了:

android 自动上划 安卓自动滑动_无限滚动_02

底部的游标是用一个自定义视图:无非就是画一个背景,然后在画一个高亮的游标

/**
     * 指示游标
     */
    private class TipView extends View {

        private int mPadding;
        private int mCount;
        private int mCurPos;
        private Paint mNorPaint;//未被选中的颜色
        private Paint mSelPaint;//被选中的颜色 白色
        private int mHeight;

        public TipView(Context context, int count) {
            super(context);
            mNorPaint = new Paint();
            mNorPaint.setAntiAlias(true);
            int selHeight = ShowUtils.dip2px(2);
            int norHeight =  ShowUtils.dip2px(1);
            mHeight =  ShowUtils.dip2px(2);
            mNorPaint.setStrokeWidth(norHeight);
            mNorPaint.setColor(Color.argb(80, 255, 255, 255));
            mSelPaint = new Paint();
            mSelPaint.setAntiAlias(true);
            mSelPaint.setStrokeWidth(selHeight);
            mSelPaint.setColor(Color.WHITE);
            mCount = count;
            mPadding =  ShowUtils.dip2px(0);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            int ow = (getWidth()-2 * mPadding)/ mCount;
            int y = getHeight() / 2;
            canvas.drawLine(mPadding, y, mCurPos * ow + mPadding, y, mNorPaint);
            canvas.drawLine(mCurPos * ow + mPadding, y, (mCurPos + 1) * ow + mPadding, y, mSelPaint);
            canvas.drawLine((mCurPos + 1) * ow + mPadding, y, getWidth() - mPadding, y, mNorPaint);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            ViewGroup.LayoutParams vp = getLayoutParams();
            vp.width = ViewGroup.LayoutParams.MATCH_PARENT;
            vp.height = mHeight;
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }

        public void setCurPostion(int pos) {
            mCurPos = pos;
            invalidate();
        }

        public void setCount(int count) {
            mCount = count;
        }
    }


R.layout.layout_recommend_item的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/iv_pic"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:contentDescription="@null"
        android:scaleType="fitXY"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:orientation="vertical"
        android:layout_alignParentBottom="true"
        android:background="@drawable/recommend"
        android:gravity="center">
        <TextView
            android:id="@+id/tv_desc"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="@color/white"
            android:textSize="@dimen/text_normal"
            android:maxLines="1"
            android:ellipsize="end"
            android:shadowColor="#ff333333"
            android:shadowDx="2"
            android:shadowDy="2"
            android:paddingRight="8dp"
            android:paddingLeft="8dp"
            android:shadowRadius="1" />
    </LinearLayout>
</RelativeLayout>

还有一个是实现自动滚动,自动滚动的话就是监听OnPagerChangeListener里面的函数,在ViewPager状态改变的时候利用Handler发送一个切换界面的消息:

@Override
        public void onPageScrollStateChanged(int i) {
            curState = i;
            if(i == ViewPager.SCROLL_STATE_DRAGGING){   //viewpager正在被拖动的时候
                stopAnimation();
            }else { //没有可执行消息时候添加消息 实现自动滚动
                if(!(sHandler.hasMessages(START_SCROLL)&&sHandler.hasMessages(SCROLL_NEXT))){
                    startAnimation();
                }
            }
        }

        @Override
        public void onPageSelected(final int i) {   //页面跳转后得到调用
            sHandler.removeMessages(SCROLL_NEXT);
            sHandler.removeMessages(START_SCROLL);
            if(curState == ViewPager.SCROLL_STATE_DRAGGING){
                return;
            }
            Message msg = sHandler.obtainMessage(SCROLL_NEXT);
            msg.arg1 = i + 1;
            msg.obj = mPager;
            sHandler.sendMessageDelayed(msg, SHOW_TIME);
            mTipView.setCurPostion(i % mDatas.size());
        }



整体的代码:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.papau.show.R;
import com.papau.show.entity.HeadViewEntity;
import com.papau.show.utils.ShowUtils;
import java.util.ArrayList;
import java.util.List;

public class RecommendView extends RelativeLayout implements IRecommend {

    private static final int START_SCROLL = 1;
    private static final int SCROLL_NEXT = 2;
    private static final int SHOW_TIME = 5000;

    private List<HeadViewEntity> mDatas = new ArrayList<>();
    private ViewPager mPager;
    private Context mContext;
    private int mWidth, mHeight;
    private ImageLoader mLoader;
    private DisplayImageOptions mOptions;
    private int mTitleHeight;
    private TipView mTipView;

    private static Handler sHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            int w = msg.what;
            ViewPager pager = (ViewPager) msg.obj;
            switch (w) {
                case START_SCROLL:
                    pager.setCurrentItem(msg.arg1, true);
                    break;
                case SCROLL_NEXT:
                    pager.setCurrentItem(msg.arg1, true);
                    break;
            }
        }
    };

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

    public RecommendView(Context context, int w, int h) {
        super(context);
        mContext = context;
        mWidth = w;
        mHeight = h;
        initView();
//        mPager.setAdapter(new RecommendAdapter());
        mPager.setOnPageChangeListener(new MOnPagerChangeListener());
        mLoader = ImageLoaderManager.getImageLoader(mContext);
        mOptions = ImageLoaderManager.getCacheOnDiskOptions(mContext);
        init();
//        DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
        mTitleHeight = ShowUtils.dip2px(48);//设置游标高度
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        ViewGroup.LayoutParams vp = getLayoutParams();
        if (vp != null) {   //设置视图的宽高
            vp.width = mWidth;
            vp.height = mHeight;
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private void initView() {
        mPager = new ViewPager(mContext);
        RelativeLayout.LayoutParams rp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
        addView(mPager, rp);
    }

    /**
     * 初始化指示游标
     */
    private void initTipView() {
        if (mTipView == null) {
            RelativeLayout.LayoutParams rp = new RelativeLayout.LayoutParams(10, 10);
            rp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);//显示在父控件的底部
            rp.bottomMargin = mTitleHeight;//游标的高度
            mTipView = new TipView(mContext, mDatas.size());
            addView(mTipView, rp);
        } else {
            mTipView.setCount(mDatas.size());
        }
    }

    @Override
    public void upDate() {
        getData();
    }

    @Override
    public void init() {
        getData();
    }

    @Override
    public void startAnimation() {
        if (mDatas.size() == 0) {
            return;
        }
        Message msg = sHandler.obtainMessage(START_SCROLL);
        msg.obj = mPager;
        msg.arg1 = (mPager.getCurrentItem() + 1);
        sHandler.sendMessageDelayed(msg, SHOW_TIME);
    }

    @Override
    public void stopAnimation() {
        sHandler.removeMessages(START_SCROLL);
        sHandler.removeMessages(SCROLL_NEXT);
    }

    /**
     * 获取viewpager要显示的数据
     */
    private void getData() {
        String[] imageData = new String[]{"http://f.hiphotos.baidu.com/image/h%3D360/sign=e105b9f1d61b0ef473e89e58edc651a1/b151f8198618367a9f738e022a738bd4b21ce573.jpg",
                "http://c.hiphotos.baidu.com/image/h%3D360/sign=b8cea9e92b738bd4db21b437918b876c/f7246b600c3387448982f948540fd9f9d72aa0bb.jpg",
                "http://a.hiphotos.baidu.com/image/h%3D360/sign=3da95d01e7dde711f8d245f097eecef4/71cf3bc79f3df8dc39cb6295cf11728b461028c4.jpg",
                "http://d.hiphotos.baidu.com/image/h%3D360/sign=410c3c96a60f4bfb93d09852334f788f/10dfa9ec8a136327a1de913a938fa0ec08fac78c.jpg",
                "http://e.hiphotos.baidu.com/image/h%3D360/sign=f6600b1613dfa9ece22e501152d1f754/342ac65c10385343ff41ee2b9113b07eca808829.jpg"};
        for (int i = 0; i < 5; i++) {
            HeadViewEntity info = new HeadViewEntity();
            info.setImageUrl(imageData[i]);
            info.setTitle("我不做大哥好多年"+i);
            info.setUrl("www.baidu.com");
            mDatas.add(info);
        }
        sHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                stopAnimation();
                initTipView();
                mPager.setAdapter(new RecommendAdapter());
                mPager.setCurrentItem(10000 * mDatas.size());//一开始设置成这样的话就可以向左无限滚动了
            }
        },2000);
    }

    /**
     * viewpager子项内容
     */
    private class RecommendAdapter extends PagerAdapter {

        /**
         * 填充子项视图的内容
         * @param container 父控件 viewpager
         * @param position 子项的位置
         * @return 返回子项视图
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            int curPos = position % mDatas.size();
            View view = View.inflate(mContext, R.layout.layout_recommend_item, null);
            ViewGroup.LayoutParams vp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            ImageView iv = (ImageView) view.findViewById(R.id.iv_pic);
            TextView tv = (TextView) view.findViewById(R.id.tv_desc);
            tv.setText(mDatas.get(curPos).getTitle());
            mLoader.displayImage(mDatas.get(curPos).getImageUrl(), iv, mOptions);
            container.addView(view, vp);
            view.setTag(curPos);
            view.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                }
            });
            return view;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }

        @Override
        public int getCount() {
            return Integer.MAX_VALUE;
        }

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

    private class MOnPagerChangeListener implements ViewPager.OnPageChangeListener {
        private int curState;
        @Override
        public void onPageScrolled(int i, float v, int i1) {

        }

        @Override
        public void onPageScrollStateChanged(int i) {
            curState = i;
            if(i == ViewPager.SCROLL_STATE_DRAGGING){   //viewpager正在被拖动的时候
                stopAnimation();
            }else { //没有可执行消息时候添加消息 实现自动滚动
                if(!(sHandler.hasMessages(START_SCROLL)&&sHandler.hasMessages(SCROLL_NEXT))){
                    startAnimation();
                }
            }
        }

        @Override
        public void onPageSelected(final int i) {   //页面跳转后得到调用
            sHandler.removeMessages(SCROLL_NEXT);
            sHandler.removeMessages(START_SCROLL);
            if(curState == ViewPager.SCROLL_STATE_DRAGGING){
                return;
            }
            Message msg = sHandler.obtainMessage(SCROLL_NEXT);
            msg.arg1 = i + 1;
            msg.obj = mPager;
            sHandler.sendMessageDelayed(msg, SHOW_TIME);
            mTipView.setCurPostion(i % mDatas.size());
        }
    }

    /**
     * 指示游标
     */
    private class TipView extends View {

        private int mPadding;
        private int mCount;
        private int mCurPos;
        private Paint mNorPaint;//未被选中的颜色
        private Paint mSelPaint;//被选中的颜色 白色
        private int mHeight;

        public TipView(Context context, int count) {
            super(context);
            mNorPaint = new Paint();
            mNorPaint.setAntiAlias(true);
            int selHeight = ShowUtils.dip2px(2);
            int norHeight =  ShowUtils.dip2px(1);
            mHeight =  ShowUtils.dip2px(2);
            mNorPaint.setStrokeWidth(norHeight);
            mNorPaint.setColor(Color.argb(80, 255, 255, 255));
            mSelPaint = new Paint();
            mSelPaint.setAntiAlias(true);
            mSelPaint.setStrokeWidth(selHeight);
            mSelPaint.setColor(Color.WHITE);
            mCount = count;
            mPadding =  ShowUtils.dip2px(0);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            int ow = (getWidth()-2 * mPadding)/ mCount;
            int y = getHeight() / 2;
            canvas.drawLine(mPadding, y, mCurPos * ow + mPadding, y, mNorPaint);
            canvas.drawLine(mCurPos * ow + mPadding, y, (mCurPos + 1) * ow + mPadding, y, mSelPaint);
            canvas.drawLine((mCurPos + 1) * ow + mPadding, y, getWidth() - mPadding, y, mNorPaint);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            ViewGroup.LayoutParams vp = getLayoutParams();
            vp.width = ViewGroup.LayoutParams.MATCH_PARENT;
            vp.height = mHeight;
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }

        public void setCurPostion(int pos) {
            mCurPos = pos;
            invalidate();
        }

        public void setCount(int count) {
            mCount = count;
        }
    }
}



然后提供了一个接口调用:

/**
 * RecommendView接口
 */
public interface IRecommend {
    void upDate();
    void init();
    void startAnimation();
    void stopAnimation();
}

图片的加载用到了ImageLoad库:


import android.content.Context;
import android.graphics.Bitmap;

import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.papau.show.constant.Constants;

import java.io.File;

public class ImageLoaderManager {
    /**
     * 不带硬盘缓存的options
     *
     * @param context
     * @return
     */
    public static synchronized DisplayImageOptions getCacheOnMemoryOptions(Context context) {

        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .cacheInMemory(true)
                .cacheOnDisk(false)
                .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
                .bitmapConfig(Bitmap.Config.ARGB_8888)
//                .showImageOnLoading(
//                        context.getResources().getDrawable(
//                                R.drawable.loading_wait))
//                .showImageOnFail(
//                        context.getResources().getDrawable(
//                                R.drawable.loading_wait))
                .build();
        return options;
    }

    public static synchronized DisplayImageOptions getCircleOptions(Context context) {

        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .cacheInMemory(true)
                .cacheOnDisk(false)
                .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
                .bitmapConfig(Bitmap.Config.ARGB_8888)
//                .showImageOnLoading(
//                        context.getResources().getDrawable(
//                                R.drawable.ic_user_head_hint))
//                .showImageOnFail(
//                        context.getResources().getDrawable(
//                                R.drawable.ic_user_head_hint))
                .build();
        return options;
    }

    /**
     * 获取在硬盘中缓存options
     *
     * @param context
     * @return options
     */
    public static synchronized DisplayImageOptions getCacheOnDiskOptions(
            Context context) {
        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .imageScaleType(ImageScaleType.EXACTLY)
                .bitmapConfig(Bitmap.Config.ARGB_8888)
//                .showImageOnLoading(
//                        context.getResources().getDrawable(
//                                R.drawable.loading_wait))
//                .showImageOnFail(
//                        context.getResources().getDrawable(
//                                R.drawable.loading_wait))
                .build();


        return options;
    }

    /**
     * 获取imageLoader 单例
     *
     * @param context
     * @return
     */
    public static synchronized ImageLoader getImageLoader(Context context) {
        ImageLoader imageLoader = ImageLoader.getInstance();
        File cacheDir = new File(Constants.sPicCacheLocalPath);
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
                context).diskCache(new UnlimitedDiskCache(cacheDir))
                .threadPoolSize(3)
                .diskCacheExtraOptions(480, 320, null)
                .build();
        imageLoader.init(config);
        return imageLoader;
    }
}

使用方法

DisplayMetrics dm = getActivity().getResources().getDisplayMetrics();
        RecommendView rv = new RecommendView(getActivity(),dm.widthPixels ,(dm.widthPixels)/2);
        headViewPager.addView(rv);