Android的OpenGL FlowCover

有两种,一种是直接继承Gallery的,通过override Gallery的getChildStaticTransformation方法实现,这个网上有,速度还不错,最开始采用的这个方案。

后来有时间,又觉得opengl可能会更快一些,所以照着iOS上很著名的FlowCover写了一个。两个的代码都贴出来吧,仅供参考。

 

第一种:

继承Gallery,重载getChildStaticTransformation函数,通过Camera来模拟变换,加了一些平移和旋转。

这个我当时碰到的主要问题在于怎么才能让距离比较合适,因为需要左右两边的几个最后能够叠在一起,所以需要一个公式来进行平移,这个公式应该满足f(max) = max, f(0) = 0, f(x) > x,其中x是距中心的距离,max是最后一个需要平移的函数,这儿我选择了左右的第二个,最后使用的是和开方有关的函数。

因为继承的是Gallery,所以只能通过spacing来控制需要显示多少个内容,不太方便,这个也是我后来写了opengl的原因。

 

  1. import android.content.Context;  
  2. import android.graphics.Camera;  
  3. import android.graphics.Matrix;  
  4. import android.view.MotionEvent;  
  5. import android.view.View;  
  6. import android.view.animation.Transformation;  
  7. import android.widget.Gallery;  
  8. import android.widget.ImageView;  
  9. public class CoverFlow extends Gallery {  
  10.     private static final String TAG = "CoverFlow";  
  11.     private static float DELTAX = 0;  
  12.     private Camera mCamera = new Camera();  
  13.     private int mMaxRotationAngle = 60;  
  14.     private int mMaxZoom = -120;  
  15.     private int mCoveflowCenter;  
  16.       
  17.     private float mSpeed = 2;  
  18.     public CoverFlow(Context context, float imagesize, float spacing) {  
  19.         super(context);  
  20.         DELTAX = (float) Math.sqrt(imagesize - spacing);  
  21.         this.setStaticTransformationsEnabled(true);  
  22.     }  
  23.     public int getMaxRotationAngle() {  
  24.         return mMaxRotationAngle;  
  25.     }  
  26.     public void setMaxRotationAngle(int maxRotationAngle) {  
  27.         mMaxRotationAngle = maxRotationAngle;  
  28.     }  
  29.     public int getMaxZoom() {  
  30.         return mMaxZoom;  
  31.     }  
  32.     public void setMaxZoom(int maxZoom) {  
  33.         mMaxZoom = maxZoom;  
  34.     }  
  35.     private int getCenterOfCoverflow() {  
  36.         return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();  
  37.     }  
  38.     private static int getCenterOfView(View view) {  
  39.         return view.getLeft() + view.getWidth() / 2;  
  40.     }    
  41.       
  42.     @Override  
  43.     protected int getChildDrawingOrder(int childCount, int i) {  
  44.         // TODO Auto-generated method stub  
  45.         //return super.getChildDrawingOrder(childCount, i);  
  46.         int select = getSelectedItemPosition() - getFirstVisiblePosition();  
  47.         if (i < select) {  
  48.             return i;  
  49.         } else if (i == select) {  
  50.             return childCount - 1;  
  51.         } else {  
  52.             return select + (childCount - i - 1);  
  53.         }  
  54.     }  
  55.       
  56.     @Override  
  57.     protected boolean getChildStaticTransformation(View child, Transformation t) {  
  58.         final int childCenter = getCenterOfView(child);  
  59.         final int childWidth = child.getWidth() ;  
  60.         int rotationAngle = 0;  
  61.         t.clear();  
  62.         t.setTransformationType(Transformation.TYPE_MATRIX);  
  63.         if (childCenter == mCoveflowCenter) {  
  64.             transformImageBitmap((ImageView) child, t, 00);  
  65.         } else {        
  66.             android.util.Log.i(TAG, "x: " + (mCoveflowCenter - childCenter));  
  67.             rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) *  mMaxRotationAngle);  
  68.             if (Math.abs(rotationAngle) > mMaxRotationAngle) {  
  69.                 rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;     
  70.             }  
  71.             transformImageBitmap((ImageView) child, t, rotationAngle, mCoveflowCenter - childCenter);           
  72.         }      
  73.         return true;  
  74.     }  
  75.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  76.         mCoveflowCenter = getCenterOfCoverflow();  
  77.         super.onSizeChanged(w, h, oldw, oldh);  
  78.     }  
  79.     private void transformImageBitmap(ImageView child, Transformation t, int rotationAngle, int delta) {              
  80.         mCamera.save();  
  81.         final Matrix imageMatrix = t.getMatrix();;  
  82.         final int imageHeight = child.getHeight();  
  83.         final int imageWidth = child.getWidth();  
  84.         final int rotation = Math.abs(rotationAngle);  
  85.         mCamera.translate(0.0f, 0.0f, 100.0f);  
  86.         //As the angle of the view gets less, zoom in       
  87.         if ( rotation < mMaxRotationAngle ) {  
  88.             float zoomAmount = (float) (mMaxZoom +  (rotation * 1.5));  
  89.             mCamera.translate(0.0f, 0.0f, zoomAmount);            
  90.         }   
  91.           
  92.         mCamera.rotateY(rotationAngle);  
  93.         float absx = Math.abs(delta);  
  94.         float x = (float) (DELTAX * Math.sqrt(absx) - absx);  
  95.         if (delta > 0) {  
  96.             mCamera.translate(-x, 00);  
  97.         } else if (delta < 0){  
  98.             mCamera.translate(x, 00);  
  99.         }  
  100.         mCamera.getMatrix(imageMatrix);   
  101.         imageMatrix.preTranslate(-(imageWidth/2), -(imageHeight/2));   
  102.         imageMatrix.postTranslate((imageWidth/2), (imageHeight/2));  
  103.         mCamera.restore();  
  104.     }  
  105.       
  106.     public void setSpeed(float speed) {  
  107.         mSpeed = speed;  
  108.     }  
  109.       
  110.     @Override  
  111.     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
  112.             float velocityY) {  
  113.         return super.onFling(e1, e2, velocityX / mSpeed, velocityY);  
  114.     }  
  115. }  
 接下来是使用的案例
  1. private static final float IMAGE_SIZE_MDPI = 170.6667f;  
  2. private static final float GALLERY_SPACING_MDPI = -23.333f;  
  3.     IMAGE_SIZE = IMAGE_SIZE_MDPI * dpi / 160;  
  4.     GALLERY_SPACING = GALLERY_SPACING_MDPI * dpi / 160;  
  5.   
  6.     mGalleryLandscape = new CoverFlow(this, IMAGE_SIZE, GALLERY_SPACING);  
  7.     mGalleryLandscape.setCallbackDuringFling(false);  
  8.     mGalleryLandscape.setAdapter(new GalleryLandscapeAdapter(this, mLocation));  
  9.     mGalleryLandscape.setSpacing((int) GALLERY_SPACING);      

因为需要放缩一下图片,所以Adpater的getView函数是这个样子的:

 

  1. @Override  
  2.         public View getView(int position, View convertView, ViewGroup parent) {  
  3.             ImageView view = (ImageView) convertView;  
  4.             if (view == null) {  
  5.                 view = new ImageView(parent.getContext());  
  6.             }  
  7.               
  8.             Bitmap bitmap = BitmapFactory.decodeFile(mLocation.get(position).getLocalImageUrl().getAbsolutePath());  
  9.             int width = bitmap.getWidth();  
  10.             int height = bitmap.getHeight();  
  11.             Bitmap bm;  
  12.             if (width > IMAGE_SIZE || height > IMAGE_SIZE) {  
  13.                 float scale = 1.0f;  
  14.                 if (width > height) {  
  15.                     scale = ((float) IMAGE_SIZE) / width;  
  16.                 } else {  
  17.                     scale = ((float) IMAGE_SIZE) / height;  
  18.                 }  
  19.                 width = (int) (width * scale);  
  20.                 height = (int) (height * scale);  
  21.                 android.util.Log.i(TAG, IMAGE_SIZE + " " + width + " " + height);  
  22.                 bm = Bitmap.createScaledBitmap(bitmap, width, height, false);  
  23.                 bitmap.recycle();  
  24.             } else {  
  25.                 bm = bitmap;  
  26.             }  
  27.             view.setImageBitmap(bm);  
  28.             return view;  
  29.         }  
 

 

 

第二种OpenGL

