CoverFlow效果控件無限循環效果

   今天開發一個滑動切換的3d動畫效果,就在gitHub上邊找了代碼,而後把這些代碼放到新建的項目中,實現了循環切換的效果,具體代碼以下:android

package pym.test.gallery3d.util;git


import android.content.res.Resources;canvas

import android.graphics.Bitmap;數組

import android.graphics.BitmapFactory;app

import android.view.Display;ide


/**函數

 * Bitmap縮放處理工具類工具

 * @author bamboopost

 *動畫

 */

public class BitmapScaleDownUtil {

/* 數據段begin */

    private final String TAG = "BitmapScaleDownUtil";

    /* 數據段end */

    /* 函數段begin */

    /**

     * @function 獲取屏幕大小

     * @param display

     * @return 屏幕寬高

     */

    public static int[] getScreenDimension(Display display)

    {

        int[] dimension = new int[2];

        dimension[0] = display.getWidth();

        dimension[1] = display.getHeight();

        

        return dimension;

    }

    

    /**

     * @function 以取樣方式加載Bitmap 

     * @param res

     * @param resId

     * @param reqWidth

     * @param reqHeight

     * @return 取樣後的Bitmap

     */

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight)

    {

        // step1,將inJustDecodeBounds置爲true,以解析Bitmap真實尺寸

        final BitmapFactory.Options options = new BitmapFactory.Options();

        options.inJustDecodeBounds = true;

        BitmapFactory.decodeResource(res, resId, options);

 

         // step2,計算Bitmap取樣比例

        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

 

        // step3,將inJustDecodeBounds置爲false,以取樣比列解析Bitmap

        options.inJustDecodeBounds = false;

        return BitmapFactory.decodeResource(res, resId, options);

    }

 

    /**

     * @function 計算Bitmap取樣比例

     * @param options

     * @param reqWidth

     * @param reqHeight

     * @return 取樣比例

     */

    private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight)

    {

        // 默認取樣比例爲1:1

        int inSampleSize = 1;

 

        // Bitmap原始尺寸

        final int width = options.outWidth;

        final int height = options.outHeight;

 

        // 取最大取樣比例

        if (height > reqHeight || width > reqWidth)

        {

            final int widthRatio = Math.round((float) width / (float) reqWidth);

            final int heightRatio = Math.round((float) height / (float) reqHeight);

 

            // 取樣比例爲X:1,其中X>=1

            inSampleSize = Math.max(widthRatio, heightRatio);

        }

 

        return inSampleSize;

    }

    /* 函數段end */

}

package pym.test.gallery3d.widget;


import android.content.Context;

import android.graphics.Camera;

import android.graphics.Matrix;

import android.util.AttributeSet;

import android.util.Log;

import android.view.View;

import android.view.animation.Transformation;

import android.widget.Gallery;

/***

 * 自定義控件

 * @author bamboo

 *

 */

public class GalleryFlow extends Gallery {

    /* 數據段begin */

     private final String TAG = "GalleryFlow";

     // 邊緣圖片最大旋轉角度

    private final float MAX_ROTATION_ANGLE = 75;

    // 中心圖片最大前置距離

     private final float MAX_TRANSLATE_DISTANCE = -100;

     // GalleryFlow中心X座標

     private int mGalleryFlowCenterX;

     // 3D變換Camera

     private Camera mCamera = new Camera();

     /* 數據段end */

 

     /* 函數段begin */

     public GalleryFlow(Context context, AttributeSet attrs)

     {

         super(context, attrs);

         // 開啓,在滑動過程當中,回調getChildStaticTransformation()

         this.setStaticTransformationsEnabled(true);

     }

     /**

      * @function 獲取GalleryFlow中心X座標

      * @return

      */

     private int getCenterXOfCoverflow()

     {

         return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();

     }

     /**

      * @function 獲取GalleryFlow子view的中心X座標

      * @param childView

     * @return

      */

     private int getCenterXOfView(View childView)

     {

         return childView.getLeft() + childView.getWidth() / 2;

     }

     

     /**

      * @note step1 系統調用measure()方法時,回調此方法;代表此時系統正在計算view的大小

      */

     @Override

     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

     {

         super.onMeasure(widthMeasureSpec, heightMeasureSpec);

         

         mGalleryFlowCenterX = getCenterXOfCoverflow();

         Log.d(TAG, "onMeasure, mGalleryFlowCenterX = " + mGalleryFlowCenterX);

    }

     

     /**

      * @note step2 系統調用layout()方法時,回調此方法;代表此時系統正在給child view分配空間

      * @note 一定在onMeasure()以後回調,但與onSizeChanged()前後順序不必定

      */

     @Override

     protected void onLayout(boolean changed, int l, int t, int r, int b)

     {

         super.onLayout(changed, l, t, r, b);

        

        mGalleryFlowCenterX = getCenterXOfCoverflow();

        Log.d(TAG, "onLayout, mGalleryFlowCenterX = " + mGalleryFlowCenterX);

     }

     

