91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android實現CoverFlow效果控件的實例代碼

發布時間:2020-09-11 14:23:17 來源:腳本之家 閱讀:147 作者:熱氣球 欄目:移動開發

最近研究了一下如何在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;
 /**
 * @author pengyiming
 * @date 2013-9-30
 * @function GalleryFlow適配器
 */
 public class ImageAdapter extends BaseAdapter
 {
 /* 數據段begin */
 private final String TAG = "ImageAdapter";
 private Context mContext; 
 //圖片數組
 private int[] mImageIds ;
 //圖片控件數組
 private ImageView[] mImages;
 //圖片控件LayoutParams
 private GalleryFlow.LayoutParams mImagesLayoutParams;
 /* 數據段end */
 /* 函數段begin */
 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);
 } 
 /**
 * @function 根據指定寬高創建待繪制的Bitmap,并繪制到ImageView控件上
 * @param imageWidth
 * @param imageHeight
 * @return void
 */
 public void createImages(int imageWidth, int imageHeight)
 {
 // 原圖與倒影的間距5px
 final int gapHeight = 5; 
 int index = 0;
 for (int imageId : mImageIds)
 {
 /* step1 采樣方式解析原圖并生成倒影 */
 // 解析原圖,生成原圖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);
  /* step2 繪制 */
 // 創建一個可包含原圖+間距+倒影的新圖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); 
 /* step3 渲染 */
 // 創建一個線性漸變的渲染器用于渲染倒影
 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); 
 /* step4 在ImageView控件上繪制 */
 ImageView imageView = new ImageView(mContext);
 imageView.setImageBitmap(bitmapWithReflection);
 imageView.setLayoutParams(mImagesLayoutParams);
 // 打log
 imageView.setTag(index);
  /* step5 釋放heap */
 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];
 }
 /* 函數段end */
 }

其次是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;
 /**
 * @author pengyiming
 * @date 2013-9-30
 * @function 自定義控件
 */
 public class GalleryFlow extends Gallery
 {
 /* 數據段begin */
 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();
 /* 數據段end */
 /* 函數段begin */
 public GalleryFlow(Context context, AttributeSet attrs)
 {
 super(context, attrs); 
 // 開啟,在滑動過程中,回調getChildStaticTransformation()
 this.setStaticTransformationsEnabled(true);
 } 
 /**
 * @function 獲取GalleryFlow中心X坐標
 * @return
 */
 private int getCenterXOfCoverflow()
 {
 return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();
 } 
 /**
 * @function 獲取GalleryFlow子view的中心X坐標
 * @param childView
 * @return
 */
 private int getCenterXOfView(View childView)
 {
 return childView.getLeft() + childView.getWidth() / 2;
 } 
 /**
 * @note step1 系統調用measure()方法時,回調此方法;表明此時系統正在計算view的大小
 */
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
 {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
 mGalleryFlowCenterX = getCenterXOfCoverflow();
 Log.d(TAG, "onMeasure, mGalleryFlowCenterX = " + mGalleryFlowCenterX);
 } 
 /**
 * @note step2 系統調用layout()方法時,回調此方法;表明此時系統正在給child view分配空間
 * @note 必定在onMeasure()之后回調,但與onSizeChanged()先后順序不一定
 */
 @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);
 } 
 /**
 * @note step2 系統調用measure()方法后,當需要繪制此view時,回調此方法;表明此時系統已計算完view的大小
 * @note 必定在onMeasure()之后回調,但與onSizeChanged()先后順序不一定
 */
 @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;
 } 
 /**
 * @function 計算GalleryFlow子view的旋轉角度
 * @note1 位于Gallery中心的圖片不旋轉
 * @note2 位于Gallery中心兩側的圖片按照離中心點的距離旋轉
 * @param childView
 * @return
 */
 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;
 } 
 /**
 * @function 計算GalleryFlow子view的前置距離
 * @note1 位于Gallery中心的圖片前置
 * @note2 位于Gallery中心兩側的圖片不前置
 * @param childView
 * @return
 */
 private float calculateTranslateDistance(View childView)
 {
 final int childCenterX = getCenterXOfView(childView);
 float translateDistance = 0; 
 if (mGalleryFlowCenterX == childCenterX)
 {
 translateDistance = MAX_TRANSLATE_DISTANCE;
 } 
 return translateDistance;
 } 
 /**
 * @function 開始變換GalleryFlow子view
 * @param childView
 * @param t
 * @param rotationAngle
 * @param 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(); 
 /* rotateY */
 // 在Y軸上旋轉,位于中心的圖片不旋轉,中心兩側的圖片豎向向里或向外翻轉。
 mCamera.rotateY(rotationAngle);
 /* rotateY */
  /* translateZ */
 // 在Z軸上前置,位于中心的圖片會有放大的效果
 mCamera.translate(0, 0, translateDistance);
 /* translateZ */ 
 // 開始變換(我的理解是:移動Camera,在2D視圖上產生3D效果)
 mCamera.getMatrix(imageMatrix);
 imageMatrix.preTranslate(-imageWidth / 2, -imageHeight / 2);
 imageMatrix.postTranslate(imageWidth / 2, imageHeight / 2); 
 mCamera.restore();
 }
 /* 函數段end */
 }

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

 package pym.test.gallery3d.util;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.view.Display;
 /**
 * @author pengyiming
 * @date 2013-9-30
 * @function Bitmap縮放處理工具類
 */
 public class BitmapScaleDownUtil
 {
 /* 數據段begin */
 private final String TAG = "BitmapScaleDownUtil";
 /* 數據段end */ 
 /* 函數段begin */
 /**
 * @function 獲取屏幕大小
 * @param display
 * @return 屏幕寬高
 */
 public static int[] getScreenDimension(Display display)
 {
 int[] dimension = new int[2];
 dimension[0] = display.getWidth();
 dimension[1] = display.getHeight(); 
 return dimension;
 } 

 /**
 * @function 以取樣方式加載Bitmap 
 * @param res
 * @param resId
 * @param reqWidth
 * @param reqHeight
 * @return 取樣后的Bitmap
 */
 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);
 }
 /**
 * @function 計算Bitmap取樣比例
 * @param options
 * @param reqWidth
 * @param reqHeight
 * @return 取樣比例
 */
 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;
 }
 /* 函數段end */
 }

測試控件的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; 
 /**
 * @author pengyiming
 * @date 2013-9-30
 */
 public class Gallery3DActivity extends Activity
 {
 /* 數據段begin */
 private final String TAG = "Gallery3DActivity";
 private Context mContext;
 // 圖片縮放倍率(相對屏幕尺寸的縮小倍率)
 public static final int SCALE_FACTOR = 8; 
 // 圖片間距(控制各圖片之間的距離)
 private final int GALLERY_SPACING = -10;
 // 控件
 private GalleryFlow mGalleryFlow;
 /* 數據段end */ 
 /* 函數段begin */
 @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);
 }
 /* 函數段end */
 }

see效果圖~~~

Android實現CoverFlow效果控件的實例代碼 

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

通海县| 葫芦岛市| 鄂托克前旗| 西充县| 桦南县| 社会| 南靖县| 萨嘎县| 紫金县| 关岭| 六安市| 民县| 和静县| 利津县| 长顺县| 蒙自县| 万盛区| 玛多县| 策勒县| 北川| 乌鲁木齐市| 铁力市| 芮城县| 萨迦县| 新宾| 田阳县| 鱼台县| 曲水县| 永州市| 宜阳县| 曲靖市| 桦川县| 北海市| 新晃| 左权县| 普宁市| 杭锦后旗| 南岸区| 固原市| 阿图什市| 淳安县|