自定义带倒影和偏转的超炫Gallery

 昨天晚上写的博客没有了,只好今天重新写一遍,重新学习下吧,首先,看下效果图:

自定义带倒影和偏转的超炫Gallery_第1张图片

  

如果这篇文章对您有用,劳烦几秒钟帮忙投下票:http://vote.blog.csdn.net/item/blogstar/aomandeshangxiao,Csdn 2012博客之星投票,谢谢!!!


   先看下主类代码:

[java]  view plain copy
  1. public class GalleryDemoActivity extends Activity {  
  2.     /** Called when the activity is first created. */  
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         requestWindowFeature(Window.FEATURE_NO_TITLE);       
  7.         setContentView(R.layout.main);  
  8.           
  9.         Integer[] images = { R.drawable.image01,   
  10.                              R.drawable.image02,   
  11.                              R.drawable.image03,   
  12.                              R.drawable.image04,   
  13.                              R.drawable.image05};  
  14.           
  15.         ImageAdapter adapter = new ImageAdapter(this, images);  
  16.         adapter.createReflectedImages();//创建倒影效果  
  17.         GalleryFlow galleryFlow = (GalleryFlow) this.findViewById(R.id.gallery);  
  18.         galleryFlow.setFadingEdgeLength(0);  
  19.         galleryFlow.setSpacing(10); //图片之间的间距  
  20.         galleryFlow.setAdapter(adapter);  
  21.           
  22.         galleryFlow.setOnItemClickListener(new OnItemClickListener() {  
  23.             public void onItemClick(AdapterView<?> parent, View view,  
  24.                     int position, long id) {  
  25.                 Toast.makeText(getApplicationContext(), String.valueOf(position), Toast.LENGTH_SHORT).show();  
  26.             }  
  27.               
  28.         });  
  29.         galleryFlow.setSelection(4);  
  30.     }  

      比较简单,先来看下倒影效果是如何实现的,在ImageAdapter类里找到createReflectedImages()这个方法:

[java]  view plain copy
  1. /** 
  2.      * 创建倒影效果 
  3.      * @return 
  4.      */  
  5.     public boolean createReflectedImages() {  
  6.      //倒影图和原图之间的距离  
  7.      final int reflectionGap = 4;  
  8.      int index = 0;  
  9.      for (int imageId : mImageIds) {  
  10.           //返回原图解码之后的bitmap对象  
  11.           Bitmap originalImage = BitmapFactory.decodeResource(mContext.getResources(), imageId);  
  12.           int width = originalImage.getWidth();  
  13.           int height = originalImage.getHeight();  
  14.           //创建矩阵对象  
  15.           Matrix matrix = new Matrix();  
  16.             
  17.           //指定一个角度以0,0为坐标进行旋转  
  18.           // matrix.setRotate(30);  
  19.             
  20.           //指定矩阵(x轴不变,y轴相反)  
  21.           matrix.preScale(1, -1);  
  22.             
  23.           //将矩阵应用到该原图之中,返回一个宽度不变,高度为原图1/2的倒影位图  
  24.           Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0,  
  25.             height/2, width, height/2, matrix, false);  
  26.             
  27.           //创建一个宽度不变,高度为原图+倒影图高度的位图  
  28.           Bitmap bitmapWithReflection = Bitmap.createBitmap(width,  
  29.             (height + height / 2), Config.ARGB_8888);  
  30.             
  31.           //将上面创建的位图初始化到画布  
  32.           Canvas canvas = new Canvas(bitmapWithReflection);  
  33.           canvas.drawBitmap(originalImage, 00null);  
  34.             
  35.           Paint deafaultPaint = new Paint();   
  36.           deafaultPaint.setAntiAlias(false);  
  37.     //    canvas.drawRect(0, height, width, height + reflectionGap,deafaultPaint);  
  38.           canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);  
  39.           Paint paint = new Paint();  
  40.           paint.setAntiAlias(false);  
  41.              
  42.           /** 
  43.            * 参数一:为渐变起初点坐标x位置, 
  44.            * 参数二:为y轴位置, 
  45.            * 参数三和四:分辨对应渐变终点, 
  46.            * 最后参数为平铺方式, 
  47.            * 这里设置为镜像Gradient是基于Shader类,所以我们通过Paint的setShader方法来设置这个渐变 
  48.            */  
  49.           LinearGradient shader = new LinearGradient(0,originalImage.getHeight(), 0,  
  50.                   bitmapWithReflection.getHeight() + reflectionGap,0x70ffffff0x00ffffff, TileMode.MIRROR);  
  51.           //设置阴影  
  52.           paint.setShader(shader);  
  53.           paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));  
  54.           //用已经定义好的画笔构建一个矩形阴影渐变效果  
  55.           canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()+ reflectionGap, paint);  
  56.             
  57.           //创建一个ImageView用来显示已经画好的bitmapWithReflection  
  58.           ImageView imageView = new ImageView(mContext);  
  59.           imageView.setImageBitmap(bitmapWithReflection);  
  60.           //设置imageView大小 ,也就是最终显示的图片大小  
  61.           imageView.setLayoutParams(new GalleryFlow.LayoutParams(200300));  
  62.           //imageView.setScaleType(ScaleType.MATRIX);  
  63.           mImages[index++] = imageView;  
  64.      }  
  65.      return true;  
  66.     }  

