仿即刻app"猜你喜歡"切換控件


     最近在即刻里看到即刻的"猜你喜歡"的板塊,覺得效果很贊。

     

    

    當點擊"換一換"時,上面三個條目程序切換效果,並且三個條目的切換以不同的速度進行。

    於是開始想辦法擼出這樣的切換效果。

    我的思路是使用豎直切換的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   

    

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="130dp"
              android:layout_height="130dp">
    <com.example.xw.jikeviewpager.RoundRectImageView
        android:id="@+id/iv"
        android:scaleType="centerCrop"
        android:layout_width="match_parent"
        android:layout_height="120dp"/>

   <TextView
       android:id="@+id/tv"
       android:text="1111"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>

</LinearLayout>

 

    創建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 <ims.length ; i++) {
            Item item=new Item(ims[i],text[i]);
            list.add(item);
        }

        int[] ims2={R.drawable.qinnv,R.drawable.yasuo,R.drawable.timo};
        String[] text2={
            "為什么啞巴琴女會說話?",
            "死亡如風,常伴吾身",
                "timo隊長,正在送命"
        };
        for (int i = 0; i <ims2.length ; i++) {
            Item item=new Item(ims2[i],text2[i]);
            list2.add(item);
        }

        viewPager.setPageTransformer(true, new ZoomOutTransformer());
        viewPager2.setPageTransformer(true,new ZoomOutTransformer());

        //viewPager.setPageTransformer(true, new StackTransformer());
        FragmentManager fm=getSupportFragmentManager();
        viewPager.setAdapter(new FragmentStatePagerAdapter(fm) {
            @Override
            public Fragment getItem(int position) {
                Item item=list.get(position);
                return MyFragment.newInstance(item.getImageId(),item.getText());
            }

            @Override
            public int getCount() {
                return list.size();
            }
        });
        viewPager.setOverScrollMode(View.OVER_SCROLL_NEVER);
        viewPager.setCurrentItem(list.size()-1);

        viewPager2.setAdapter(new FragmentStatePagerAdapter(fm) {
            @Override
            public Fragment getItem(int position) {
                Item item=list2.get(position);
                return MyFragment.newInstance(item.getImageId(),item.getText());
            }

            @Override
            public int getCount() {
                return list2.size();
            }
        });

        viewPager2.setOverScrollMode(View.OVER_SCROLL_NEVER);
        viewPager2.setCurrentItem(list.size()-1);
    }

    因為我們用的是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即可。

    以上方法僅供參考,實際應用的話肯定還是要不斷地優化處理。

  

    

    

     

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM