栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

Android实现CoverFlow效果控件的实例代码

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android实现CoverFlow效果控件的实例代码

最近研究了一下如何在Android上实现CoverFlow效果的控件,其实早在2010年,就有Neil Davies开发并开源出了这个控件,Neil大神的这篇博客地址。首先是阅读源码,弄明白核心思路后,自己重新写了一遍这个控件,并加入了详尽的注释以便日后查阅;而后在使用过程中,发现了有两点可以改进:

(1)初始图片位于中间,左边空了一半空间,比较难看,可以改为重复滚动地展示;

(2)由于图片一开始就需要加载出来,所以对内存开销较大,很容易OOM,需要对图片的内存空间进行压缩。

这个自定义控件包括4个部分,用于创建及提供图片对象的ImageAdapter,计算图片旋转角度等的自定义控件GalleryFlow,压缩采样率解析Bitmap的工具类BitmapScaleDownUtil,以及承载自定义控件的Gallery3DActivity。

首先是ImageAdapter,代码如下:

 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.Mode;
 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
 {
 
 private final String TAG = "ImageAdapter";
 private Context mContext; 
 //图片数组
 private int[] mImageIds ;
 //图片控件数组
 private ImageView[] mImages;
 //图片控件LayoutParams
 private GalleryFlow.LayoutParams mImagesLayoutParams;
 
 
 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);
 } 
 
 public void createImages(int imageWidth, int imageHeight)
 {
 // 原图与倒影的间距5px
 final int gapHeight = 5; 
 int index = 0;
 for (int imageId : mImageIds)
 {
 
 // 解析原图,生成原图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);
  
 // 创建一个可包含原图+间距+倒影的新图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); 
 
 // 创建一个线性渐变的渲染器用于渲染倒影
 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(Mode.DST_IN));
 // 渲染倒影+间距
 canvas.drawRect(0, height, width, (height + gapHeight + height / 2), paint); 
 
 ImageView imageView = new ImageView(mContext);
 imageView.setImageBitmap(bitmapWithReflection);
 imageView.setLayoutParams(mImagesLayoutParams);
 // 打log
 imageView.setTag(index);
  
 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];
 }
 
 }

其次是GalleryFlow,代码如下:

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;
 
 public class GalleryFlow extends Gallery
 {
 
 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();
 
 
 public GalleryFlow(Context context, AttributeSet attrs)
 {
 super(context, attrs); 
 // 开启,在滑动过程中,回调getChildStaticTransformation()
 this.setStaticTransformationsEnabled(true);
 } 
 
 private int getCenterXOfCoverflow()
 {
 return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();
 } 
 
 private int getCenterXOfView(View childView)
 {
 return childView.getLeft() + childView.getWidth() / 2;
 } 
 
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
 {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
 mGalleryFlowCenterX = getCenterXOfCoverflow();
 Log.d(TAG, "onMeasure, mGalleryFlowCenterX = " + mGalleryFlowCenterX);
 } 
 
 @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);
 } 
 
 @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;
 } 
 
 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;
 } 
 
 private float calculateTranslateDistance(View childView)
 {
 final int childCenterX = getCenterXOfView(childView);
 float translateDistance = 0; 
 if (mGalleryFlowCenterX == childCenterX)
 {
 translateDistance = MAX_TRANSLATE_DISTANCE;
 } 
 return 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(); 
 
 // 在Y轴上旋转,位于中心的图片不旋转,中心两侧的图片竖向向里或向外翻转。
 mCamera.rotateY(rotationAngle);
 
  
 // 在Z轴上前置,位于中心的图片会有放大的效果
 mCamera.translate(0, 0, translateDistance);
  
 // 开始变换(我的理解是:移动Camera,在2D视图上产生3D效果)
 mCamera.getMatrix(imageMatrix);
 imageMatrix.preTranslate(-imageWidth / 2, -imageHeight / 2);
 imageMatrix.postTranslate(imageWidth / 2, imageHeight / 2); 
 mCamera.restore();
 }
 
 }

Bitmap解析用具BitmapScaleDownUtil,代码如下:

 package pym.test.gallery3d.util;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.view.Display;
 
 public class BitmapScaleDownUtil
 {
 
 private final String TAG = "BitmapScaleDownUtil";
  
 
 
 public static int[] getScreenDimension(Display display)
 {
 int[] dimension = new int[2];
 dimension[0] = display.getWidth();
 dimension[1] = display.getHeight(); 
 return dimension;
 } 

 
 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);
 }
 
 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;
 }
 
 }

测试控件的Gallery3DActivity,代码如下:

 package pym.test.gallery3d.main;
 import pym.test.gallery3d.R;
 import pym.test.gallery3d.util.BitmapScaleDownUtil;
 import pym.test.gallery3d.widget.GalleryFlow;
 import pym.test.gallery3d.widget.ImageAdapter;
 import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle; 
 
 public class Gallery3DActivity extends Activity
 {
 
 private final String TAG = "Gallery3DActivity";
 private Context mContext;
 // 图片缩放倍率(相对屏幕尺寸的缩小倍率)
 public static final int SCALE_FACTOR = 8; 
 // 图片间距(控制各图片之间的距离)
 private final int GALLERY_SPACING = -10;
 // 控件
 private GalleryFlow mGalleryFlow;
  
 
 @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);
 }
 
 }

see效果图~~~

 

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对考高分网的支持。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/156221.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号