这个的基本思想是抄iOS的,但是进行了一些更改,例如利用velocitytracker进行速度的计算等。

  1. package com.locatify.fengji.coverflow;  
  2. import java.nio.ByteBuffer;  
  3. import java.nio.ByteOrder;  
  4. import java.nio.FloatBuffer;  
  5. import javax.microedition.khronos.egl.EGLConfig;  
  6. import javax.microedition.khronos.opengles.GL10;  
  7. import android.content.Context;  
  8. import android.graphics.Bitmap;  
  9. import android.graphics.BitmapFactory;  
  10. import android.graphics.Canvas;  
  11. import android.graphics.Paint;  
  12. import android.graphics.PixelFormat;  
  13. import android.graphics.Rect;  
  14. import android.graphics.RectF;  
  15. import android.opengl.GLSurfaceView;  
  16. import android.opengl.GLU;  
  17. import android.opengl.GLUtils;  
  18. import android.view.MotionEvent;  
  19. import android.view.VelocityTracker;  
  20. import android.view.animation.AnimationUtils;  
  21. public class CoverFlowOpenGL extends GLSurfaceView implements GLSurfaceView.Renderer {  
  22.     private static final String TAG = "AnotherCoverFlow";  
  23.       
  24.     private static final int TOUCH_MINIMUM_MOVE = 5;  
  25.     private static final int IMAGE_SIZE = 256; // the bitmap size we use for the texture  
  26.     private static final int MAX_TILES = 48; // the maximum tiles in the cache  
  27.     private static final int VISIBLE_TILES = 3; // the visble tiles left and right  
  28.       
  29.     private static final float SCALE = 0.7f; // the scale of surface view  
  30.     private static final float SPREAD_IMAGE = 0.14f;  
  31.     private static final float FLANK_SPREAD = 0.4f;  
  32.     private static final float FRICTION = 10.0f;  
  33.     private static final float MAX_SPEED = 6.0f;  
  34.       
  35.     private static final float[] GVertices = new float[]{  
  36.         -1.0f, -1.0f, 0.0f,  
  37.          1.0f, -1.0f, 0.0f,  
  38.         -1.0f,  1.0f, 0.0f,  
  39.          1.0f,  1.0f, 0.0f,  
  40.     };  
  41.       
  42.     private static final float[] GTextures = new float[]{  
  43.         0.0f, 1.0f,  
  44.         1.0f, 1.0f,  
  45.         0.0f, 0.0f,  
  46.         1.0f, 0.0f,  
  47.     };  
  48.       
  49.     private GL10 mGLContext;  
  50.     private FloatBuffer mVerticesBuffer;  
  51.     private FloatBuffer mTexturesBuffer;  
  52.     private float[] mMatrix;  
  53.       
  54.     private int mBgTexture;  
  55.     private FloatBuffer mBgVerticesBuffer;  
  56.     private FloatBuffer mBgTexturesBuffer;  
  57.     private Bitmap mBgBitmap;  
  58.     private boolean mInitBackground;  
  59.       
  60.     private float mOffset;  
  61.     private RectF mTouchRect;  
  62.       
  63.     private int mWidth;  
  64.     private boolean mTouchMoved;  
  65.     private float mTouchStartPos;  
  66.     private float mTouchStartX;  
  67.     private float mTouchStartY;  
  68.       
  69.     private float mStartOffset;  
  70.     private long mStartTime;  
  71.       
  72.     private float mStartSpeed;  
  73.     private float mDuration;  
  74.     private Runnable mAnimationRunnable;  
  75.     private VelocityTracker mVelocity;  
  76.       
  77.     private boolean mStopBackgroundThread;  
  78.     private CoverFlowListener mListener;  
  79.     private DataCache<Integer, CoverFlowRecord> mCache;  
  80.       
  81.     public CoverFlowOpenGL(Context context) {  
  82.         super(context);  
  83.           
  84.         setEGLConfigChooser(8, 8, 8, 8, 16, 0);  
  85.           
  86.         setRenderer(this);  
  87.         setRenderMode(RENDERMODE_WHEN_DIRTY);  
  88.           
  89.         getHolder().setFormat(PixelFormat.TRANSLUCENT);  
  90.         //setZOrderMediaOverlay(true);  
  91.         //setZOrderOnTop(true);  
  92.           
  93.         mCache = new DataCache<Integer, CoverFlowRecord>(MAX_TILES);  
  94.         mOffset = 0;  
  95.         mInitBackground = false;  
  96.     }  
  97.       
  98.     public void setCoverFlowListener(CoverFlowListener listener) {  
  99.         mListener = listener;  
  100.     }  
  101.       
  102.     private float checkValid(float off) {  
  103.         int max = mListener.getCount(this) - 1;  
  104.         if (off < 0)  
  105.             return 0;  
  106.         else if (off > max)  
  107.             return max;  
  108.           
  109.         return off;  
  110.     }  
  111.       
  112.     public void setSelection(int position) {  
  113.         endAnimation();  
  114.         mOffset = position;  
  115.     }  
  116.       
  117.     @Override  
  118.     public boolean onTouchEvent(MotionEvent event) {  
  119.         int action = event.getAction();  
  120.         switch(action) {  
  121.         case MotionEvent.ACTION_DOWN:  
  122.             touchBegan(event);  
  123.             return true;  
  124.         case MotionEvent.ACTION_MOVE:  
  125.             touchMoved(event);  
  126.             return true;  
  127.         case MotionEvent.ACTION_UP:  
  128.             touchEnded(event);  
  129.             return true;  
  130.         }  
  131.         return false;  
  132.     }  
  133.       
  134.     private void touchBegan(MotionEvent event) {  
  135.         endAnimation();  
  136.           
  137.         float x = event.getX();  
  138.         mTouchStartX = x;  
  139.         mTouchStartY = event.getY();  
  140.         mStartTime = System.currentTimeMillis();  
  141.         mStartOffset = mOffset;  
  142.           
  143.         mTouchMoved = false;  
  144.           
  145.         mTouchStartPos = (x / mWidth) * 10 - 5;  
  146.         mTouchStartPos /= 2;  
  147.           
  148.         mVelocity = VelocityTracker.obtain();  
  149.         mVelocity.addMovement(event);  
  150.     }  
  151.       
  152.     private void touchMoved(MotionEvent event) {  
  153.         float pos = (event.getX() / mWidth) * 10 - 5;  
  154.         pos /= 2;  
  155.           
  156.         if (!mTouchMoved) {  
  157.             float dx = Math.abs(event.getX() - mTouchStartX);  
  158.             float dy = Math.abs(event.getY() - mTouchStartY);  
  159.               
  160.             if (dx < TOUCH_MINIMUM_MOVE && dy < TOUCH_MINIMUM_MOVE)  
  161.                 return ;  
  162.               
  163.             mTouchMoved = true;  
  164.         }  
  165.           
  166.         mOffset = checkValid(mStartOffset + mTouchStartPos - pos);  
  167.           
  168.         requestRender();  
  169.         mVelocity.addMovement(event);  
  170.     }  
  171.       
  172.     private void touchEnded(MotionEvent event) {  
  173.         float pos = (event.getX() / mWidth) * 10 - 5;  
  174.         pos /= 2;  
  175.           
  176.         if (mTouchMoved) {  
  177.             mStartOffset += mTouchStartPos - pos;  
  178.             mStartOffset = checkValid(mStartOffset);  
  179.             mOffset = mStartOffset;  
  180.               
  181.             mVelocity.addMovement(event);  
  182.               
  183.             mVelocity.computeCurrentVelocity(1000);  
  184.             double speed = mVelocity.getXVelocity();  
  185.             speed = (speed / mWidth) * 10;  
  186.             android.util.Log.i(TAG, "SPEED: " + speed);  
  187.             if (speed > MAX_SPEED)  
  188.                 speed = MAX_SPEED;  
  189.             else if (speed < -MAX_SPEED)  
  190.                 speed = -MAX_SPEED;  
  191.               
  192.             startAnimation(-speed);  
  193.         } else {  
  194.             if (mTouchRect.contains(event.getX(), event.getY())) {  
  195.                 mListener.topTileClicked(this, (int) (mOffset + 0.01));  
  196.             }  
  197.         }  
  198.     }  
  199.       
  200.     private void startAnimation(double speed) {  
  201.         if (mAnimationRunnable != null)  
  202.             return ;  
  203.           
  204.         double delta = speed * speed / (FRICTION * 2);  
  205.         if (speed < 0)  
  206.             delta = -delta;  
  207.           
  208.         double nearest = mStartOffset + delta;  
  209.         nearest = Math.floor(nearest + 0.5);  
  210.         nearest = checkValid((float) nearest);  
  211.           
  212.         mStartSpeed = (float) Math.sqrt(Math.abs(nearest - mStartOffset) * FRICTION * 2);  
  213.         if (nearest < mStartOffset)  
  214.             mStartSpeed = -mStartSpeed;  
  215.           
  216.         mDuration = Math.abs(mStartSpeed / FRICTION);  
  217.         mStartTime = AnimationUtils.currentAnimationTimeMillis();  
  218.           
  219.         mAnimationRunnable = new Runnable() {  
  220.             @Override  
  221.             public void run() {  
  222.                 driveAnimation();  
  223.             }  
  224.         };  
  225.         post(mAnimationRunnable);  
  226.     }  
  227.       
  228.     private void driveAnimation() {  
  229.         float elapsed = (AnimationUtils.currentAnimationTimeMillis() - mStartTime) / 1000.0f;  
  230.         if (elapsed >= mDuration)  
  231.             endAnimation();  
  232.         else {  
  233.             updateAnimationAtElapsed(elapsed);  
  234.             post(mAnimationRunnable);  
  235.         }  
  236.     }  
  237.       
  238.     private void endAnimation() {  
  239.         if (mAnimationRunnable != null) {  
  240.             mOffset = (float) Math.floor(mOffset + 0.5);  
  241.             mOffset = checkValid(mOffset);  
  242.               
  243.             requestRender();  
  244.               
  245.             removeCallbacks(mAnimationRunnable);  
  246.             mAnimationRunnable = null;  
  247.         }  
  248.     }  
  249.       
  250.     private void updateAnimationAtElapsed(float elapsed) {  
  251.         if (elapsed > mDuration)  
  252.             elapsed = mDuration;  
  253.           
  254.         float delta = Math.abs(mStartSpeed) * elapsed - FRICTION * elapsed * elapsed / 2;  
  255.         if (mStartSpeed < 0)  
  256.             delta = -delta;  
  257.           
  258.         mOffset = checkValid(mStartOffset + delta);  
  259.         requestRender();  
  260.     }  
  261.       
  262.     @Override  
  263.     public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
  264.         mCache.clear();  
  265.         android.util.Log.i(TAG, "CREATE");  
  266.         mGLContext = gl;  
  267.         mVerticesBuffer = makeFloatBuffer(GVertices);  
  268.         mTexturesBuffer = makeFloatBuffer(GTextures);  
  269.     }  
  270.     @Override  
  271.     public void onSurfaceChanged(GL10 gl, int w, int h) {  
  272.         if (getAnimation() != null)  
  273.             return;  
  274.           
  275.         android.util.Log.i(TAG, "CHANGED");  
  276.         mWidth = w;  
  277.           
  278.         float imagew = w * 0.45f / SCALE / 2.0f;  
  279.         float imageh = h * 0.45f / SCALE / 2.0f;  
  280.         mTouchRect = new RectF(w / 2 - imagew, h / 2 - imageh, w / 2 + imagew, h / 2 + imageh);  
  281.           
  282.         gl.glViewport(0, 0, w, h);  
  283.       
  284.         float ratio = ((float) w) / h;  
  285.         gl.glMatrixMode(GL10.GL_PROJECTION);  
  286.         gl.glLoadIdentity();  
  287.         gl.glOrthof(-ratio * SCALE, ratio * SCALE, -1 * SCALE, 1 * SCALE, 1, 3);  
  288.           
  289.         float[] vertices = new float[] {  
  290.                 -ratio * SCALE, -SCALE, 0,  
  291.                 ratio * SCALE, -SCALE, 0,  
  292.                 -ratio * SCALE, SCALE, 0,  
  293.                 ratio * SCALE, SCALE, 0  
  294.         };  
  295.         mBgVerticesBuffer = makeFloatBuffer(vertices);  
  296.     }  
  297.       
  298.     public void setBackgroundTexture(int res) {  
  299.         mBgBitmap = BitmapFactory.decodeResource(getResources(), res);  
  300.         mInitBackground = true;  
  301.     }  
  302.       
  303.     private void initBg() {  
  304.         mInitBackground = false;  
  305.         if (mBgBitmap != null) {  
  306.             int tmp = 1;  
  307.             int w = mBgBitmap.getWidth();  
  308.             int h = mBgBitmap.getHeight();  
  309.             while (w > tmp || h > tmp) {  
  310.                 tmp <<= 1;  
  311.             }  
  312.               
  313.             int width = tmp;  
  314.             int height = tmp;  
  315.             Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);  
  316.             Canvas cv = new Canvas(bm);  
  317.               
  318.             int left = (width - w) / 2;  
  319.             int top = (height - h) / 2;  
  320.             cv.drawBitmap(mBgBitmap, left, top, new Paint());  
  321.               
  322.             GL10 gl = mGLContext;  
  323.               
  324.             int[] tex = new int[1];  
  325.             gl.glGenTextures(1, tex, 0);  
  326.             mBgTexture = tex[0];  
  327.               
  328.             gl.glBindTexture(GL10.GL_TEXTURE_2D, mBgTexture);  
  329.             GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bm, 0);  
  330.             bm.recycle();  
  331.               
  332.             gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);  
  333.             gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);  
  334.             gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);  
  335.             gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);  
  336.             gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_REPLACE);  
  337.               
  338.             float[] textcoor = new float[] {  
  339.                     (tmp - w) / 2.0f / tmp, (tmp - h) / 2.0f / tmp,  
  340.                     (tmp + w) / 2.0f / tmp, (tmp - h) / 2.0f / tmp,  
  341.                     (tmp - w) / 2.0f / tmp, (tmp + h) / 2.0f / tmp,  
  342.                     (tmp + w) / 2.0f / tmp, (tmp + h) / 2.0f / tmp   
  343.             };  
  344.             mBgTexturesBuffer = makeFloatBuffer(textcoor);  
  345.         }  
  346.     }  
  347.       
  348.     @Override  
  349.     public void onDrawFrame(GL10 gl) {  
  350.         //android.util.Log.i(TAG, "DRAW");  
  351.         gl.glMatrixMode(GL10.GL_MODELVIEW);  
  352.         gl.glLoadIdentity();  
  353.         GLU.gluLookAt(gl, 0, 0, 2, 0f, 0f, 0f, 0f, 1.0f, 0.0f);  
  354.           
  355.         gl.glDisable(GL10.GL_DEPTH_TEST);  
  356.         gl.glClearColor(0, 0, 0, 0);  
  357.         gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);  
  358.           
  359.         gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);  
  360.         gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  
  361.           
  362.         drawBg(gl);  
  363.         draw(gl);  
  364.     }  
  365.       
  366.     public void drawBg(GL10 gl) {  
  367.         if (mBgBitmap != null) {  
  368.             if (mInitBackground)  
  369.                 initBg();  
  370.               
  371.             gl.glPushMatrix();  
  372.               
  373.             gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mBgVerticesBuffer);  
  374.             gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mBgTexturesBuffer);  
  375.             gl.glEnable(GL10.GL_TEXTURE_2D);  
  376.               
  377.             gl.glBindTexture(GL10.GL_TEXTURE_2D, mBgTexture); // bind texture  
  378.             gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);  
  379.               
  380.             gl.glPopMatrix();  
  381.         }  
  382.     }  
  383.       
  384.     private void draw(GL10 gl) {  
  385.         mStopBackgroundThread = true;  
  386.         gl.glPushMatrix();  
  387.           
  388.         gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVerticesBuffer); // vertices of square  
  389.         gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexturesBuffer); // texture vertices  
  390.         gl.glEnable(GL10.GL_TEXTURE_2D);  
  391.           
  392.         gl.glEnable(GL10.GL_BLEND);  
  393.         gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);  
  394.           
  395.         final float offset = mOffset;  
  396.         int i = 0;  
  397.         int max = mListener.getCount(this) - 1;  
  398.         int mid = (int) Math.floor(offset + 0.5);  
  399.         int iStartPos = mid - VISIBLE_TILES;  
  400.           
  401.         if (iStartPos < 0)  
  402.             iStartPos = 0;  
  403.         // draw the left tiles  
  404.         for (i = iStartPos; i < mid; ++i) {  
  405.             drawTile(i, i - offset, gl);  
  406.         }     
  407.           
  408.         // draw the right tiles  
  409.         int iEndPos = mid + VISIBLE_TILES;  
  410.         if (iEndPos > max)  
  411.             iEndPos = max;  
  412.         for (i = iEndPos; i >= mid; --i) {  
  413.             drawTile(i, i - offset, gl);  
  414.         }  
  415.           
  416.         mListener.tileOnTop(this, (int) offset);  
  417.           
  418.         gl.glPopMatrix();  
  419.         mStopBackgroundThread = false;  
  420.         preLoadCache(iStartPos - 3, iEndPos + 3);  
  421.     }  
  422.       
  423.     private void drawTile(int position, float off, GL10 gl) {  
  424.         CoverFlowRecord fcr = getTileAtIndex(position, gl);  
  425.         if (mMatrix == null) {  
  426.             mMatrix = new float[16];  
  427.             mMatrix[15] = 1;  
  428.             mMatrix[10] = 1;  
  429.             mMatrix[5] = 1;  
  430.             mMatrix[0] = 1;  
  431.         }  
  432.           
  433.         float trans = off * SPREAD_IMAGE;  
  434.         float f = off * FLANK_SPREAD;  
  435.         if (f > FLANK_SPREAD)  
  436.             f = FLANK_SPREAD;  
  437.         else if (f < -FLANK_SPREAD)  
  438.             f = -FLANK_SPREAD;  
  439.           
  440.         mMatrix[3] = -f;  
  441.         mMatrix[0] = 1 - Math.abs(f);  
  442.         float sc = 0.45f * mMatrix[0];  
  443.         trans += f * 1;  
  444.           
  445.         gl.glPushMatrix();  
  446.         gl.glBindTexture(GL10.GL_TEXTURE_2D, fcr.mTexture[0]); // bind texture  
  447.           
  448.         // draw bitmap  
  449.         gl.glTranslatef(trans, 0, 0); // translate the picture to the right position  
  450.         gl.glScalef(sc, sc, 1.0f); // scale the picture  
  451.         gl.glMultMatrixf(mMatrix, 0); // rotate the picture  
  452.         gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);  
  453.           
  454.         // draw the reflection  
  455.         gl.glTranslatef(0, -2, 0);  
  456.         gl.glScalef(1, -1, 1);  
  457.         gl.glColor4f(0.5f, 0.5f, 0.5f, 0);  
  458.         gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);  
  459.         gl.glColor4f(1, 1, 1, 1);  
  460.           
  461.         gl.glPopMatrix();  
  462.     }  
  463.     private CoverFlowRecord getTileAtIndex(int position, GL10 gl) {  
  464.         synchronized(this) {  
  465.             CoverFlowRecord fcr = mCache.objectForKey(position);  
  466.             if (fcr == null) {  
  467.                 Bitmap bm = mListener.getImage(this, position);  
  468.                 if (bm == null)  
  469.                     return null;  
  470.       
  471.                 int[] texture = imageToTexture(bm, gl);  
  472.                 fcr = new CoverFlowRecord(texture, gl);  
  473.                   
  474.                 mCache.putObjectForKey(position, fcr);  
  475.             }  
  476.             return fcr;  
  477.         }  
  478.     }  
  479.     private int[] imageToTexture(Bitmap bitmap, GL10 gl) {  
  480.         // generate texture  
  481.         int[] texture = new int[1];  
  482.         gl.glGenTextures(1, texture, 0);  
  483.         gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]);  
  484.           
  485.         int width = bitmap.getWidth();  
  486.         int height = bitmap.getHeight();  
  487.         Bitmap bm = Bitmap.createBitmap(IMAGE_SIZE, IMAGE_SIZE, Bitmap.Config.ARGB_8888);  
  488.         Canvas cv = new Canvas(bm);  
  489.         if (width > IMAGE_SIZE || height > IMAGE_SIZE) {  
  490.             // scale the bitmap, make the width or height to the IMAGE_SIZE  
  491.             Rect src = new Rect(0, 0, width, height);  
  492.               
  493.             float scale = 1.0f;  
  494.             if (width > height)  
  495.                 scale = ((float) IMAGE_SIZE) / width;  
  496.             else  
  497.                 scale = ((float) IMAGE_SIZE) / height;  
  498.             width = (int) (width * scale);  
  499.             height = (int) (height * scale);  
  500.             float left = (IMAGE_SIZE - width) / 2.0f;  
  501.             float top = (IMAGE_SIZE - height) / 2.0f;  
  502.             RectF dst = new RectF(left, top, left + width, top + height);  
  503.               
  504.             cv.drawBitmap(bitmap, src, dst, new Paint());  
  505.         } else {  
  506.             float left = (IMAGE_SIZE - width) / 2.0f;  
  507.             float top = (IMAGE_SIZE - height) / 2.0f;  
  508.             cv.drawBitmap(bitmap, left, top, new Paint());  
  509.         }  
  510.           
  511.         GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bm, 0); // draw the bitmap in the texture  
  512.         bm.recycle();  
  513.         bitmap.recycle();  
  514.           
  515.         // some texture settings  
  516.         gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);  
  517.         gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);  
  518.         gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);  
  519.         gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);  
  520.         gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_REPLACE);  
  521.           
  522.         return texture;  
  523.     }  
  524.       
  525.     // preload the cache from startindex(including) to endIndex(exclusive)  
  526.     // you just can preload the cache after the view has been attached to the window  
  527.     public void preLoadCache(final int startIndex, final int endIndex) {  
  528.         mStopBackgroundThread = false;  
  529.         if (mGLContext != null) {  
  530.             new Thread(new Runnable() {  
  531.                 public void run() {  
  532.                     int start = startIndex;  
  533.                     if (start < 0)  
  534.                         start = 0;  
  535.                       
  536.                     int max = mListener.getCount(CoverFlowOpenGL.this);  
  537.                     int end = endIndex > max ? max : endIndex;  
  538.                       
  539.                     for (int i = start; i < end && !mStopBackgroundThread; ++i) {  
  540.                         getTileAtIndex(i, mGLContext);  
  541.                     }  
  542.                 }  
  543.             }).run();  
  544.         }  
  545.     }  
  546.       
  547.     private static FloatBuffer makeFloatBuffer(final float[] arr) {  
  548.         ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);  
  549.         bb.order(ByteOrder.nativeOrder());  
  550.         FloatBuffer fb = bb.asFloatBuffer();  
  551.         fb.put(arr);  
  552.         fb.position(0);  
  553.         return fb;  
  554.     }  
  555.       
  556.     public static class CoverFlowRecord {  
  557.         private int[] mTexture;  
  558.         private GL10 gl;  
  559.           
  560.         public CoverFlowRecord(int[] texture, GL10 gl) {  
  561.             mTexture = texture;  
  562.             this.gl = gl;  
  563.         }  
  564.           
  565.         @Override  
  566.         protected void finalize() throws Throwable {  
  567.             if (mTexture != null) {  
  568.                 gl.glDeleteTextures(1, mTexture, 0);  
  569.             }  
  570.               
  571.             super.finalize();  
  572.         }  
  573.     }  
  574.       
  575.     public static interface CoverFlowListener {  
  576.         public int getCount(CoverFlowOpenGL view);              // Number of images to display  
  577.         public Bitmap getImage(CoverFlowOpenGL anotherCoverFlow, int position); // Image at position  
  578.         public void tileOnTop(CoverFlowOpenGL view, int position); // Notify what tile is on top after scroll or start  
  579.         public void topTileClicked(CoverFlowOpenGL view, int position);  
  580.     }  
  581. }  
 

 

