├── images └── 0.jpg ├── res ├── drawable-normal │ ├── a.jpg │ ├── b.jpg │ ├── c.jpg │ ├── d.jpg │ ├── e.jpg │ ├── f.jpg │ ├── g.jpg │ ├── h.jpg │ ├── i.jpg │ ├── j.jpg │ ├── k.jpg │ ├── l.jpg │ └── m.jpg ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-ldpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── values │ └── strings.xml └── layout │ └── main.xml ├── lib └── universal-image-loader-1.8.6.jar ├── README.md ├── .settings └── org.eclipse.jdt.core.prefs ├── project.properties ├── .classpath ├── src └── com │ └── demo │ └── coverflow │ ├── MyApp.java │ ├── CoverflowDemoActivity.java │ ├── ImageLoaderUtils.java │ ├── CoverFlow.java │ └── ImageAdapter.java ├── AndroidManifest.xml ├── .project └── proguard.cfg /images/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/images/0.jpg -------------------------------------------------------------------------------- /res/drawable-normal/a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/a.jpg -------------------------------------------------------------------------------- /res/drawable-normal/b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/b.jpg -------------------------------------------------------------------------------- /res/drawable-normal/c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/c.jpg -------------------------------------------------------------------------------- /res/drawable-normal/d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/d.jpg -------------------------------------------------------------------------------- /res/drawable-normal/e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/e.jpg -------------------------------------------------------------------------------- /res/drawable-normal/f.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/f.jpg -------------------------------------------------------------------------------- /res/drawable-normal/g.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/g.jpg -------------------------------------------------------------------------------- /res/drawable-normal/h.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/h.jpg -------------------------------------------------------------------------------- /res/drawable-normal/i.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/i.jpg -------------------------------------------------------------------------------- /res/drawable-normal/j.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/j.jpg -------------------------------------------------------------------------------- /res/drawable-normal/k.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/k.jpg -------------------------------------------------------------------------------- /res/drawable-normal/l.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/l.jpg -------------------------------------------------------------------------------- /res/drawable-normal/m.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-normal/m.jpg -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/universal-image-loader-1.8.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/CoverFlow/HEAD/lib/universal-image-loader-1.8.6.jar -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CoverFlow 2 | Infinite loop photo wall, which support sliding around(无限循环照片墙,支持左右滑动) 3 | 效果图: 4 | ![Alt text](https://github.com/xuningjack/CoverFlow/raw/master/images/0.jpg) 5 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 3 | org.eclipse.jdt.core.compiler.compliance=1.6 4 | org.eclipse.jdt.core.compiler.source=1.6 5 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hello World, CoverflowDemoActivity! 5 | CoverflowDemo 6 | 7 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system use, 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | 10 | # Project target. 11 | target=android-14 12 | -------------------------------------------------------------------------------- /res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/com/demo/coverflow/MyApp.java: -------------------------------------------------------------------------------- 1 | package com.demo.coverflow; 2 | 3 | import com.nostra13.universalimageloader.core.ImageLoader; 4 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; 5 | 6 | import android.app.Application; 7 | import android.util.DisplayMetrics; 8 | 9 | public class MyApp extends Application { 10 | 11 | @Override 12 | public void onCreate() { 13 | 14 | super.onCreate(); 15 | //注册ImageLoader 16 | DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics(); 17 | ImageLoaderConfiguration config = ImageLoaderUtils.getApplicationOptions(displayMetrics.widthPixels , displayMetrics.heightPixels, getApplicationContext()); 18 | ImageLoader.getInstance().init(config); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/demo/coverflow/CoverflowDemoActivity.java: -------------------------------------------------------------------------------- 1 | package com.demo.coverflow; 2 | 3 | import android.app.Activity; 4 | 5 | import android.graphics.Color; 6 | import android.os.Bundle; 7 | 8 | /** 9 | * 主界面 10 | * @author Jack 11 | * @version 创建时间:2013-10-31 下午2:13:47 12 | */ 13 | public class CoverflowDemoActivity extends Activity { 14 | 15 | @Override 16 | public void onCreate(Bundle savedInstanceState) { 17 | 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.main); 20 | CoverFlow cf = new CoverFlow(this); 21 | cf.setBackgroundColor(Color.BLACK); 22 | cf.setAdapter(new ImageAdapter(this)); 23 | ImageAdapter imageAdapter = new ImageAdapter(this); 24 | cf.setAdapter(imageAdapter); 25 | // cf.setAlphaMode(false); //两边未selected的图片不透明 26 | // cf.setCircleMode(false); 27 | cf.setSelection(Integer.MAX_VALUE / 2, true); 28 | cf.setAnimationDuration(1000); 29 | setContentView(cf); 30 | } 31 | } -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Android_Coverflow 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /proguard.cfg: -------------------------------------------------------------------------------- 1 | -optimizationpasses 5 2 | -dontusemixedcaseclassnames 3 | -dontskipnonpubliclibraryclasses 4 | -dontpreverify 5 | -verbose 6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 7 | 8 | -keep public class * extends android.app.Activity 9 | -keep public class * extends android.app.Application 10 | -keep public class * extends android.app.Service 11 | -keep public class * extends android.content.BroadcastReceiver 12 | -keep public class * extends android.content.ContentProvider 13 | -keep public class * extends android.app.backup.BackupAgentHelper 14 | -keep public class * extends android.preference.Preference 15 | -keep public class com.android.vending.licensing.ILicensingService 16 | 17 | -keepclasseswithmembernames class * { 18 | native ; 19 | } 20 | 21 | -keepclasseswithmembers class * { 22 | public (android.content.Context, android.util.AttributeSet); 23 | } 24 | 25 | -keepclasseswithmembers class * { 26 | public (android.content.Context, android.util.AttributeSet, int); 27 | } 28 | 29 | -keepclassmembers class * extends android.app.Activity { 30 | public void *(android.view.View); 31 | } 32 | 33 | -keepclassmembers enum * { 34 | public static **[] values(); 35 | public static ** valueOf(java.lang.String); 36 | } 37 | 38 | -keep class * implements android.os.Parcelable { 39 | public static final android.os.Parcelable$Creator *; 40 | } 41 | -------------------------------------------------------------------------------- /src/com/demo/coverflow/ImageLoaderUtils.java: -------------------------------------------------------------------------------- 1 | package com.demo.coverflow; 2 | 3 | import java.io.File; 4 | import android.content.Context; 5 | 6 | import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; 7 | import com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache; 8 | import com.nostra13.universalimageloader.core.DisplayImageOptions; 9 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; 10 | import com.nostra13.universalimageloader.core.assist.QueueProcessingType; 11 | import com.nostra13.universalimageloader.utils.StorageUtils; 12 | 13 | /** 14 | * 图片加载配置工具类 15 | * @author nick 16 | */ 17 | public class ImageLoaderUtils { 18 | 19 | public static ImageLoaderConfiguration getApplicationOptions(int width,int height,Context context){ 20 | 21 | File cacheDir = StorageUtils.getCacheDirectory(context); 22 | ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context) 23 | .threadPoolSize(5) // default 24 | .tasksProcessingOrder(QueueProcessingType.FIFO) // default 25 | .memoryCache(new LruMemoryCache(4 * 1024 * 1024)) 26 | .memoryCacheSize(4 * 1024 * 1024) 27 | .discCache(new UnlimitedDiscCache(cacheDir)) // default 28 | .discCacheSize(50 * 1024 * 1024) 29 | .discCacheFileCount(100) 30 | .writeDebugLogs() 31 | .build(); 32 | return config; 33 | } 34 | 35 | /** 36 | * 默认配置 37 | * @return 38 | */ 39 | public static DisplayImageOptions getDefaultOptions(){ 40 | DisplayImageOptions options = new DisplayImageOptions.Builder() 41 | .cacheInMemory(true) 42 | .cacheOnDisc(true) 43 | .build(); 44 | return options; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/com/demo/coverflow/CoverFlow.java: -------------------------------------------------------------------------------- 1 | package com.demo.coverflow; 2 | 3 | import android.content.Context; 4 | import android.graphics.Camera; 5 | import android.graphics.Matrix; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | import android.view.animation.Transformation; 9 | import android.widget.Gallery; 10 | import android.widget.ImageView; 11 | 12 | /** 13 | * 自定义gallery,未被选中项有角度的显示 14 | * @author Jack 15 | * @version 创建时间:2013-10-31 下午12:58:45 16 | */ 17 | public class CoverFlow extends Gallery { 18 | 19 | private Camera mCamera = new Camera(); 20 | private int mMaxRotationAngle = 50; 21 | private int mMaxZoom = -380; 22 | private int mCoveflowCenter; 23 | private boolean mAlphaMode = true; 24 | private boolean mCircleMode = false; 25 | 26 | /**构造方法必须有一个*/ 27 | public CoverFlow(Context context) { 28 | 29 | super(context); 30 | this.setStaticTransformationsEnabled(true); 31 | } 32 | 33 | public boolean getCircleMode() { 34 | 35 | return mCircleMode; 36 | } 37 | 38 | /** 39 | * 获得中间的图片的位置(带有左边距的) 40 | * @return 41 | */ 42 | private int getCenterOfCoverflow() { 43 | 44 | return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft(); 45 | } 46 | 47 | /** 48 | * 获得view的中间位置 49 | * @param view 50 | * @return 51 | */ 52 | private static int getCenterOfView(View view) { 53 | 54 | return view.getLeft() + view.getWidth() / 2; 55 | } 56 | 57 | protected boolean getChildStaticTransformation(View child, Transformation t) { 58 | 59 | final int childCenter = getCenterOfView(child); 60 | final int childWidth = child.getWidth(); 61 | int rotationAngle = 0; 62 | t.clear(); 63 | t.setTransformationType(Transformation.TYPE_MATRIX); 64 | if (childCenter == mCoveflowCenter) { 65 | 66 | transformImageBitmap((ImageView) child, t, 0); 67 | } else { 68 | 69 | rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle); 70 | if (Math.abs(rotationAngle) > mMaxRotationAngle) { 71 | 72 | rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle; 73 | } 74 | transformImageBitmap((ImageView) child, t, rotationAngle); 75 | } 76 | return true; 77 | } 78 | 79 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 80 | 81 | mCoveflowCenter = getCenterOfCoverflow(); 82 | super.onSizeChanged(w, h, oldw, oldh); 83 | } 84 | 85 | private void transformImageBitmap(ImageView child, Transformation t, int rotationAngle) { 86 | 87 | mCamera.save(); 88 | final Matrix imageMatrix = t.getMatrix(); 89 | final int imageHeight = child.getLayoutParams().height; 90 | final int imageWidth = child.getLayoutParams().width; 91 | final int rotation = Math.abs(rotationAngle); 92 | //平移变换,x,y,z三轴 93 | mCamera.translate(0.0f, 0.0f, 0.0f); 94 | // 如视图的角度变小,放大  95 | if (rotation <= mMaxRotationAngle) { 96 | 97 | float zoomAmount = (float) (mMaxZoom + (rotation * 1.5)); 98 | mCamera.translate(0.0f, 0.0f, zoomAmount); 99 | if (mCircleMode) {//改变角度 100 | 101 | if (rotation < 40) 102 | mCamera.translate(0.0f, 155, 0.0f); 103 | else 104 | mCamera.translate(0.0f, (255 - rotation * 2.5f), 0.0f); 105 | } 106 | if (mAlphaMode) {//改变透明度 107 | 108 | ((ImageView) (child)).setAlpha((int) (255 - rotation * 2.5)); 109 | } 110 | } 111 | mCamera.rotateY(rotationAngle); 112 | mCamera.getMatrix(imageMatrix); 113 | imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2)); 114 | imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2)); 115 | mCamera.restore(); 116 | } 117 | } -------------------------------------------------------------------------------- /src/com/demo/coverflow/ImageAdapter.java: -------------------------------------------------------------------------------- 1 | package com.demo.coverflow; 2 | 3 | import com.nostra13.universalimageloader.core.ImageLoader; 4 | import com.nostra13.universalimageloader.core.assist.FailReason; 5 | import com.nostra13.universalimageloader.core.assist.ImageLoadingListener; 6 | 7 | import android.content.Context; 8 | import android.graphics.Bitmap; 9 | import android.graphics.Bitmap.Config; 10 | import android.graphics.Canvas; 11 | import android.graphics.LinearGradient; 12 | import android.graphics.Matrix; 13 | import android.graphics.Paint; 14 | import android.graphics.PorterDuff.Mode; 15 | import android.graphics.PorterDuffXfermode; 16 | import android.graphics.Shader.TileMode; 17 | import android.graphics.drawable.BitmapDrawable; 18 | import android.view.View; 19 | import android.view.ViewGroup; 20 | import android.widget.BaseAdapter; 21 | import android.widget.ImageView; 22 | 23 | 24 | /** 25 | * CoverFlow的Adapter 26 | * @author Jack 27 | * @version 创建时间:2013-10-31 下午4:16:17 28 | */ 29 | public class ImageAdapter extends BaseAdapter { 30 | 31 | int mGalleryItemBackground; 32 | private Context mContext; 33 | /*private Integer[] mImageIds = { R.drawable.a, R.drawable.b, 34 | R.drawable.c, R.drawable.d, R.drawable.e, R.drawable.f, 35 | R.drawable.g, R.drawable.h, R.drawable.i, R.drawable.j 36 | , R.drawable.k, R.drawable.l, R.drawable.m};*/ 37 | private String[] mImageUrls = {"http://img0.pcgames.com.cn/pcgames/1408/02/4162655_IMG_9462.jpg", 38 | "http://img0.pcgames.com.cn/pcgames/1408/02/4162655_IMG_9466_thumb.jpg", 39 | "http://img0.pcgames.com.cn/pcgames/1408/02/4162655_IMG_9478_thumb.jpg", 40 | "http://img0.pcgames.com.cn/pcgames/1408/02/4162655_IMG_9504_thumb.jpg", 41 | "http://img0.pcgames.com.cn/pcgames/1408/02/4162655_IMG_9552_thumb.jpg", 42 | "http://img0.pcgames.com.cn/pcgames/1408/02/4162655_IMG_9581_thumb.jpg"}; 43 | 44 | public ImageAdapter(Context c) { 45 | mContext = c; 46 | } 47 | 48 | @Override 49 | public int getCount() { 50 | return Integer.MAX_VALUE; 51 | } 52 | 53 | @Override 54 | public Object getItem(int position) { 55 | return position; 56 | } 57 | 58 | @Override 59 | public long getItemId(int position) { 60 | return position; 61 | } 62 | 63 | @Override 64 | public View getView(int position, View convertView, ViewGroup parent) { 65 | ImageView imageView = createReflectedImages(mContext, mImageUrls[position % mImageUrls.length]); 66 | imageView.setLayoutParams(new CoverFlow.LayoutParams(120, 100)); 67 | imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); 68 | return imageView; 69 | } 70 | 71 | 72 | /** 73 | * 倒影处理逻辑 74 | * @param mContext 75 | * @param imageUrl 76 | * @return 77 | */ 78 | public ImageView createReflectedImages(Context mContext, String imageUrl) { 79 | ImageView imageView = new ImageView(mContext); 80 | ImageLoader.getInstance().displayImage(imageUrl, imageView, ImageLoaderUtils.getDefaultOptions(), new ImageLoadingListener() { 81 | 82 | @Override 83 | public void onLoadingStarted(String arg0, View arg1) { 84 | 85 | } 86 | 87 | @Override 88 | public void onLoadingFailed(String arg0, View arg1, FailReason arg2) { 89 | 90 | } 91 | 92 | @Override 93 | public void onLoadingComplete(String url, View imageView, Bitmap originalImage) { 94 | final int REFLECTIONGAP = 4; 95 | int width = originalImage.getWidth(); 96 | int height = originalImage.getHeight(); 97 | 98 | //Matrix 旋转、镜像处理的矩阵类 99 | Matrix matrix = new Matrix(); 100 | matrix.preScale(1, -1); 101 | Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height / 2, width, height / 2, matrix, false); 102 | Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height / 2), Config.ARGB_8888); 103 | Canvas canvas = new Canvas(bitmapWithReflection); 104 | canvas.drawBitmap(originalImage, 0, 0, null); 105 | Paint deafaultPaint = new Paint(); 106 | canvas.drawRect(0, height, width, height + REFLECTIONGAP, deafaultPaint); 107 | canvas.drawBitmap(reflectionImage, 0, height + REFLECTIONGAP, null); 108 | Paint paint = new Paint(); 109 | //线性渐变 110 | LinearGradient shader = new LinearGradient(0, 111 | originalImage.getHeight(), 0, bitmapWithReflection.getHeight() 112 | + REFLECTIONGAP, 0x70ffffff, 0x00ffffff, TileMode.MIRROR); 113 | paint.setShader(shader); 114 | //设置两张图片相交时的模式 ,倒影图片隐藏一部分 115 | paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); 116 | //按照设置绘制倒影图片 117 | canvas.drawRect(0, height, width, bitmapWithReflection.getHeight() + REFLECTIONGAP, paint); 118 | ((ImageView)imageView).setImageBitmap(bitmapWithReflection); 119 | // 设置的抗锯齿 120 | BitmapDrawable drawable = (BitmapDrawable) ((ImageView)imageView).getDrawable(); 121 | drawable.setAntiAlias(true); 122 | } 123 | 124 | @Override 125 | public void onLoadingCancelled(String arg0, View arg1) { 126 | } 127 | }); 128 | return imageView; 129 | } 130 | } 131 | --------------------------------------------------------------------------------