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

本文介绍如何在Android Gallery中实现图片的倒影效果和偏转效果,包括使用Bitmap合成图片、设置渐变透明度及利用Camera API实现图片倾斜。

      


   先看下主类代码:

  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()这个方法:

  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设置高度。

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

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

  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文件中:

  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,来看下它的代码:

  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. }  

主要的方法就是:

  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.     }  

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

  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()这个方法:

  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这个方法,如果想滑动一次只切换一张图片,可以试一下下面这个方法:

  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里面的滑动转换为了点击物理左右方向键。

数据驱动的两阶段分布鲁棒(1-范数∞-范数约束)的电热综合能源系统研究(Matlab代码实现)内容概要:本文围绕“数据驱动的两阶段分布鲁棒(1-范数∞-范数约束)的电热综合能源系统研究”展开,提出了一种结合数据驱动与分布鲁棒优化方法的建模框架,用于解决电热综合能源系统在不确定性环境下的优化调度问题。研究采用两阶段优化结构,第一阶段进行预决策,第二阶段根据实际场景进行调整,通过引入1-范数∞-范数约束来构建不确定集,有效刻画风电、负荷等不确定性变量的波动特性,提升模型的鲁棒性实用性。文中提供了完整的Matlab代码实现,便于读者复现验证算法性能,并结合具体案例分析了不同约束条件下系统运行的经济性与可靠性。; 适合人群:具备一定电力系统、优化理论Matlab编程基础的研究生、科研人员及工程技术人员,尤其适合从事综合能源系统、鲁棒优化、不确定性建模等相关领域研究的专业人士。; 使用场景及目标:①掌握数据驱动的分布鲁棒优化方法在综合能源系统中的应用;②理解1-范数∞-范数在构建不确定集中的作用与差异;③学习两阶段鲁棒优化模型的建模思路与Matlab实现技巧,用于科研复现、论文写作或工程项目建模。; 阅读建议:建议读者结合提供的Matlab代码逐段理解算法实现细节,重点关注不确定集构建、两阶段模型结构设计及求解器调用方式,同时可尝试更换数据或调整约束参数以加深对模型鲁棒性的理解。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值