当中用了一个类进行数据的cache,挺简单的。

  1. package com.locatify.fengji.coverflow;  
  2. import java.util.LinkedHashMap;  
  3. import java.util.concurrent.locks.ReadWriteLock;  
  4. import java.util.concurrent.locks.ReentrantReadWriteLock;  
  5. public class DataCache<K, E> {  
  6.     private int mCapacity;  
  7.     private LinkedHashMap<K, E> mCache;  
  8.     private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();  
  9.       
  10.     public DataCache(int capacity) {  
  11.         mCapacity = capacity;  
  12.         mCache = new LinkedHashMap<K, E>(mCapacity) {  
  13.             private static final long serialVersionUID = -9165777183357349715L;  
  14.             @Override  
  15.             protected boolean removeEldestEntry(java.util.Map.Entry<K, E> eldest) {  
  16.                 return size() > mCapacity;  
  17.             }  
  18.         };  
  19.     }  
  20.       
  21.     public E objectForKey(K key) {  
  22.         mReadWriteLock.readLock().lock();  
  23.         final E result = mCache.get(key);  
  24.         mReadWriteLock.readLock().unlock();  
  25.           
  26.         return result;  
  27.     }  
  28.       
  29.     public void putObjectForKey(final K key, final E value) {  
  30.         if (key != null && value != null) {  
  31.             mReadWriteLock.writeLock().lock();  
  32.             mCache.put(key, value);  
  33.             mReadWriteLock.writeLock().unlock();  
  34.         }  
  35.     }  
  36.       
  37.     public boolean containsKey(final K key) {  
  38.         mReadWriteLock.readLock().lock();  
  39.         final boolean result = mCache.containsKey(key);  
  40.         mReadWriteLock.readLock().unlock();  
  41.           
  42.         return result;  
  43.     }  
  44.       
  45.     public void clear() {  
  46.         mReadWriteLock.writeLock().lock();  
  47.         mCache.clear();  
  48.         mReadWriteLock.writeLock().unlock();  
  49.     }  
  50. }  
 

 

恩,大概就是这样子,第一次写日志,代码里有一些注释,如果还有什么问题可以留言。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值