先获取倒影,然后把倒影和原照片合成一张图片。里面使用到了bitmap的静态方法createBitmap(),看下官方文档:

[plain]  view plain copy
  1. public static Bitmap createBitmap (Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)  
  2.   
  3. Since: API Level 1  
  4. Returns an immutable bitmap from subset of the source bitmap, transformed by the optional matrix. It is initialized with the same density as the original bitmap.  
  5. Parameters  
  6.   
  7. source  The bitmap we are subsetting  
  8. x   The x coordinate of the first pixel in source  
  9. y   The y coordinate of the first pixel in source  
  10. width   The number of pixels in each row  
  11. height  The number of rows  
  12. m   Optional matrix to be applied to the pixels  
  13. filter  true if the source should be filtered. Only applies if the matrix contains more than just translation.  
  14. Returns  
  15.   
  16. A bitmap that represents the specified subset of source  
  17. Throws  
  18.   
  19. IllegalArgumentException    if the x, y, width, height values are outside of the dimensions of the source bitmap.  

  参数x、y就是开始复制的起点坐标,就是从原图的那个坐标点开始复制,width设置复制的宽度,height设置高度。

因为代码中注释较详细,这里不再多说。

    下面这段代码是设置渐变效果:

[java]  view plain copy
  1. /** 
  2.        * 参数一:为渐变起初点坐标x位置, 
  3.        * 参数二:为y轴位置, 
  4.        * 参数三和四:分辨对应渐变终点, 
  5.        * 最后参数为平铺方式, 
  6.        * 这里设置为镜像Gradient是基于Shader类,所以我们通过Paint的setShader方法来设置这个渐变 
  7.        */  
  8.       LinearGradient shader = new LinearGradient(0,originalImage.getHeight(), 0,  
  9.               bitmapWithReflection.getHeight() + reflectionGap,0x70ffffff0x00ffffff, TileMode.MIRROR);  
     看完倒影,再来看一下偏转,在main.xml文件中:

[html]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical"  
  6.     >  
  7.     <nsouth.jonas.android.GalleryFlow   
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="match_parent"  
  10.         android:gravity="center_vertical"  
  11.         android:id="@+id/gallery"  
  12.     />  
  13. </LinearLayout>  

只有一个自定义的GalleryFlow,来看下它的代码:

[java]  view plain copy
  1. public class GalleryFlow extends Gallery{  
  2.     private Camera mCamera = new Camera();//相机类  
  3.     private int mMaxRotationAngle = 60;//最大转动角度  
  4.     private int mMaxZoom = -280;////最大缩放值  
  5.     private int mCoveflowCenter;//半径值  
  6.   
  7.     public GalleryFlow(Context context) {  
  8.         super(context);  
  9.         //支持转换 ,执行getChildStaticTransformation方法  
  10.         this.setStaticTransformationsEnabled(true);  
  11.     }  
  12.       
  13.     public GalleryFlow(Context context, AttributeSet attrs) {  
  14.         super(context, attrs);  
  15.         this.setStaticTransformationsEnabled(true);  
  16.     }  
  17.       
  18.     public GalleryFlow(Context context, AttributeSet attrs, int defStyle) {  
  19.         super(context, attrs, defStyle);  
  20.         this.setStaticTransformationsEnabled(true);  
  21.     }  
  22.       
  23.     /** 
  24.      * 获取旋转最大角度 
  25.      * @return 
  26.      */  
  27.     public int getMaxRotationAngle() {  
  28.         return mMaxRotationAngle;  
  29.     }  
  30.       
  31.     /** 
  32.      * 设置旋转最大角度 
  33.      * @param maxRotationAngle 
  34.      */  
  35.     public void setMaxRotationAngle(int maxRotationAngle) {  
  36.         mMaxRotationAngle = maxRotationAngle;  
  37.     }  
  38.       
  39.     /** 
  40.      * 获取最大缩放值 
  41.      * @return 
  42.      */  
  43.     public int getMaxZoom() {  
  44.         return mMaxZoom;  
  45.     }  
  46.       
  47.     /** 
  48.      * 设置最大缩放值 
  49.      * @param maxZoom 
  50.      */  
  51.     public void setMaxZoom(int maxZoom) {  
  52.         mMaxZoom = maxZoom;  
  53.     }  
  54.       
  55.     /** 
  56.      * 获取半径值 
  57.      * @return 
  58.      */  
  59.     private int getCenterOfCoverflow() {  
  60.         return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2  
  61.                         + getPaddingLeft();  
  62.     }  
  63.       
  64.     /** 
  65.      * @param view 
  66.      * @return 
  67.      */  
  68.     private static int getCenterOfView(View view) {  
  69.         return view.getLeft() + view.getWidth() / 2;  
  70.     }     
  71.       
  72.    //控制gallery中每个图片的旋转(重写的gallery中方法)  
  73.     protected boolean getChildStaticTransformation(View child, Transformation t) {    
  74.         //取得当前子view的半径值  
  75.         final int childCenter = getCenterOfView(child);         
  76.         final int childWidth = child.getWidth();  
  77.         //旋转角度  
  78.         int rotationAngle = 0;  
  79.         //重置转换状态  
  80.         t.clear();  
  81.         //设置转换类型  
  82.         t.setTransformationType(Transformation.TYPE_MATRIX);  
  83.         //如果图片位于中心位置不需要进行旋转  
  84.         if (childCenter == mCoveflowCenter) {  
  85.             transformImageBitmap((ImageView) child, t, 0);  
  86.         } else {  
  87.             //根据图片在gallery中的位置来计算图片的旋转角度  
  88.             rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);  
  89.             System.out.println("rotationAngle:" +rotationAngle);  
  90.             //如果旋转角度绝对值大于最大旋转角度返回(-mMaxRotationAngle或mMaxRotationAngle;)  
  91.             if (Math.abs(rotationAngle) > mMaxRotationAngle) {  
  92.                 rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;  
  93.             }  
  94.             transformImageBitmap((ImageView) child, t, rotationAngle);  
  95.         }  
  96.         return true;  
  97.     }  
  98.       
  99.     /** 
  100.      *  
  101.      */  
  102.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  103.         mCoveflowCenter = getCenterOfCoverflow();  
  104.         super.onSizeChanged(w, h, oldw, oldh);  
  105.     }  
  106.       
  107.       
  108.     private void transformImageBitmap(ImageView child, Transformation t,  
  109.                     int rotationAngle) {  
  110.         //对效果进行保存  
  111.         mCamera.save();  
  112.         final Matrix imageMatrix = t.getMatrix();  
  113.         //图片高度  
  114.         final int imageHeight = child.getLayoutParams().height;  
  115.         //图片宽度  
  116.         final int imageWidth = child.getLayoutParams().width;  
  117.           
  118.         //返回旋转角度的绝对值  
  119.         final int rotation = Math.abs(rotationAngle);  
  120.           
  121.         // 在Z轴上正向移动camera的视角,实际效果为放大图片。  
  122.         // 如果在Y轴上移动,则图片上下移动;X轴上对应图片左右移动。  
  123.         mCamera.translate(0.0f, 0.0f, 100.0f);  
  124.         // As the angle of the view gets less, zoom in  
  125.         if (rotation < mMaxRotationAngle) {  
  126.             float zoomAmount = (float) (mMaxZoom + (rotation * 1.5));  
  127.             mCamera.translate(0.0f, 0.0f, zoomAmount);  
  128.         }  
  129.         // 在Y轴上旋转,对应图片竖向向里翻转。  
  130.         // 如果在X轴上旋转,则对应图片横向向里翻转。  
  131.         mCamera.rotateY(rotationAngle);  
  132.         mCamera.getMatrix(imageMatrix);  
  133.         imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));  
  134.         imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));  
  135.         mCamera.restore();  
  136.     }  
  137. }  

主要的方法就是:

[java]  view plain copy
  1. //控制gallery中每个图片的旋转(重写的gallery中方法)  
  2.     protected boolean getChildStaticTransformation(View child, Transformation t) {    
  3.         //取得当前子view的半径值  
  4.         final int childCenter = getCenterOfView(child);         
  5.         final int childWidth = child.getWidth();  
  6.         //旋转角度  
  7.         int rotationAngle = 0;  
  8.         //重置转换状态  
  9.         t.clear();  
  10.         //设置转换类型  
  11.         t.setTransformationType(Transformation.TYPE_MATRIX);  
  12.         //如果图片位于中心位置不需要进行旋转  
  13.         if (childCenter == mCoveflowCenter) {  
  14.             transformImageBitmap((ImageView) child, t, 0);  
  15.         } else {  
  16.             //根据图片在gallery中的位置来计算图片的旋转角度  
  17.             rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);  
  18.             System.out.println("rotationAngle:" +rotationAngle);  
  19.             //如果旋转角度绝对值大于最大旋转角度返回(-mMaxRotationAngle或mMaxRotationAngle;)  
  20.             if (Math.abs(rotationAngle) > mMaxRotationAngle) {  
  21.                 rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;  
  22.             }  
  23.             transformImageBitmap((ImageView) child, t, rotationAngle);  
  24.         }  
  25.         return true;  
  26.     }  

先根据图片所处的位置计算出需要旋转的角度,然后进行旋转:

[java]  view plain copy
  1. //根据图片在gallery中的位置来计算图片的旋转角度  
  2.          rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);  
  3.          System.out.println("rotationAngle:" +rotationAngle);  
  4.          //如果旋转角度绝对值大于最大旋转角度返回(-mMaxRotationAngle或mMaxRotationAngle;)  
  5.          if (Math.abs(rotationAngle) > mMaxRotationAngle) {  
  6.              rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;  
  7.          }  
  8.          transformImageBitmap((ImageView) child, t, rotationAngle);  

主要功能实现是在transformImageBitmap()这个方法:

[java]  view plain copy
  1. private void transformImageBitmap(ImageView child, Transformation t,  
  2.                     int rotationAngle) {  
  3.         //对效果进行保存  
  4.         mCamera.save();  
  5.         final Matrix imageMatrix = t.getMatrix();  
  6.         //图片高度  
  7.         final int imageHeight = child.getLayoutParams().height;  
  8.         //图片宽度  
  9.         final int imageWidth = child.getLayoutParams().width;  
  10.           
  11.         //返回旋转角度的绝对值  
  12.         final int rotation = Math.abs(rotationAngle);  
  13.           
  14.         // 在Z轴上正向移动camera的视角,实际效果为放大图片。  
  15.         // 如果在Y轴上移动,则图片上下移动;X轴上对应图片左右移动。  
  16.         mCamera.translate(0.0f, 0.0f, 100.0f);  
  17.         // As the angle of the view gets less, zoom in  
  18.         if (rotation < mMaxRotationAngle) {  
  19.             float zoomAmount = (float) (mMaxZoom + (rotation * 1.5));  
  20.             mCamera.translate(0.0f, 0.0f, zoomAmount);  
  21.         }  
  22.         // 在Y轴上旋转,对应图片竖向向里翻转。  
  23.         // 如果在X轴上旋转,则对应图片横向向里翻转。  
  24.         mCamera.rotateY(rotationAngle);  
  25.         mCamera.getMatrix(imageMatrix);  
  26.         imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));  
  27.         imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));  
  28.         mCamera.restore();  
  29.     }  

主要进行翻转操作。


关于滑动速度的修改需要重写onFling这个方法,如果想滑动一次只切换一张图片,可以试一下下面这个方法:

[java]  view plain copy
  1. private boolean isScrollingLeft(MotionEvent e1, MotionEvent e2) {    
  2.         return e2.getX() > e1.getX();    
  3.     }    
  4.     
  5.     @Override    
  6.     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {    
  7.         // e1是按下的事件,e2是抬起的事件    
  8.         int keyCode;    
  9.         if (isScrollingLeft(e1, e2)) {    
  10.             keyCode = KeyEvent.KEYCODE_DPAD_LEFT;    
  11.         } else {    
  12.             keyCode = KeyEvent.KEYCODE_DPAD_RIGHT;    
  13.         }    
  14.         onKeyDown(keyCode, null);    
  15.         return true;    
  16.     }    

只是简单的把onFling里面的滑动转换为了点击物理左右方向键。




最后,下载地址:http://download.csdn.net/detail/aomandeshangxiao/4211424

如果这篇文章对您有用,劳烦几秒钟帮忙投下票:http://vote.blog.csdn.net/item/blogstar/aomandeshangxiao,Csdn 2012博客之星投票,谢谢!!!

你可能感兴趣的:(自定义带倒影和偏转的超炫Gallery)