     /**

      * @note step2 系統調用measure()方法後,當須要繪製此view時,回調此方法;代表此時系統已計算完view的大小

      * @note 一定在onMeasure()以後回調,但與onSizeChanged()前後順序不必定

      */

     @Override

     protected void onSizeChanged(int w, int h, int oldw, int oldh)

     {

         super.onSizeChanged(w, h, oldw, oldh);

         

         mGalleryFlowCenterX = getCenterXOfCoverflow();

         Log.d(TAG, "onSizeChanged, mGalleryFlowCenterX = " + mGalleryFlowCenterX);

     }

     

     @Override

     protected boolean getChildStaticTransformation(View childView, Transformation t)

    {

        // 計算旋轉角度

        float rotationAngle = calculateRotationAngle(childView);

        

         // 計算前置距離

        float translateDistance = calculateTranslateDistance(childView);

        

        // 開始3D變換

        transformChildView(childView, t, rotationAngle, translateDistance);

        

        return true;

    }

     

    /**

     * @function 計算GalleryFlow子view的旋轉角度

     * @note1 位於Gallery中心的圖片不旋轉

     * @note2 位於Gallery中心兩側的圖片按照離中心點的距離旋轉

     * @param childView

     * @return

     */

   private float calculateRotationAngle(View childView)

    {

        final int childCenterX = getCenterXOfView(childView);

        float rotationAngle = 0;

        

         rotationAngle = (mGalleryFlowCenterX - childCenterX) / (float) mGalleryFlowCenterX * MAX_ROTATION_ANGLE;

         

       if (rotationAngle > MAX_ROTATION_ANGLE)

        {

            rotationAngle = MAX_ROTATION_ANGLE;

        }

       else if (rotationAngle < -MAX_ROTATION_ANGLE)

       {

            rotationAngle = -MAX_ROTATION_ANGLE;

       }

        return rotationAngle;

    }

    /**

      * @function 計算GalleryFlow子view的前置距離

     * @note1 位於Gallery中心的圖片前置

    * @note2 位於Gallery中心兩側的圖片不前置

     * @param childView

     * @return

    */

   private float calculateTranslateDistance(View childView)

    {

       final int childCenterX = getCenterXOfView(childView);

        float translateDistance = 0;

        if (mGalleryFlowCenterX == childCenterX)

        {

           translateDistance = MAX_TRANSLATE_DISTANCE;

        }

       return translateDistance;

    }

   /**

     * @function 開始變換GalleryFlow子view

     * @param childView

     * @param t

     * @param rotationAngle

    * @param translateDistance

     */

    private void transformChildView(View childView, Transformation t, float rotationAngle, float translateDistance)

    {

        t.clear();

        t.setTransformationType(Transformation.TYPE_MATRIX);

        final Matrix imageMatrix = t.getMatrix();

        final int imageWidth = childView.getWidth();

      final int imageHeight = childView.getHeight();

        mCamera.save();

        /* rotateY */

       // 在Y軸上旋轉,位於中心的圖片不旋轉,中心兩側的圖片豎向向裏或向外翻轉。

      mCamera.rotateY(rotationAngle);

        /* rotateY */

         /* translateZ */

       // 在Z軸上前置,位於中心的圖片會有放大的效果

        mCamera.translate(0, 0, translateDistance);

        /* translateZ */

       // 開始變換(個人理解是:移動Camera,在2D視圖上產生3D效果)

        mCamera.getMatrix(imageMatrix);

        imageMatrix.preTranslate(-imageWidth / 2, -imageHeight / 2);

        imageMatrix.postTranslate(imageWidth / 2, imageHeight / 2);

       mCamera.restore();

    }

    /* 函數段end */


}

package pym.test.gallery3d.widget;


import pym.test.gallery3d.util.BitmapScaleDownUtil;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.Bitmap.Config;

import android.graphics.Canvas;

import android.graphics.LinearGradient;

import android.graphics.Matrix;

import android.graphics.Paint;

import android.graphics.PaintFlagsDrawFilter;

import android.graphics.PorterDuff;

import android.graphics.PorterDuffXfermode;

import android.graphics.Shader.TileMode;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.Gallery;

import android.widget.ImageView;


