Android gallery 3D效果

        在看了iOS上面的CoverFlow后,感觉效果真的不错,就想在android上面实现一个,这个程序在网上参考了一此核心的代码,当然我添加了一些其他的东西,废话不多话,先看效果,不然就是无图无真相了。

 

Android gallery 3D效果

 

其实实现这个效果很简单,下面作一个简单的介绍

 

一,创建倒影效果

这个基本思路是:

1,创建一个源图一样的图,利用martrix将图片旋转180度。这个倒影图的高是源图的一半。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Matrix matrix =  new Matrix();
 
// 1表示放大比例,不放大也不缩小。
// -1表示在y轴上相反,即旋转180度。
matrix.preScale( 1 , - 1 );
 
Bitmap reflectionBitmap = Bitmap.createBitmap(
     srcBitmap,
     0 ,
     srcBitmap.getHeight() /  2 ,   // top为源图的一半
     srcBitmap.getWidth(),        // 宽度与源图一样
     srcBitmap.getHeight() /  2 ,   // 高度与源图的一半
     matrix,
     false );

2,创建一个最终效果的图,即源图 + 间隙 + 倒影。

?
1
2
3
4
5
6
final int REFLECTION_GAP =  5 ;
 
Bitmap bitmapWithReflection = Bitmap.createBitmap(
        reflectionWidth,
        srcHeight + reflectionHeight + REFLECTION_GAP,
        Config.ARGB_8888);

3,依次将源图、倒影图绘制在最终的bitmap上面。

?
1
2
3
4
5
6
7
8
// Prepare the canvas to draw stuff.
Canvas canvas =  new Canvas(bitmapWithReflection);
             
// Draw the original bitmap.
canvas.drawBitmap(srcBitmap,  0 0 null );
             
// Draw the reflection bitmap.
canvas.drawBitmap(reflectionBitmap,  0 , srcHeight + REFLECTION_GAP,  null );
4,创建LinearGradient,从而给定一个由上到下的渐变色。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Paint paint =  new Paint();
paint.setAntiAlias( true );
LinearGradient shader =  new LinearGradient(
         0 ,
         srcHeight,
         0 ,
         bitmapWithReflection.getHeight() + REFLECTION_GAP,
         0x70FFFFFF ,
         0x00FFFFFF ,
         TileMode.MIRROR);
paint.setShader(shader);
paint.setXfermode( new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));
 
// Draw the linear shader.
canvas.drawRect(
         0 ,
         srcHeight,
         srcWidth,
         bitmapWithReflection.getHeight() + REFLECTION_GAP,
         paint);

二,扩展Gallery

扩展系统的gallery,我们需要重写两个方法,getChildStaticTransformation()和getChildDrawingOrder(),同时,要使这两个方法能被调用,必须执行如下两行代码,文档上面是有说明的。

?
1
2
3
4
// Enable set transformation.
this .setStaticTransformationsEnabled( true );
// Enable set the children drawing order.
this .setChildrenDrawingOrderEnabled( true );

  • getChildDrawingOrder的实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Override
protected int getChildDrawingOrder( int childCount,  int i)
{
     // Current selected index.
     int selectedIndex = getSelectedItemPosition() - getFirstVisiblePosition();
     if (selectedIndex <  0 )
     {
         return i;
     }
     
     if (i < selectedIndex)
     {
         return i;
     }
     else if (i >= selectedIndex)
     {
         return childCount -  1 - i + selectedIndex;
     }
     else
     {
         return i;
     }
}

这里为什么要计算drawing order,因为从上图中看到,我们的效果是:中间左边的顺序是 0, 1, 2,右边的child覆盖左边的child,而在中间右边的顺序正好相反,左边的覆盖右边的,所以我们要重写这个方法,而gallery自身的实现,不是这种效果。

  • getChildStaticTransformation的实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Override
