仿即刻 "猜你喜欢" 切换效果

2,512 阅读4分钟

     最近在即刻里看到即刻的"猜你喜欢"的板块,觉得效果很赞。

     

    当点击"换一换"时,上面三个条目程序切换效果,并且三个条目的切换以不同的速度进行。

    于是开始想办法撸出这样的切换效果。

    我的思路是使用竖直切换的ViewPager,因为之前使用过ViewPager的一些切换动画和这里的切换很相似。

    最后实现的两种效果:

               

    github地址点我  

    关于竖直切换的ViewPager,你能找到很多资料,我这里使用的是一个日本小哥的VerticalViewPager

    他在onInterceptTouchEvent方法里巧妙的添加了swapTouchEvent方法,将左右滑动切换转换为上下滑动,或者说当你上下滑动时,造成一个假象,viewpager以为你在上下切换。

package com.example.xw.jikeviewpager;

/**
 * Created by xw on 2016/10/9.
 */

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;

import Transformer.DefaultTransformer;


public class VerticalViewPager extends ViewPager {

    public VerticalViewPager(Context context) {
        this(context, null);
    }

    public VerticalViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        setPageTransformer(false, new DefaultTransformer());
    }

    private MotionEvent swapTouchEvent(MotionEvent event) {
        float width = getWidth();
        float height = getHeight();

        float swappedX = (event.getY() / height) * width;
        float swappedY = (event.getX() / width) * height;

        event.setLocation(swappedX, swappedY);

        return event;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        boolean intercept = super.onInterceptTouchEvent(swapTouchEvent(event));
        //If not intercept, touch event should not be swapped.
        swapTouchEvent(event);
        return intercept;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return super.onTouchEvent(swapTouchEvent(ev));
    }

}

   关于DefaultTransformer类,是用来控制切换效果的,接下来我们会用ZoomOutTransformer。

   关于这几个类,代码点我

   接下来发现即刻切换中的图片都是圆角矩形,关于自定义一个圆角矩形ImageView,代码如下,具体就不分析了。

public class RoundRectImageView extends ImageView{

    private Paint paint;

    public RoundRectImageView(Context context) {
        this(context,null);
    }

    public RoundRectImageView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public RoundRectImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        paint  = new Paint();
    }

    /**
     * 绘制圆角矩形图片
     * @author caizhiming
     */
    @Override
    protected void onDraw(Canvas canvas) {

        Drawable drawable = getDrawable();
        if (null != drawable) {
            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
            Bitmap b = getRoundBitmap(bitmap, 20);
            final Rect rectSrc = new Rect(0, 0, b.getWidth(), b.getHeight());
            final Rect rectDest = new Rect(0,0,getWidth(),getHeight());
            paint.reset();
            canvas.drawBitmap(b, rectSrc, rectDest, paint);

        } else {
            super.onDraw(canvas);
        }
    }

    /**
     * 获取圆角矩形图片方法
     * @param bitmap
     * @param roundPx,一般设置成14
     * @return Bitmap
     * @author caizhiming
     */
    private Bitmap getRoundBitmap(Bitmap bitmap, int roundPx) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;

        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        int x = bitmap.getWidth();

        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;


    }
}

    接下来我们实现第一种切换效果,以一个RoundRectImageView加textview作为fragment,然后将fragment作为VerticalViewPager的内容。

    fragment_item.xml   



    

   


    创建fragment类和一个item的实体类代码就省略了。

    要注意这里利用 Argument传数据生成fragment。

   public static MyFragment newInstance(int imgId,String text){
        Bundle args=new Bundle();
        args.putSerializable(ARG_IMG_ID,imgId);
        args.putSerializable(ARG_TEXT,text);

        MyFragment fragment=new MyFragment();
        fragment.setArguments(args);
        return fragment;

    }

     接下来在MainActivity中,我们的布局使用两个VerticalViewPager和一个负责切换的button。

private void initViewPager() {


       int[] ims={R.drawable.kenan,R.drawable.mingren,R.drawable.lufei};
        String[] text={"身体虽然变小,但头脑依然灵活",
                "卡 给 分 新 诺 句 子 !!!",
                "我是要成为海贼王的男人!"};
        for (int i = 0; i 

    因为我们用的是ZoomOut的效果,所以先设置显示在最后一页,点击button时,设置位置减1,刚好可以实现往下切换的效果。

   (其实是因为没有找到ZoomIn的类,如果你找到了直接使用这个转换效果类即可)

changeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                    viewPager.setCurrentItem((viewPager.getCurrentItem()-1));
                    viewPager2.setCurrentItem(viewPager2.getCurrentItem()-1);
            }
        });

    最后,还要实现的是两边切换速度不一样,因为viewPager.setCurrentItem方法设施的切换总是一闪而过,太短暂了,无法形成视觉停留的效果。

    这时候需要用到的类

    FixedSpeedScroller

public class FixedSpeedScroller extends Scroller {
    private int mDuration = 1500;

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

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

    @Override
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        // Ignore received duration, use fixed one instead
        super.startScroll(startX, startY, dx, dy, mDuration);
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy) {
        // Ignore received duration, use fixed one instead
        super.startScroll(startX, startY, dx, dy, mDuration);
    }

    public void setmDuration(int time) {
        mDuration = time;
    }

    public int getmDuration() {
        return mDuration;
    }
    public void initViewPagerScroll(ViewPager viewPager) {
        try {
            Field mScroller = ViewPager.class.getDeclaredField("mScroller");
            mScroller.setAccessible(true);
            mScroller.set(viewPager, this);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

    这里我们看到是利用的反射的手法修改viewpager的"mScroller"字段。

    MainActivity中初始化时调用

    private void initSpeed() {
        FixedSpeedScroller scroller=new FixedSpeedScroller(this);
        scroller.setmDuration(2500);
        scroller.initViewPagerScroll(viewPager);

        FixedSpeedScroller scroller2=new FixedSpeedScroller(this);
        scroller2.setmDuration(1500);
        scroller2.initViewPagerScroll(viewPager2);
    }

     这时候就已经完成了不同的切换速度。

     效果:

    

    至于第二种文字单独切换的,只要将文字单独用一个VerticalViewPager即可。

    以上方法仅供参考,实际应用的话肯定还是要不断地优化处理。