Android 对Gallery的挖掘

来源:互联网 发布:十大网络暴力事件 编辑:程序博客网 时间:2024/05/07 19:40
一.循环Gallery

现在看一下官方API的文档,可以看到这样一句话:该类已被弃用,其他水平滚动窗口小部件包括HorizontalScrollView和ViewPager从支持库。因为这个类是API Level 1里面的,时间比较久了。虽说被弃用,也只是不再支持后续的更新,但是我们也可以用它来作为一个学习的例子。所以说即使是Gallery不让用了,我们还可以使用HorizontalScrollView和ViewPager呢。ViewPager已经说过了,今天的主角是Gallery。

  Gallery是用来水平滚动的显示一系列项目Gallery组件可以横向显示一个图像列表,当单击当前图像的后一个图像时,这个图像列表会向左移动一格,当单击当前图像的前一个图像时,这个图像列表会向右移动一样。也可以通过拖动的方式来向左和向右移动图像列表在使用Gallery的时候,我们应指定他的背景,不然它的项目会紧凑的贴在一起,不会产生画廊的效果了。但是,你也可以通过指定Gallery的属性来设置距离,高度等参数来产生画廊的效果。显然这样做比较麻烦,除非自定义一些其他效果。

   最简单的情况是,我们在一个xml布局中添加一个Gallery,如下:

[html] view plaincopy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent" >  
  5.     <Gallery   
  6.         android:layout_width="match_parent"  
  7.         android:layout_height="wrap_content"  
  8.         android:id="@+id/gallery"  
  9.         />  
  10. </RelativeLayout>  
  Gallery有几个xml属性:

  animationDuration当布局已经改变,设置一个过渡动画应该运行多长时间(以毫秒为单位)。

  gravity:项目的位置

  spacing设置项目之间间距

  unselectedAlpha:设置没有选择时的Alpha

  另外Gallery还有一个内部类,Gallery.LayoutParams,继承自LayoutParams,用来提供一个位置来保存当前转换信息和之前的位置转换信息。

  定义完xml文件,之后就是在是在Activity里面实例化Gallery,设置Adapter,看代码

[java] view plaincopy
  1. package com.example.androidgallerydemo;  
  2.   
  3. import com.example.galleryFlowdemo.DGalleryActivity;  
  4. import android.os.Bundle;  
  5. import android.app.Activity;  
  6. import android.content.Intent;  
  7. import android.content.res.TypedArray;  
  8. import android.view.Menu;  
  9. import android.view.View;  
  10. import android.widget.AdapterView;  
  11. import android.widget.AdapterView.OnItemClickListener;  
  12. import android.widget.Gallery;  
  13. import android.widget.ImageView;  
  14. import android.widget.Toast;  
  15.   
  16. public class AndroidGalleryDemo extends Activity {  
  17.   
  18.     private Intent intent;  
  19.     private Gallery gallery;  
  20.     private ImageView imageView;  
  21.     @Override  
  22.     public void onCreate(Bundle savedInstanceState) {  
  23.         super.onCreate(savedInstanceState);  
  24.         setContentView(R.layout.activity_android_gallery_demo);  
  25.           
  26.         gallery=(Gallery) findViewById(R.id.gallery);  
  27.         TypedArray typedArray = obtainStyledAttributes(R.styleable.Gallery);  //设置背景风格。Gallery背景风格定义在attrs.xml中    
  28.         MyImageAdapter adapter=new MyImageAdapter(this);  
  29.         adapter.setmGalleryItemBackground(typedArray.getResourceId(R.styleable.Gallery_android_galleryItemBackground, 0));  //设置gallery背景  
  30.         gallery.setAdapter(adapter);    
  31.         gallery.setOnItemClickListener(new OnItemClickListener() {  
  32.   
  33.             public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,  
  34.                     long arg3) {  
  35.                 Toast.makeText(AndroidGalleryDemo.this"" + arg2, Toast.LENGTH_SHORT).show();  
  36.                 switch(arg2){  
  37.                 case 0:  
  38.                     intent=new Intent(AndroidGalleryDemo.this,DGalleryActivity.class);  
  39.                     startActivity(intent);  
  40.                 }  
  41.             }  
  42.               
  43.         });  
  44.     }  
  45.   
  46.     @Override  
  47.     public boolean onCreateOptionsMenu(Menu menu) {  
  48.         getMenuInflater().inflate(R.menu.activity_android_gallery_demo, menu);  
  49.         return true;  
  50.     }  
  51. }  
  这里我们需要自己定义一个Adapter,继承自BaseAdapter,BaseAdapter是一个非常重要的类,大家一定要熟练掌握如何继承各种形式的BaseAdapter。代码如下:

[java] view plaincopy
  1. package com.example.androidgallerydemo;  
  2.   
  3. import android.content.Context;  
  4. import android.view.View;  
  5. import android.view.ViewGroup;  
  6. import android.widget.BaseAdapter;  
  7. import android.widget.Gallery;  
  8. import android.widget.ImageView;  
  9.   
  10. /* 
  11.  *  MyImageAdapter 用来控制gallery的资源和操作. 
  12.  */  
  13. public class MyImageAdapter extends BaseAdapter {  
  14.   
  15.     private int mGalleryItemBackground;// 用来设置gallery的风格  
  16.       
  17.     public int getmGalleryItemBackground() {  
  18.         return mGalleryItemBackground;  
  19.     }  
  20.   
  21.     public void setmGalleryItemBackground(int mGalleryItemBackground) {  
  22.         this.mGalleryItemBackground = mGalleryItemBackground;  
  23.     }  
  24.   
  25.     private Context context;  
  26.     private Integer[] imageids={R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d};//图片的资源ID,我们在gallery浏览的图片    
  27.       
  28.     public MyImageAdapter(Context context){//构造函数    
  29.         this.context=context;  
  30.     }  
  31.       
  32.     public int getCount() {//返回所有图片的个数            
  33.         return imageids.length;  
  34.     }  
  35.   
  36.     public Object getItem(int arg0) { //返回图片在资源的位置            
  37.         return arg0;  
  38.     }  
  39.   
  40.     public long getItemId(int position) {//返回图片在资源的位置         
  41.         return position;  
  42.     }  
  43.   
  44.     public View getView(int position, View convertView, ViewGroup parent) {  //此方法是最主要的,他设置好的ImageView对象返回给Gallery    
  45.         ImageView imageview = new ImageView(context);   
  46.         imageview.setImageResource(imageids[position]);  <span style="font-family: 'Microsoft YaHei'; font-size: 12px; background-color: rgb(247, 247, 247); ">//通过索引获得图片并设置给ImageView  </span>  
  47.         imageview.setScaleType(ImageView.ScaleType.FIT_XY); <span style="font-family: 'Microsoft YaHei'; font-size: 12px; background-color: rgb(247, 247, 247); ">//设置ImageView的伸缩规格,用了自带的属性值</span>  
  48.         imageview.setLayoutParams(new Gallery.LayoutParams(128128));<span style="font-family: 'Microsoft YaHei'; font-size: 12px; background-color: rgb(247, 247, 247); ">//设置布局参数  </span>  
  49.         imageview.setBackgroundResource(mGalleryItemBackground); //设置风格,此风格的配置是在xml中    
  50.         return imageview;  
  51.     }  
  52. }  
  还有就是背景的样式,ImageAdapter类的构造方法中获得了Gallery组件的属性信息。这些信息被定义在res\values\attrs.xml文件中,代码如下:

[html] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <declare-styleable name="Gallery">  
  4.         <attr name="android:galleryItemBackground" />  
  5.     </declare-styleable>  
  6. </resources>  
它就是来产生那个方框的效果的,这样就完成了最简单的gallery的使用,效果如下:

 

   二.循环Gallery

下面对这个例子做一下拓展,常规做法,Gallery组件只能有限地显示指定的图像。也就是说,如果为Gallery组件指定了4张图像,那么当Gallery组件显示到第4张时,就不会再继续显示了。这虽然在大多数时候没有什么关系,但在某些情况下,我们希望图像显示到最后一张时再重第1张开始显示,也就是循环显示。要实现这种风格的Gallery组件,就需要对GalleryAdapter对象进行一番修改。本来想在Api提供的方法中寻找突破口,但是却未果,可能还是自己水平不行,所以只能借鉴一下网上的一个解决方法。

  ImageAdapter类中有两个非常重要的方法:getCountgetView。其中getCount方法用于返回图像总数,要注意的是,这个总数不能大于图像的实际数(可以小于图像的实际数),否则会抛出越界异常。当Gallery组件要显示某一个图像时,就会调用getView方法,并将当前的图像索引(position参数)传入该方法。一般getView方法用于返回每一个显示图像的组件(ImageView对象)。从这一点可以看出,Gallery组件是即时显示图像的,而不是一下将所有的图像都显示出来。在getView方法中除了创建了ImageView对象,还用从resIds数组中获得了相应的图像资源ID来设置在ImageView中显示的图像。最后还设置了Gallery组件的背景显示风格。所以position的数值和getCount是对应的,比如我们这里是四个图片,那么position就是从0到3.如果我们想要实现循环那么当position的数值超过3时就应该让它变为0,解决方法就是取余,用position来除图片数组的长度,公式是:imageids=[position%imageids.length]。这样,当position超过3时,它的值是4,而图片数组长度也是4,求余就是0,这样gallery就会显示数组里第一个图片,同理当position为5,求余为1,显示第二个图片,以此类推。

   这样,只要在之前的MyImageAdapter修改一下即可,一个是getCount返回值为:

[java] view plaincopy
  1. public int getCount()  
  2.        {  
  3.            return Integer.MAX_VALUE;  
  4.        }  
    一个是设置图片显示资源为: imageView.setImageResource(resIds[position % resIds.length]);

  当然,这种方法从本质上说只是伪循环,也就是说,如果真把图像移动到getCount方法返回的值那里,那也就显示到最后一个图像的。不过在这里getCount方法返回的是Integer.MAX_VALUE,这个值超过了20亿,除非有人真想把图像移动到第20亿的位置,否则Gallery组件看着就是一个循环显示图像的组件。 

   三.菜单Gallery

  而且,gallery有很多的方法供我们使用,比如选中一个项目,项目移动,keyDown,keyUp等等。在这里我们是展示了一系列图片,也可以用gallery来当TabWidget作为菜单项。

   这个比较简单了,在gallery的OnClickListener()方法里加载各个页面的布局文件就可以了。有人这么做来替换TabWidget,因为后者比较浪费资源,前者是只有在用时才会加载。

    四.Gallery3D效果

   先看一下效果图,


  那如何实现呢,这个就需要用到关于图像处理方面的类了。

  1.倒影效果的实现:

第一:利用Matrix矩阵来实现图片的旋转。

第二:利用旋转后的图片创建一个位图reflectionImage,宽度不变,高度是原始图片的一半(自己可以随意设置),就是效果图中倒影的大小

第三:创建一个能包含原始图片和倒影图片的位图finalReflection(宽度一样,高度是原始图片的高度加上倒影图片的高度)

第四:用刚创建的位图finalReflection创建一个画布

第五:把原始图片和倒影图片添加到画布上去

第六:创建线性渐变LinearGradient对象,实现倒影图片所在的区域是渐变效果


这个写在MyImageAdapter里面就可以了,代码如下:

[java] view plaincopy
  1. import android.content.res.Resources;  
  2. import android.graphics.Bitmap;  
  3. import android.graphics.BitmapFactory;  
  4. import android.graphics.Canvas;  
  5. import android.graphics.LinearGradient;  
  6. import android.graphics.Matrix;  
  7. import android.graphics.Paint;  
  8. import android.graphics.PorterDuffXfermode;  
  9. import android.graphics.Bitmap.Config;  
  10. import android.graphics.PorterDuff.Mode;  
  11. import android.graphics.Shader.TileMode;  
  12. import android.view.View;  
  13. import android.view.ViewGroup;  
  14. import android.widget.BaseAdapter;  
  15. import android.widget.ImageView;  
  16. import android.widget.ImageView.ScaleType;  
  17.   
  18. public class ImageAdapter extends BaseAdapter {  
  19.     int mGalleryItemBackground;  
  20.     private Context mContext;  
  21.     private Integer[] mImageIds;  
  22.     private ImageView[] mImages;  
  23.     public ImageAdapter(Context c, Integer[] ImageIds) {  
  24.         mContext = c;  
  25.         mImageIds = ImageIds;  
  26.         mImages = new ImageView[mImageIds.length];  
  27.     }  
  28.     public boolean createReflectedImages() {  
  29.         final int reflectionGap = 4;  
  30.         int index = 0;  
  31.         for (int imageId : mImageIds) {  
  32.             Bitmap originalImage = BitmapFactory.decodeResource(mContext  
  33.                     .getResources(), imageId);  
  34.             int width = originalImage.getWidth();  
  35.             int height = originalImage.getHeight();  
  36.             Matrix matrix = new Matrix();  
  37.             matrix.preScale(1, -1);  
  38.             Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0,  
  39.                     height / 2, width, height / 2, matrix, false);  
  40.             Bitmap bitmapWithReflection = Bitmap.createBitmap(width,  
  41.                     (height + height / 2), Config.ARGB_8888);  
  42.   
  43.             Canvas canvas = new Canvas(bitmapWithReflection);  
  44.             canvas.drawBitmap(originalImage, 00null);  
  45.             Paint deafaultPaint = new Paint();  
  46.             canvas.drawRect(0, height, width, height + reflectionGap,  
  47.                     deafaultPaint);  
  48.   
  49.             canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);  
  50.             Paint paint = new Paint();  
  51.             LinearGradient shader = new LinearGradient(0, originalImage  
  52.                     .getHeight(), 0, bitmapWithReflection.getHeight()  
  53.                     + reflectionGap, 0x70ffffff0x00ffffff, TileMode.CLAMP);  
  54.   
  55.             paint.setShader(shader);  
  56.             paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));  
  57.             canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()  
  58.                     + reflectionGap, paint);  
  59.             ImageView imageView = new ImageView(mContext);  
  60.             imageView.setImageBitmap(bitmapWithReflection);  
  61.             imageView.setLayoutParams(new GalleryFlow.LayoutParams(180240));  
  62.             imageView.setScaleType(ScaleType.MATRIX);  
  63.             mImages[index++] = imageView;  
  64.         }  
  65.         return true;  
  66.     }  
  67.     private Resources getResources() {  
  68.         // TODO Auto-generated method stub  
  69.         return null;  
  70.     }  
  71.     public int getCount() {  
  72.         return mImageIds.length;  
  73.     }  
  74.     public Object getItem(int position) {  
  75.         return position;  
  76.     }  
  77.     public long getItemId(int position) {  
  78.         return position;  
  79.     }  
  80.     public View getView(int position, View convertView, ViewGroup parent) {  
  81.         return mImages[position];  
  82.     }  
  83.         public float getScale(boolean focused, int offset) {  
  84.         return Math.max(01.0f / (float) Math.pow(2, Math.abs(offset)));  
  85.     }  
  86.   
  87. }  
这样就实现倒影效果了,那如何在gallery中显示呢,我们还需要重写Gallery,才会显示如上的效果,如果不重写而是直接运行的话不仅没有效果还会报错。重写的目的就是实现像上面那样,图片有间距等效果,代码如下:

