ViewPager实现炫酷的3D无限轮播

1,240 阅读9分钟

关于普通的ViewPager无限轮播很多博客都有实现,我就不赘述了,也有很多优秀的开源库,很好用比如说Banner,那我们为什么不自己实现一下另类的轮播呢。先看图:

这就是我的一个轮播,手指滑动时图片按照手指的滑动方向滑动(默认右边),好了话不多说。我说说自己的实现方式和思路吧: viewPager提供了一个setPageTransformer方法我们利用这个方法实现ViewPager.PageTransformer接口:

public class DepthPageTransformer implements ViewPager.PageTransformer {
private Rotate3dAnimation rotation;

public void transformPage(View view, float position) {
    if (UserBean.ITEMCREND) {
        startRotation(view, 120);//倾斜度
    } else{
        startRotation(view, -120);
    }
}

private void startRotation(View image, float start, float end) {
    // 计算中心点
    final float centerX = image.getWidth() / 2.0f;
    final float centerY = image.getHeight() / 2.0f;
    rotation = new Rotate3dAnimation(start, end, centerX, centerY, 0ftrue);
    rotation.setDuration(500);
    rotation.setFillAfter(true);

    //匀速旋转
    //rotation.setInterpolator(new DecelerateInterpolator());
    image.startAnimation(rotation);


}

}

我们看到构造方法transformPage(View view, float position)中的view 这个view代表viewpager中的每个item,那么我们用这个item来实现一些特效就可以看到我刚才那种效果了, Rotate3dAnimation是谷歌开源的一个3D旋转特效。这里我稍稍修改利用 然后是viewpager的适配器

public class MyPageAdapter extends PagerAdapter {

private Context context;
private ArrayList<Integer> imgList;

public MyPageAdapter(Context context, ArrayList<Integer> newsList{
    this.context = context;
    this.imgList = newsList;
}

@Override
public int getCount(
{
    return Integer.MAX_VALUE;//最大值

}

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

public Object instantiateItem(ViewGroup container, final int position{

    View view = View.inflate(context, R.layout.itempage, null);
    ImageView imageView = (ImageView) view.findViewById(R.id.img);
    imageView.setBackgroundResource(imgList.get(position % imgList.size()));
    imageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view
{
            onItemClickListener.onClick(view,position % imgList.size());
        }
    });
    container.addView(view);
    return view;

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

/**
 * 点击
 */

public interface OnItemClickListener {
    void onClick(View view, int position);
}

OnItemClickListener onItemClickListener;

public void setOnItemClickListener(OnItemClickListener onItemClickListener{
    this.onItemClickListener = onItemClickListener;
}

}

设置Integer.MAX_VALUE来实现一个伪循环,因为是伪循环所以点击监听还需要我们自己来实现viewpager本身的监听就不对了,所以要 position % imgList.size()取余来设置viewpager的 item的点击事件。再看实现逻辑

public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener {

private ViewPager viewPager;
private ArrayList<Integer> arrayList;
private MyPageAdapter myPageAdapter;
private int mPagerPosition;//当前的item
private int firstTime, secondTime, slideNumber = 0;//第一和第二次手指触屏的时间以及滑动次数
private int mPagerIndex = 0;
private int pageCurrentItem;//当前选中的item

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

    viewPager = findViewById(R.id.viewpage);
    arrayList = new ArrayList();
    arrayList.add(R.drawable.jt1);
    arrayList.add(R.drawable.jt2);
    arrayList.add(R.drawable.jt3);

    myPageAdapter = new MyPageAdapter(MainActivity.this, arrayList);
    viewPager.setAdapter(myPageAdapter);
    viewPager.setCurrentItem(Integer.MAX_VALUE / 2);//伪循环 MAX_VALUE最大值21亿左右
    viewPager.addOnPageChangeListener(this);
    viewPager.setPageMargin(-270);//item之间的间隔

    viewPager.setOffscreenPageLimit(2); //缓存item个数
    viewPager.setPageTransformer(truenew DepthPageTransformer());

    ViewPagerScroller scroller = new ViewPagerScroller(MainActivity.this);
    scroller.setScrollDuration(500);//这个是设置切换过渡时间为500毫秒
    scroller.initViewPagerScroll(viewPager);
    handler.sendEmptyMessageDelayed(0x0011000);

    viewPager.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {

            switch (motionEvent.getAction()) {
                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_MOVE:
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mmssSSS");//yyyyMMddHH
                    firstTime = Integer.parseInt(simpleDateFormat.format(new Date()));
                    handler.removeMessages(0x001);
                    slideNumber++;//滑动次数
                    break;
                case MotionEvent.ACTION_UP:
                    if (mPagerIndex >= 1) {
                        if (firstTime - secondTime > 2000) {
                            if (firstTime != secondTime) {
                                handler.sendEmptyMessageDelayed(0x0012000);
                            }
                        } else {
                            handler.sendEmptyMessageDelayed(0x0022000);
                        }
                    }
                    if (slideNumber < 2) {//解决如果用户只滑动一次
                        handler.sendEmptyMessageDelayed(0x0012000);
                    }
                    secondTime = firstTime;
                    mPagerIndex++;
                    break;

                default:
                    break;
            }


            return false;
        }
    });
    myPageAdapter.setOnItemClickListener(new MyPageAdapter.OnItemClickListener() {
        @Override
        public void onClick(View view, int position) {
            Log.i("position==", position + "");

        }
    });


}

Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        if (msg.what == 0x001) {
            pageCurrentItem = viewPager.getCurrentItem() + 1;
            viewPager.setCurrentItem(pageCurrentItem);
            handler.removeMessages(0x001);
            handler.sendEmptyMessageDelayed(0x0012000);

        } else if (msg.what == 0x002) {
            handler.removeMessages(0x001);
            handler.sendEmptyMessageDelayed(0x0011000);
        }

    }
};

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    if (mPagerPosition == position || mPagerPosition + 1 == position && mPagerPosition != 0) {
        UserBean.ITEMCREND = false;
    } else {
        UserBean.ITEMCREND  = true;
    }
}

