文档章节

CoverFlow效果控件无限循环效果

今日竹石
 今日竹石
发布于 2015/07/29 20:50
字数 1752
阅读 337
收藏 5

   今天开发一个滑动切换的3d动画效果,就在gitHub上边找了代码,然后把这些代码放到新建的项目中,实现了循环切换的效果,具体代码如下:

package pym.test.gallery3d.util;


import android.content.res.Resources;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.view.Display;


/**

 * Bitmap缩放处理工具类

 * @author bamboo

 *

 */

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>


© 著作权归作者所有

今日竹石
粉丝 41
博文 227
码字总数 181312
作品 0
朝阳
程序员
私信 提问
类似Cover Flow的效果

1、首先,这个看一个cover Flow的图 我想这个很多朋友都可以android的gallery或者其他模仿出来。 2、我的需求:先看图 1、左右可以滑动的效果,但是中间的图片移植都是红色的那张。左右的也只...

Muse.F.J.Roger
2012/09/13
470
0
Android实现CoverFlow效果

先上一张效果图: 上代码,看了代码什么都明白 CoverFlow从Gallery继承过来 package com.coverflow; import android.content.Context;import android.graphics.Camera;import android.graphi......

迷途d书童
2012/02/28
20.2K
25
我看了你的Android实现CoverFlow效果,请教一个问题

我看了你的Android实现CoverFlow效果,请教一个问题,我现在做的项目,同你做的那个效果很像,但就是要Gallery上下滑动,我找了很久,都没有相关的答案,请问你,我应该怎么做?感激不尽...

hugolubingshen
2012/03/14
1K
2
超炫的3D特效程序管理功能android

PC上不说了一些很炫的界面效果很多,其实android上也可以实现很多很COOL的特效。 先看一下效果吧! 相册功能的效果: 下面是加载的andriod 里的程序,用3D效果列出来。这个可以做为android开机...

yumingxinli
2013/02/12
1K
0
免费的Android UI库及组件推荐

短短数年时间Android平台就已经形成了一个庞大而活跃的开发者社区。许多社区开发的项目业已进入成熟阶段,甚至可以用于商业的软件生产中,且不用担心质量问题。 本文编译自androiduipatterns...

晨曦之光
2012/03/01
479
0

没有更多内容

加载失败,请刷新页面

加载更多

Supervisor-守护进程工具

进程管理工具(Supervisor) 简介 Supervisor是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统。它可以很方便的监听、启动、停止、重启一个或...

鬼方赤命
19分钟前
4
0
ajax与Fetch

一、ajax 使用步骤 1.创建XmlHttpRequest对象 2.调用open方法设置基本请求信息 3.设置发送的数据,发送请求 4.注册监听的回调函数 5.拿到返回值,对页面进行更新 //1.创建Ajax对象 if(...

Bing309
23分钟前
3
0
Nginx正则配置

Nginx配置中Location的语法规则 location [ = | ~ | ~* | ^~ | !~ | !~* ] /uri/{ … } = 表示精确匹配 ~ 表示区分大小写正则匹配 ~* 表示不区分大小写正则匹配 ^~ 表示URI以某个常规字符串开...

NoodlesMars
27分钟前
19
0
数组

1. 二维数组的查找 https://my.oschina.net/u/3973793/blog/3097920 2. 数组中重复的数字 https://my.oschina.net/u/3973793/blog/3106083 3. 构建乘积数组 https://my.oschina.net/u/39737......

Garphy
29分钟前
5
0
JS中的七大数据类型

在JavaScript中变量包含两种类型的值:一种是基本类型,一种是引用类型。任何不属于基本类型的东西都属于对象。 基本类型包括:Null、Undefined、Number、String、Boolean、Symbol(ES6新增)...

蓝小驴
32分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部