Android实现CoverFlow效果
先上一张效果图:
CoverFlow从Gallery继承过来
001 |
package com.coverflow; |
003 |
import android.content.Context; |
004 |
import android.graphics.Camera; |
005 |
import android.graphics.Matrix; |
006 |
import android.util.AttributeSet; |
007 |
import android.view.View; |
008 |
import android.view.animation.Transformation; |
009 |
import android.widget.Gallery; |
010 |
import android.widget.ImageView; |
012 |
public class CoverFlow extends Gallery
{ |
014 |
private Camera
mCamera = new Camera(); |
015 |
private int mMaxRotationAngle
= 50 ; |
016 |
private int mMaxZoom
= - 380 ; |
017 |
private int mCoveflowCenter; |
018 |
private boolean mAlphaMode
= true ; |
019 |
private boolean mCircleMode
= false ; |
021 |
public CoverFlow(Context
context) { |
023 |
this .setStaticTransformationsEnabled( true ); |
026 |
public CoverFlow(Context
context, AttributeSet attrs) { |
027 |
super (context,
attrs); |
028 |
this .setStaticTransformationsEnabled( true ); |
031 |
public CoverFlow(Context
context, AttributeSet attrs, int defStyle)
{ |
032 |
super (context,
attrs, defStyle); |
033 |
this .setStaticTransformationsEnabled( true ); |
036 |
public int getMaxRotationAngle()
{ |
037 |
return mMaxRotationAngle; |
040 |
public void setMaxRotationAngle( int maxRotationAngle)
{ |
041 |
mMaxRotationAngle
= maxRotationAngle; |
044 |
public boolean getCircleMode()
{ |
048 |
public void setCircleMode( boolean isCircle)
{ |
049 |
mCircleMode
= isCircle; |
052 |
public boolean getAlphaMode()
{ |
056 |
public void setAlphaMode( boolean isAlpha)
{ |
057 |
mAlphaMode
= isAlpha; |
060 |
public int getMaxZoom()
{ |
064 |
public void setMaxZoom( int maxZoom)
{ |
068 |
private int getCenterOfCoverflow()
{ |
069 |
return (getWidth()
- getPaddingLeft() - getPaddingRight()) / 2 |
073 |
private static int getCenterOfView(View
view) { |
074 |
return view.getLeft()
+ view.getWidth() / 2 ; |
077 |
protected boolean getChildStaticTransformation(View
child, Transformation t) { |
078 |
final int childCenter
= getCenterOfView(child); |
079 |
final int childWidth
= child.getWidth(); |
080 |
int rotationAngle
= 0 ; |
082 |
t.setTransformationType(Transformation.TYPE_MATRIX); |
083 |
if (childCenter
== mCoveflowCenter) { |
084 |
transformImageBitmap((ImageView)
child, t, 0 ); |
086 |
rotationAngle
= ( int )
((( float )
(mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle); |
087 |
if (Math.abs(rotationAngle)
> mMaxRotationAngle) { |
088 |
rotationAngle
= (rotationAngle < 0 )
? -mMaxRotationAngle |
091 |
transformImageBitmap((ImageView)
child, t, rotationAngle); |
097 |
*
这就是所谓的在大小的布局时,这一观点已经发生了改变。如果 你只是添加到视图层次,有人叫你旧的观念 价值观为0。 |
100 |
*
Current width of this view. |
102 |
*
Current height of this view. |
104 |
*
Old width of this view. |
106 |
*
Old height of this view. |
108 |
protected void onSizeChanged( int w, int h, int oldw, int oldh)
{ |
109 |
mCoveflowCenter
= getCenterOfCoverflow(); |
110 |
super .onSizeChanged(w,
h, oldw, oldh); |
117 |
*
ImageView the ImageView whose bitmap we want to rotate |
120 |
*
@param rotationAngle |
121 |
*
the Angle by which to rotate the Bitmap |
123 |
private void transformImageBitmap(ImageView
child, Transformation t, |
126 |
final Matrix
imageMatrix = t.getMatrix(); |
127 |
final int imageHeight
= child.getLayoutParams().height; |
128 |
final int imageWidth
= child.getLayoutParams().width; |
129 |
final int rotation
= Math.abs(rotationAngle); |
130 |
mCamera.translate( 0 .0f, 0 .0f, 100 .0f); |
133 |
if (rotation
<= mMaxRotationAngle) { |
134 |
float zoomAmount
= ( float )
(mMaxZoom + (rotation * 1.5 )); |
135 |
mCamera.translate( 0 .0f, 0 .0f,
zoomAmount); |
138 |
mCamera.translate( 0 .0f, 155 , 0 .0f); |
140 |
mCamera.translate( 0 .0f,
( 255 -
rotation * 2 .5f), 0 .0f); |
143 |
((ImageView)
(child)).setAlpha(( int )
( 255 -
rotation * 2.5 )); |
146 |
mCamera.rotateY(rotationAngle); |
147 |
mCamera.getMatrix(imageMatrix); |
148 |
imageMatrix.preTranslate(-(imageWidth
/ 2 ),
-(imageHeight / 2 )); |
149 |
imageMatrix.postTranslate((imageWidth
/ 2 ),
(imageHeight / 2 )); |
这个就是CoverFlow类,说明几点:
1. 成员函数
mCamera是用来做类3D效果处理,比如z轴方向上的平移,绕y轴的旋转等
mMaxRotationAngle是图片绕y轴最大旋转角度,也就是屏幕最边上那两张图片的旋转角度
mMaxZoom是图片在z轴平移的距离,视觉上看起来就是放大缩小的效果.
其他的变量都可以无视
也就是说把这个属性设成true的时候每次viewGroup(看Gallery的源码就可以看到它是从ViewGroup间接继承过来的)在重新画它的child的时候都会促发getChildStaticTransformation这个函数,所以我们只需要在这个函数里面去加上旋转和放大的操作就可以了
其他的getter和setter函数都可以无视
ImageAdapter适配器:
001 |
package com.coverflow; |
003 |
import android.content.Context; |
004 |
import android.graphics.Bitmap; |
005 |
import android.graphics.BitmapFactory; |
006 |
import android.graphics.Canvas; |
007 |
import android.graphics.LinearGradient; |
008 |
import android.graphics.Matrix; |
009 |
import android.graphics.Paint; |
010 |
import android.graphics.PorterDuffXfermode; |
011 |
import android.graphics.Bitmap.Config; |
012 |
import android.graphics.PorterDuff.Mode; |
013 |
import android.graphics.Shader.TileMode; |
014 |
import android.graphics.drawable.BitmapDrawable; |
015 |
import android.view.View; |
016 |
import android.view.ViewGroup; |
017 |
import android.widget.BaseAdapter; |
018 |
import android.widget.ImageView; |
020 |
import com.gallery.R; |
022 |
public class ImageAdapter extends BaseAdapter
{ |
023 |
int mGalleryItemBackground; |
024 |
private Context
mContext; |
025 |
private Integer[]
mImageIds = { |
032 |
public ImageAdapter(Context
c) { |
036 |
public int getCount()
{ |
037 |
return mImageIds.length; |
040 |
public Object
getItem( int position)
{ |
044 |
public long getItemId( int position)
{ |
048 |
public View
getView( int position,
View convertView, ViewGroup parent) { |
050 |
ImageView
i = createReflectedImages(mContext,mImageIds[position]); |
052 |
i.setLayoutParams( new CoverFlow.LayoutParams( 120 , 100 )); |
053 |
i.setScaleType(ImageView.ScaleType.CENTER_INSIDE); |
056 |
BitmapDrawable
drawable = (BitmapDrawable) i.getDrawable(); |
057 |
drawable.setAntiAlias( true ); |
061 |
public float getScale( boolean focused, int offset)
{ |
062 |
return Math.max( 0 , 1 .0f
/ ( float )
Math.pow( 2 ,
Math.abs(offset))); |
065 |
public ImageView
createReflectedImages(Context mContext, int imageId)
{ |
067 |
Bitmap
originalImage = BitmapFactory.decodeResource(mContext.getResources(), imageId); |
069 |
final int reflectionGap
= 4 ; |
071 |
int width
= originalImage.getWidth(); |
072 |
int height
= originalImage.getHeight(); |
074 |
Matrix
matrix = new Matrix(); |
075 |
matrix.preScale( 1 ,
- 1 ); |
077 |
Bitmap
reflectionImage = Bitmap.createBitmap(originalImage, 0 , |
078 |
height
/ 2 ,
width, height / 2 ,
matrix, false ); |
080 |
Bitmap
bitmapWithReflection = Bitmap.createBitmap(width, |
081 |
(height
+ height / 2 ),
Config.ARGB_8888); |
083 |
Canvas
canvas = new Canvas(bitmapWithReflection); |
085 |
canvas.drawBitmap(originalImage, 0 , 0 , null ); |
087 |
Paint
deafaultPaint = new Paint(); |
088 |
canvas.drawRect( 0 ,
height, width, height + reflectionGap, deafaultPaint); |
090 |
canvas.drawBitmap(reflectionImage, 0 ,
height + reflectionGap, null ); |
092 |
Paint
paint = new Paint(); |
093 |
LinearGradient
shader = new LinearGradient( 0 ,
originalImage |
094 |
.getHeight(), 0 ,
bitmapWithReflection.getHeight() |
095 |
+
reflectionGap, 0x70ffffff , 0x00ffffff ,
TileMode.MIRROR); |
097 |
paint.setShader(shader); |
099 |
paint.setXfermode( new PorterDuffXfermode(Mode.DST_IN)); |
101 |
canvas.drawRect( 0 ,
height, width, bitmapWithReflection.getHeight() |
102 |
+
reflectionGap, paint); |
104 |
ImageView
imageView = new ImageView(mContext); |
105 |
imageView.setImageBitmap(bitmapWithReflection); |
BitmapDrawable drawable = (BitmapDrawable) i.getDrawable();
drawable.setAntiAlias(true);
是保证图片绕Y旋转了以后不会出现锯齿.
下面是Activity:
01 |
package com.coverflow; |
03 |
import android.app.Activity; |
04 |
import android.graphics.Color; |
05 |
import android.os.Bundle; |
09 |
public class HelloAndroid extends Activity
{ |
10 |
/**
Called when the activity is first created. */ |
12 |
public void onCreate(Bundle
savedInstanceState) { |
13 |
super .onCreate(savedInstanceState); |
15 |
CoverFlow
cf = new CoverFlow( this ); |
17 |
cf.setBackgroundColor(Color.BLACK); |
18 |
cf.setAdapter( new ImageAdapter( this )); |
19 |
ImageAdapter
imageAdapter = new ImageAdapter( this ); |
20 |
cf.setAdapter(imageAdapter); |
23 |
cf.setSelection( 2 , true ); |
24 |
cf.setAnimationDuration( 1000 ); |