@Override
public void onPageSelected(int position) {

}

@Override
public void onPageScrollStateChanged(int state) {
    if (state == 1) {//state有三种状态下文会将,当手指刚触碰屏幕时state的值为1,我们就在这个时候给mViewPagerIndex 赋值。
        mPagerPosition = viewPager.getCurrentItem();
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    handler.removeMessages(0x001);
    handler.removeMessages(0x002);
    slideNumber = 0;
}

}

这里难点就是viewpagr的setOnTouchListener监听我们可以监听用户第一次和第二次按下屏幕的时间相减满足我们设定的时间就发送handler让handler来执行选中item; 对了我们还要修改下viewpager的滑动

public class ViewPagerScroller extends Scroller {
private int mScrollDuration = 1000; // 滑动速度

/**
 * 设置速度速度
 *
 * @param duration
 */


public void setScrollDuration(int duration) {

    this.mScrollDuration = duration;

}


public ViewPagerScroller(Context context) {

    super(context);

}

public ViewPagerScroller(Context context, Interpolator interpolator) {

    super(context, interpolator);

}

public ViewPagerScroller(Context context, Interpolator interpolator, boolean flywheel) {

    super(context, interpolator, flywheel);

}

@Override

public void startScroll(int startX, int startY, int dx, int dy, int duration) {

    super.startScroll(startX, startY, dx, dy, mScrollDuration);

}

@Override

public void startScroll(int startX, int startY, int dx, int dy) {

    super.startScroll(startX, startY, dx, dy, mScrollDuration);

}

public void initViewPagerScroll(ViewPager viewPager) {

    try {

        Field mScroller = ViewPager.class.getDeclaredField("mScroller");

        mScroller.setAccessible(true);

        mScroller.set(viewPager, this);

    } catch (Exception e) {

        e.printStackTrace();

    }

}

}

于是大功告成:附上我的项目下载地址:gitee.com/duanpingwei…