protected boolean getChildStaticTransformation(View child, Transformation t)
{
     super .getChildStaticTransformation(child, t);
     
     final int childCenter = getCenterOfView(child);
     final int childWidth  = child.getWidth();
     
     int rotationAngle =  0 ;
     t.clear();
     t.setTransformationType(Transformation.TYPE_MATRIX);
     
     // If the child is in the center, we do not rotate it.
     if (childCenter == mCoveflowCenter)
     {
         transformImageBitmap(child, t,  0 );
     }
     else
     {
         // Calculate the rotation angle.
         rotationAngle = ( int )((( float )(mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
         
         // Make the angle is not bigger than maximum.
         if (Math.abs(rotationAngle) > mMaxRotationAngle)
         {
             rotationAngle = (rotationAngle <  0 ) ? -mMaxRotationAngle : mMaxRotationAngle;
         }
         
         transformImageBitmap(child, t, rotationAngle);
     }
     
     return true ;
}

这个方法就是根据child来计算它的transformation(变换),我们需要去修改它里面的matrix,从而达到旋转的效果。根据位置和角度来计算的matrix的方法写在另外一个方法transformImageBitmap中实现。

  • transformImageBitmap()的实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private void transformImageBitmap(View child, Transformation t,  int rotationAngle)
{
     mCamera.save();
     
     final Matrix imageMatrix = t.getMatrix();
     final int imageHeight = child.getHeight();
     final int imageWidth  = child.getWidth();
     final int rotation    = Math.abs(rotationAngle);
     
     // Zoom on Z axis.
     mCamera.translate( 0 0 , mMaxZoom);
     
     if (rotation < mMaxRotationAngle)
     {
         float zoomAmount = ( float )(mMaxZoom + rotation *  1 .5f);
         mCamera.translate( 0 0 , zoomAmount);
     }
     
     // Rotate the camera on Y axis.
     mCamera.rotateY(rotationAngle);
     // Get the matrix from the camera, in fact, the matrix is S (scale) transformation.
     mCamera.getMatrix(imageMatrix);
     
     // The matrix final is T2 * S * T1, first translate the center point to (0, 0),
     // then scale, and then translate the center point to its original point.
     // T * S * T
     
     // S * T1
     imageMatrix.postTranslate((imageWidth /  2 ), (imageHeight /  2 ));
     // (T2 * S) * T1
     imageMatrix.preTranslate(-(imageWidth /  2 ), -(imageHeight /  2 ));
     
     mCamera.restore();
}

这里,简单说明一个,

        第一,先在Z轴上平称,其实就是得到一个缩放矩阵变换,我这里简写为 S。

        第二,是利用camera这个类来生成matrix,其实mCamera.rotateY就是围绕Y轴旋转。这里生成了一个旋转矩阵,记为 R 。经过这两步,此时调用mCamera.getMatrix(imageMatrix); 从Camera中得到matrix,此时这个矩阵中包含了S * R。

        第三,最关键是下面两句       

?
1
2
3
4
// S * T1
  imageMatrix.postTranslate((imageWidth /  2 ), (imageHeight /  2 ));
  // (T2 * S) * T1
  imageMatrix.preTranslate(-(imageWidth /  2 ), -(imageHeight /  2 ));
        由于这里涉及到旋转与缩放,缩放操作其实应该是针对Child中点进行了,这里就是作一个平衡操作,我们必须是先平移,再缩放,再平移回原来位置,所以,我们最终的矩阵变换应该是这样的:

        M = T * (S * R) * T1   (这里在T1表示与T相反)。

三,完整代码

GalleryFlow.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Transformation;
import android.widget.Gallery;
 
public class GalleryFlow  extends Gallery
{
     /**
      * The camera class is used to 3D transformation matrix.
      */
     private Camera mCamera =  new Camera();
     
     /**
      * The max rotation angle.
      */
     private int mMaxRotationAngle =  60 ;
     
     /**
      * The max zoom value (Z axis).
      */
     private int mMaxZoom = - 120 ;
     
     /**
      * The center of the gallery.
      */
     private int mCoveflowCenter =  0 ;
     
     public GalleryFlow(Context context)
     {
         this (context,  null );
     }
     
     public GalleryFlow(Context context, AttributeSet attrs)
     {
         this (context, attrs,  0 );
     }
     
     public GalleryFlow(Context context, AttributeSet attrs,  int defStyle)
     {
         super (context, attrs, defStyle);
         
         // Enable set transformation.
         this .setStaticTransformationsEnabled( true );
         // Enable set the children drawing order.
         this .setChildrenDrawingOrderEnabled( true );
     }
     
     public int getMaxRotationAngle()
     {
         return mMaxRotationAngle;
     }
     
     public void setMaxRotationAngle( int maxRotationAngle)
     {
         mMaxRotationAngle = maxRotationAngle;
     }
     
     public int getMaxZoom()
     {
         return mMaxZoom;
     }
     
     public void setMaxZoom( int maxZoom)
     {
         mMaxZoom = maxZoom;
     }
     
     @Override
     protected int getChildDrawingOrder( int childCount,  int i)
     {
         // Current selected index.
         int selectedIndex = getSelectedItemPosition() - getFirstVisiblePosition();
         if (selectedIndex <  0 )
         {
             return i;
         }
         
         if (i < selectedIndex)
         {
             return i;
         }
         else if (i >= selectedIndex)
         {
             return childCount -  1 - i + selectedIndex;
         }
         else
         {
             return i;
         }
     }
     
     @Override
     protected void onSizeChanged( int w,  int h,  int oldw,  int oldh)
     {
         mCoveflowCenter = getCenterOfCoverflow();
         super .onSizeChanged(w, h, oldw, oldh);
     }
     
     private int getCenterOfView(View view)
     {
         return view.getLeft() + view.getWidth() /  2 ;
     }
     
     @Override
     protected boolean getChildStaticTransformation(View child, Transformation t)
     {
         super .getChildStaticTransformation(child, t);
         
         final int childCenter = getCenterOfView(child);
         final int childWidth  = child.getWidth();
         
         int rotationAngle =  0 ;
         t.clear();
         t.setTransformationType(Transformation.TYPE_MATRIX);
         
         // If the child is in the center, we do not rotate it.
         if (childCenter == mCoveflowCenter)
         {
             transformImageBitmap(child, t,  0 );
         }
         else
         {
             // Calculate the rotation angle.
             rotationAngle = ( int )((( float )(mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
             
             // Make the angle is not bigger than maximum.
             if (Math.abs(rotationAngle) > mMaxRotationAngle)
             {
                 rotationAngle = (rotationAngle <  0 ) ? -mMaxRotationAngle : mMaxRotationAngle;
             }
             
             transformImageBitmap(child, t, rotationAngle);
         }
         
         return true ;
     }
     
     private int getCenterOfCoverflow()
     {
         return (getWidth() - getPaddingLeft() - getPaddingRight()) /  2 + getPaddingLeft();
     }
     
     private void transformImageBitmap(View child, Transformation t,  int rotationAngle)
     {
         mCamera.save();
         
         final Matrix imageMatrix = t.getMatrix();
         final int imageHeight = child.getHeight();
         final int imageWidth  = child.getWidth();
         final int rotation    = Math.abs(rotationAngle);
         
         // Zoom on Z axis.
         mCamera.translate( 0 0 , mMaxZoom);
         
         if (rotation < mMaxRotationAngle)
         {
             float zoomAmount = ( float )(mMaxZoom + rotation *  1 .5f);
             mCamera.translate( 0 0 , zoomAmount);
         }
         
         // Rotate the camera on Y axis.
         mCamera.rotateY(rotationAngle);
         // Get the matrix from the camera, in fact, the matrix is S (scale) transformation.
         mCamera.getMatrix(imageMatrix);
         
         // The matrix final is T2 * S * T1, first translate the center point to (0, 0),
         // then scale, and then translate the center point to its original point.
         // T * S * T
         
         // S * T1
         imageMatrix.postTranslate((imageWidth /  2 ), (imageHeight /  2 ));
         // (T2 * S) * T1
         imageMatrix.preTranslate(-(imageWidth /  2 ), -(imageHeight /  2 ));
         
         mCamera.restore();
     }
}

BitmapUtil.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package com.lee.gallery3d.utils;
 
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.PixelFormat;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.Drawable;
 
public class BitmapUtil
{
     public static Bitmap createReflectedBitmap(Bitmap srcBitmap)
     {
         if ( null == srcBitmap)
         {
             return null ;
         }
         
         // The gap between the reflection bitmap and original bitmap.
         final int REFLECTION_GAP =  4 ;
         
         int srcWidth  = srcBitmap.getWidth();
         int srcHeight = srcBitmap.getHeight();
         int reflectionWidth  = srcBitmap.getWidth();
         int reflectionHeight = srcBitmap.getHeight() /  2 ;
         
         if ( 0 == srcWidth || srcHeight ==  0 )
         {
             return null ;
         }
         
         // The matrix
         Matrix matrix =  new Matrix();
         matrix.preScale( 1 , - 1 );
         
         try
         {
             // The reflection bitmap, width is same with original's, height is half of original's.
             Bitmap reflectionBitmap = Bitmap.createBitmap(
                     srcBitmap,
                     0 ,
                     srcHeight /  2 ,
                     srcWidth,
                     srcHeight /  2 ,
                     matrix,
                     false );
             
             if ( null == reflectionBitmap)
             {
                 return null ;
             }
             
             // Create the bitmap which contains original and reflection bitmap.
             Bitmap bitmapWithReflection = Bitmap.createBitmap(
                     reflectionWidth,
                     srcHeight + reflectionHeight + REFLECTION_GAP,
                     Config.ARGB_8888);
             
             if ( null == bitmapWithReflection)
             {
                 return null ;
             }
             
             // Prepare the canvas to draw stuff.
             Canvas canvas =  new Canvas(bitmapWithReflection);
             
             // Draw the original bitmap.
             canvas.drawBitmap(srcBitmap,  0 0 null );
             
             // Draw the reflection bitmap.
             canvas.drawBitmap(reflectionBitmap,  0 , srcHeight + REFLECTION_GAP,  null );
             
             Paint paint =  new Paint();
             paint.setAntiAlias( true );
             LinearGradient shader =  new LinearGradient(
                     0 ,
                     srcHeight,
                     0 ,
                     bitmapWithReflection.getHeight() + REFLECTION_GAP,
                     0x70FFFFFF ,
                     0x00FFFFFF ,
                     TileMode.MIRROR);
             paint.setShader(shader);
             paint.setXfermode( new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));
             
             // Draw the linear shader.
             canvas.drawRect(
                     0 ,
                     srcHeight,
                     srcWidth,
                     bitmapWithReflection.getHeight() + REFLECTION_GAP,
                     paint);
             
             return bitmapWithReflection;
         }
         catch (Exception e)
         {
             e.printStackTrace();
         }
         
         return null ;
     }
}
来自:http://blog.csdn.net/leehong2005/article/details/8070538 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值