[java] view plaincopy
  1. import android.content.Context;  
  2. import android.graphics.Camera;  
  3. import android.graphics.Matrix;  
  4. import android.util.AttributeSet;  
  5. import android.view.View;  
  6. import android.view.animation.Transformation;  
  7. import android.widget.Gallery;  
  8. import android.widget.ImageView;  
  9.   
  10. public class GalleryFlow extends Gallery {  
  11.   
  12.     private Camera mCamera = new Camera();  
  13.     private int mMaxRotationAngle = 60;  
  14.     private int mMaxZoom = -120;  
  15.     private int mCoveflowCenter;  
  16.     public GalleryFlow(Context context) {  
  17.             super(context);  
  18.             this.setStaticTransformationsEnabled(true);  
  19.     }  
  20.     public GalleryFlow(Context context, AttributeSet attrs) {  
  21.             super(context, attrs);  
  22.             this.setStaticTransformationsEnabled(true);  
  23.     }  
  24.     public GalleryFlow(Context context, AttributeSet attrs, int defStyle) {  
  25.             super(context, attrs, defStyle);  
  26.             this.setStaticTransformationsEnabled(true);  
  27.     }  
  28.     public int getMaxRotationAngle() {  
  29.             return mMaxRotationAngle;  
  30.     }  
  31.     public void setMaxRotationAngle(int maxRotationAngle) {  
  32.             mMaxRotationAngle = maxRotationAngle;  
  33.     }  
  34.     public int getMaxZoom() {  
  35.             return mMaxZoom;  
  36.     }  
  37.     public void setMaxZoom(int maxZoom) {  
  38.             mMaxZoom = maxZoom;  
  39.     }  
  40.     private int getCenterOfCoverflow() {  
  41.             return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2  
  42.                             + getPaddingLeft();  
  43.     }  
  44.     private static int getCenterOfView(View view) {  
  45.             return view.getLeft() + view.getWidth() / 2;  
  46.     }  
  47.     protected boolean getChildStaticTransformation(View child, Transformation t) {  
  48.             final int childCenter = getCenterOfView(child);  
  49.             final int childWidth = child.getWidth();  
  50.             int rotationAngle = 0;  
  51.             t.clear();  
  52.             t.setTransformationType(Transformation.TYPE_MATRIX);  
  53.             if (childCenter == mCoveflowCenter) {  
  54.                     transformImageBitmap((ImageView) child, t, 0);  
  55.             } else {  
  56.                     rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);  
  57.                     if (Math.abs(rotationAngle) > mMaxRotationAngle) {  
  58.                             rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle  
  59.                                             : mMaxRotationAngle;  
  60.                     }  
  61.                     transformImageBitmap((ImageView) child, t, rotationAngle);  
  62.             }  
  63.             return true;  
  64.     }  
  65.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  66.             mCoveflowCenter = getCenterOfCoverflow();  
  67.             super.onSizeChanged(w, h, oldw, oldh);  
  68.     }  
  69.     private void transformImageBitmap(ImageView child, Transformation t,  
  70.                     int rotationAngle) {  
  71.             mCamera.save();  
  72.             final Matrix imageMatrix = t.getMatrix();  
  73.             final int imageHeight = child.getLayoutParams().height;  
  74.             final int imageWidth = child.getLayoutParams().width;  
  75.             final int rotation = Math.abs(rotationAngle);  
  76.             // 在Z轴上正向移动camera的视角,实际效果为放大图片。  
  77.             // 如果在Y轴上移动,则图片上下移动;X轴上对应图片左右移动。  
  78.             mCamera.translate(0.0f, 0.0f, 100.0f);  
  79.             // As the angle of the view gets less, zoom in  
  80.             if (rotation < mMaxRotationAngle) {  
  81.                     float zoomAmount = (float) (mMaxZoom + (rotation * 1.5));  
  82.                     mCamera.translate(0.0f, 0.0f, zoomAmount);  
  83.             }  
  84.             // 在Y轴上旋转,对应图片竖向向里翻转。  
  85.             // 如果在X轴上旋转,则对应图片横向向里翻转。  
  86.             mCamera.rotateY(rotationAngle);  
  87.             mCamera.getMatrix(imageMatrix);  
  88.             imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));  
  89.             imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));  
  90.             mCamera.restore();  
  91.     }  
  92. }  

至此就完成了3D效果显示,其实Gallery还有很多其他的可以实现的效果。大家只要有想法就去实现吧!


来源:http://blog.csdn.net/wangjinyu501/article/details/8179206