public class ImageAdapter extends BaseAdapter {

/* 數據段begin */

private final String TAG = "ImageAdapter";

private Context mContext;

// 圖片數組

private int[] mImageIds;

// 圖片控件數組

private ImageView[] mImages;

// 圖片控件LayoutParams

private GalleryFlow.LayoutParams mImagesLayoutParams;


/* 數據段end */

/* 函數段begin */

public ImageAdapter(Context context, int[] imageIds) {

mContext = context;

mImageIds = imageIds;

mImages = new ImageView[mImageIds.length];

mImagesLayoutParams = new GalleryFlow.LayoutParams(

Gallery.LayoutParams.WRAP_CONTENT,

Gallery.LayoutParams.WRAP_CONTENT);

}


/**

* @function 根據指定寬高建立待繪製的Bitmap,並繪製到ImageView控件上

* @param imageWidth

* @param imageHeight

* @return void

*/

@SuppressWarnings("deprecation")

public void createImages(int imageWidth, int imageHeight) {

// 原圖與倒影的間距5px

final int gapHeight = 5;

int index = 0;

for (int imageId : mImageIds) {

/* step1 採樣方式解析原圖並生成倒影 */

// 解析原圖,生成原圖Bitmap對象

// Bitmap originalImage =

// BitmapFactory.decodeResource(mContext.getResources(), imageId);

Bitmap originalImage = BitmapScaleDownUtil

.decodeSampledBitmapFromResource(mContext.getResources(),

imageId, imageWidth, imageHeight);

int width = originalImage.getWidth();

int height = originalImage.getHeight();

// Y軸方向反向,實質就是X軸翻轉

Matrix matrix = new Matrix();

matrix.setScale(1, -1);

// 且僅取原圖下半部分建立倒影Bitmap對象

Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0,

height / 2, width, height / 2, matrix, false);


/* step2 繪製 */

// 建立一個可包含原圖+間距+倒影的新圖Bitmap對象

Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height

+ gapHeight + height / 2), Config.ARGB_8888);

// 在新圖Bitmap對象之上建立畫布

Canvas canvas = new Canvas(bitmapWithReflection);

// 抗鋸齒效果

canvas.setDrawFilter(new PaintFlagsDrawFilter(0,

Paint.ANTI_ALIAS_FLAG));

// 繪製原圖

canvas.drawBitmap(originalImage, 0, 0, null);

// 繪製間距

Paint gapPaint = new Paint();

gapPaint.setColor(0xFFCCCCCC);

canvas.drawRect(0, height, width, height + gapHeight, gapPaint);

// 繪製倒影

canvas.drawBitmap(reflectionImage, 0, height + gapHeight, null);

/* step3 渲染 */

// 建立一個線性漸變的渲染器用於渲染倒影

Paint paint = new Paint();

LinearGradient shader = new LinearGradient(0, height, 0, (height

+ gapHeight + height / 2), 0x70ffffff, 0x00ffffff,

TileMode.CLAMP);

// 設置畫筆渲染器

paint.setShader(shader);

// 設置圖片混合模式

paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

// 渲染倒影+間距

canvas.drawRect(0, height, width,

(height + gapHeight + height / 2), paint);


/* step4 在ImageView控件上繪製 */

ImageView imageView = new ImageView(mContext);

imageView.setImageBitmap(bitmapWithReflection);

imageView.setLayoutParams(mImagesLayoutParams);

// 打log

imageView.setTag(index);


/* step5 釋放heap */

originalImage.recycle();

reflectionImage.recycle();

// bitmapWithReflection.recycle();

mImages[index++] = imageView;

}

}


@Override

public int getCount() {

return Integer.MAX_VALUE;

}


@Override

public Object getItem(int position) {

return mImages[position];

}


@Override

public long getItemId(int position) {

return position;

}


@Override

public View getView(int position, View convertView, ViewGroup parent) {

return mImages[position % mImages.length];

}

/* 函數段end */

}

package pym.test.gallery3d.widget;


import pym.test.gallery3d.util.BitmapScaleDownUtil;

import android.app.Activity;

import android.content.Context;

import android.os.Bundle;


public class MainActivity extends Activity {/* 數據段begin */

private final String TAG = "Gallery3DActivity";

private Context mContext;

// 圖片縮放倍率(相對屏幕尺寸的縮小倍率)

public static final int SCALE_FACTOR = 8;

// 圖片間距(控制各圖片之間的距離)

private final int GALLERY_SPACING = -10;

// 控件

private GalleryFlow mGalleryFlow;


/* 數據段end */

/* 函數段begin */

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

mContext = getApplicationContext();

setContentView(R.layout.gallery_3d_activity_layout);

initGallery();

}


private void initGallery() {

// 圖片ID

int[] images = { R.drawable.picture_1, R.drawable.picture_2,

R.drawable.picture_3, R.drawable.picture_4,

R.drawable.picture_5, R.drawable.picture_6,

R.drawable.picture_7 };

ImageAdapter adapter = new ImageAdapter(mContext, images);

// 計算圖片的寬高

int[] dimension = BitmapScaleDownUtil

.getScreenDimension(getWindowManager().getDefaultDisplay());

int imageWidth = dimension[0] / SCALE_FACTOR;

int imageHeight = dimension[1] / SCALE_FACTOR;

// 初始化圖片

adapter.createImages(imageWidth, imageHeight);

// 設置Adapter,顯示位置位於控件中間,這樣使得左右都可"無限"滑動

mGalleryFlow = (GalleryFlow) findViewById(R.id.gallery_flow);

mGalleryFlow.setSpacing(GALLERY_SPACING);

mGalleryFlow.setAdapter(adapter);

mGalleryFlow.setSelection(Integer.MAX_VALUE / 2);

}

/* 函數段end */

}

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical" >


    <pym.test.gallery3d.widget.GalleryFlow

        android:id="@+id/gallery_flow"

        android:layout_width="match_parent"

        android:layout_marginTop="20dp"

        android:layout_height="150dp" />


</LinearLayout>

相關文章
相關標籤/搜索