先上一张效果图:
上代码,看了代码什么都明白
CoverFlow从Gallery继承过来
001 | package com.coverflow; |
002 | |
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; |
011 | |
012 | public class CoverFlow extends Gallery { |
013 | |
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 ; |
020 | |
021 | public CoverFlow(Context context) { |
022 | super (context); |
023 | this .setStaticTransformationsEnabled( true ); |
024 | } |
025 | |
026 | public CoverFlow(Context context, AttributeSet attrs) { |
027 | super (context, attrs); |
028 | this .setStaticTransformationsEnabled( true ); |
029 | } |
030 | |
031 | public CoverFlow(Context context, AttributeSet attrs, int defStyle) { |
032 | super (context, attrs, defStyle); |
033 | this .setStaticTransformationsEnabled( true ); |
034 | } |
035 | |
036 | public int getMaxRotationAngle() { |
037 | return mMaxRotationAngle; |
038 | } |
039 | |
040 | public void setMaxRotationAngle( int maxRotationAngle) { |
041 | mMaxRotationAngle = maxRotationAngle; |
042 | } |
043 | |
044 | public boolean getCircleMode() { |
045 | return mCircleMode; |
046 | } |
047 | |
048 | public void setCircleMode( boolean isCircle) { |
049 | mCircleMode = isCircle; |
050 | } |
051 | |
052 | public boolean getAlphaMode() { |
053 | return mAlphaMode; |
054 | } |
055 | |
056 | public void setAlphaMode( boolean isAlpha) { |
057 | mAlphaMode = isAlpha; |
058 | } |
059 | |
060 | public int getMaxZoom() { |
061 | return mMaxZoom; |
062 | } |
063 | |
064 | public void setMaxZoom( int maxZoom) { |
065 | mMaxZoom = maxZoom; |
066 | } |
067 | |
068 | private int getCenterOfCoverflow() { |
069 | return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 |
070 | + getPaddingLeft(); |
071 | } |
072 | |
073 | private static int getCenterOfView(View view) { |
074 | return view.getLeft() + view.getWidth() / 2 ; |
075 | } |
076 | |
077 | protected boolean getChildStaticTransformation(View child, Transformation t) { |
078 | final int childCenter = getCenterOfView(child); |
079 | final int childWidth = child.getWidth(); |
080 | int rotationAngle = 0 ; |
081 | t.clear(); |
082 | t.setTransformationType(Transformation.TYPE_MATRIX); |
083 | if (childCenter == mCoveflowCenter) { |
084 | transformImageBitmap((ImageView) child, t, 0 ); |
085 | } else { |
086 | rotationAngle = ( int ) ((( float ) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle); |
087 | if (Math.abs(rotationAngle) > mMaxRotationAngle) { |
088 | rotationAngle = (rotationAngle < 0 ) ? -mMaxRotationAngle |
089 | : mMaxRotationAngle; |
090 | } |
091 | transformImageBitmap((ImageView) child, t, rotationAngle); |
092 | } |
093 | return true ; |
094 | } |
095 | |
096 | /** |
097 | * 这就是所谓的在大小的布局时,这一观点已经发生了改变。如果 你只是添加到视图层次,有人叫你旧的观念 价值观为0。 |
098 | * |
099 | * @param w |
100 | * Current width of this view. |
101 | * @param h |
102 | * Current height of this view. |
103 | * @param oldw |
104 | * Old width of this view. |
105 | * @param oldh |
106 | * Old height of this view. |
107 | */ |
108 | protected void onSizeChanged( int w, int h, int oldw, int oldh) { |
109 | mCoveflowCenter = getCenterOfCoverflow(); |
110 | super .onSizeChanged(w, h, oldw, oldh); |
111 | } |
112 | |
113 | /** |
114 | * 把图像位图的角度通过 |
115 | * |
116 | * @param imageView |
117 | * ImageView the ImageView whose bitmap we want to rotate |
118 | * @param t |
119 | * transformation |
120 | * @param rotationAngle |
121 | * the Angle by which to rotate the Bitmap |
122 | */ |
123 | private void transformImageBitmap(ImageView child, Transformation t, |
124 | int rotationAngle) { |
125 | mCamera.save(); |
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); |
131 | |
132 | // 如视图的角度更少,放大 |
133 | if (rotation <= mMaxRotationAngle) { |
134 | float zoomAmount = ( float ) (mMaxZoom + (rotation * 1.5 )); |
135 | mCamera.translate( 0 .0f, 0 .0f, zoomAmount); |
136 | if (mCircleMode) { |
137 | if (rotation < 40 ) |
138 | mCamera.translate( 0 .0f, 155 , 0 .0f); |
139 | else |
140 | mCamera.translate( 0 .0f, ( 255 - rotation * 2 .5f), 0 .0f); |
141 | } |
142 | if (mAlphaMode) { |
143 | ((ImageView) (child)).setAlpha(( int ) ( 255 - rotation * 2.5 )); |
144 | } |
145 | } |
146 | mCamera.rotateY(rotationAngle); |
147 | mCamera.getMatrix(imageMatrix); |
148 | imageMatrix.preTranslate(-(imageWidth / 2 ), -(imageHeight / 2 )); |
149 | imageMatrix.postTranslate((imageWidth / 2 ), (imageHeight / 2 )); |
150 | mCamera.restore(); |
151 | } |
152 | } |
这个就是CoverFlow类,说明几点:
1. 成员函数mCamera是用来做类3D效果处理,比如z轴方向上的平移,绕y轴的旋转等mMaxRotationAngle是图片绕y轴最大旋转角度,也就是屏幕最边上那两张图片的旋转角度mMaxZoom是图片在z轴平移的距离,视觉上看起来就是放大缩小的效果.其他的变量都可以无视也就是说把这个属性设成true的时候每次viewGroup(看Gallery的源码就可以看到它是从ViewGroup间接继承过来的)在重新画它的child的时候都会促发getChildStaticTransformation这个函数,所以我们只需要在这个函数里面去加上旋转和放大的操作就可以了其他的getter和setter函数都可以无视ImageAdapter适配器:001 | package com.coverflow; |
002 | |
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; |
019 | |
020 | import com.gallery.R; |
021 | |
022 | public class ImageAdapter extends BaseAdapter { |
023 | int mGalleryItemBackground; |
024 | private Context mContext; |
025 | private Integer[] mImageIds = { |
026 | R.drawable.a1, |
027 | R.drawable.a2, |
028 | R.drawable.a3, |
029 | R.drawable.a4, |
030 | R.drawable.a5 }; |
031 | |
032 | public ImageAdapter(Context c) { |
033 | mContext = c; |
034 | } |
035 | |
036 | public int getCount() { |
037 | return mImageIds.length; |
038 | } |
039 | |
040 | public Object getItem( int position) { |
041 | return position; |
042 | } |
043 | |
044 | public long getItemId( int position) { |
045 | return position; |
046 | } |
047 | |
048 | public View getView( int position, View convertView, ViewGroup parent) { |
049 | |
050 | ImageView i = createReflectedImages(mContext,mImageIds[position]); |
051 | |
052 | i.setLayoutParams( new CoverFlow.LayoutParams( 120 , 100 )); |
053 | i.setScaleType(ImageView.ScaleType.CENTER_INSIDE); |
054 | |
055 | // 设置的抗锯齿 |
056 | BitmapDrawable drawable = (BitmapDrawable) i.getDrawable(); |
057 | drawable.setAntiAlias( true ); |
058 | return i; |
059 | } |
060 | |
061 | public float getScale( boolean focused, int offset) { |
062 | return Math.max( 0 , 1 .0f / ( float ) Math.pow( 2 , Math.abs(offset))); |
063 | } |
064 | |
065 | public ImageView createReflectedImages(Context mContext, int imageId) { |
066 | |
067 | Bitmap originalImage = BitmapFactory.decodeResource(mContext.getResources(), imageId); |
068 | |
069 | final int reflectionGap = 4 ; |
070 | |
071 | int width = originalImage.getWidth(); |
072 | int height = originalImage.getHeight(); |
073 | |
074 | Matrix matrix = new Matrix(); |
075 | matrix.preScale( 1 , - 1 ); |
076 | |
077 | Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0 , |
078 | height / 2 , width, height / 2 , matrix, false ); |
079 | |
080 | Bitmap bitmapWithReflection = Bitmap.createBitmap(width, |
081 | (height + height / 2 ), Config.ARGB_8888); |
082 | |
083 | Canvas canvas = new Canvas(bitmapWithReflection); |
084 | |
085 | canvas.drawBitmap(originalImage, 0 , 0 , null ); |
086 | |
087 | Paint deafaultPaint = new Paint(); |
088 | canvas.drawRect( 0 , height, width, height + reflectionGap, deafaultPaint); |
089 | |
090 | canvas.drawBitmap(reflectionImage, 0 , height + reflectionGap, null ); |
091 | |
092 | Paint paint = new Paint(); |
093 | LinearGradient shader = new LinearGradient( 0 , originalImage |
094 | .getHeight(), 0 , bitmapWithReflection.getHeight() |
095 | + reflectionGap, 0x70ffffff , 0x00ffffff , TileMode.MIRROR); |
096 | |
097 | paint.setShader(shader); |
098 | |
099 | paint.setXfermode( new PorterDuffXfermode(Mode.DST_IN)); |
100 | |
101 | canvas.drawRect( 0 , height, width, bitmapWithReflection.getHeight() |
102 | + reflectionGap, paint); |
103 | |
104 | ImageView imageView = new ImageView(mContext); |
105 | imageView.setImageBitmap(bitmapWithReflection); |
106 | |
107 | return imageView; |
108 | } |
109 | |
110 | } |
BitmapDrawable drawable = (BitmapDrawable) i.getDrawable(); drawable.setAntiAlias(true);是保证图片绕Y旋转了以后不会出现锯齿.
下面是Activity:01 | package com.coverflow; |
02 | |
03 | import android.app.Activity; |
04 | import android.graphics.Color; |
05 | import android.os.Bundle; |
06 | |
07 | import com.gallery.R; |
08 | |
09 | public class HelloAndroid extends Activity { |
10 | /** Called when the activity is first created. */ |
11 | @Override |
12 | public void onCreate(Bundle savedInstanceState) { |
13 | super .onCreate(savedInstanceState); |
14 | |
15 | CoverFlow cf = new CoverFlow( this ); |
16 | // cf.setBackgroundResource(R.drawable.shape); |
17 | cf.setBackgroundColor(Color.BLACK); |
18 | cf.setAdapter( new ImageAdapter( this )); |
19 | ImageAdapter imageAdapter = new ImageAdapter( this ); |
20 | cf.setAdapter(imageAdapter); |
21 | // cf.setAlphaMode(false); |
22 | // cf.setCircleMode(false); |
23 | cf.setSelection( 2 , true ); |
24 | cf.setAnimationDuration( 1000 ); |
25 | setContentView(cf); |
26 | } |
27 | |
28 | } |
参考自:
http://www.eoeandroid.com/thread-70209-1-1.htmlhttp://www.apkbus.com/android-18441-1-1.html