HardBirch

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

时间:12-04-10 栏目:安卓源码解析与小应用 作者:张飞不张,文采横飞 评论:21 点击: 9,248 次

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

     先看下主类代码:

public class GalleryDemoActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    	super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.main);

        Integer[] images = { R.drawable.image01,
        					 R.drawable.image02,
        					 R.drawable.image03,
        					 R.drawable.image04,
        					 R.drawable.image05};

        ImageAdapter adapter = new ImageAdapter(this, images);
        adapter.createReflectedImages();//创建倒影效果
        GalleryFlow galleryFlow = (GalleryFlow) this.findViewById(R.id.gallery);
        galleryFlow.setFadingEdgeLength(0);
        galleryFlow.setSpacing(10); //图片之间的间距
        galleryFlow.setAdapter(adapter);

        galleryFlow.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                Toast.makeText(getApplicationContext(), String.valueOf(position), Toast.LENGTH_SHORT).show();
            }

        });
        galleryFlow.setSelection(4);
    }

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

/**
     * 创建倒影效果
     * @return
     */
    public boolean createReflectedImages() {
     //倒影图和原图之间的距离
     final int reflectionGap = 4;
     int index = 0;
     for (int imageId : mImageIds) {
	      //返回原图解码之后的bitmap对象
	      Bitmap originalImage = BitmapFactory.decodeResource(mContext.getResources(), imageId);
	      int width = originalImage.getWidth();
	      int height = originalImage.getHeight();
	      //创建矩阵对象
	      Matrix matrix = new Matrix();

	      //指定一个角度以0,0为坐标进行旋转
	      // matrix.setRotate(30);

	      //指定矩阵(x轴不变,y轴相反)
	      matrix.preScale(1, -1);

	      //将矩阵应用到该原图之中,返回一个宽度不变,高度为原图1/2的倒影位图
	      Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0,
	        height/2, width, height/2, matrix, false);

	      //创建一个宽度不变,高度为原图+倒影图高度的位图
	      Bitmap bitmapWithReflection = Bitmap.createBitmap(width,
	        (height + height / 2), Config.ARGB_8888);

	      //将上面创建的位图初始化到画布
	      Canvas canvas = new Canvas(bitmapWithReflection);
	      canvas.drawBitmap(originalImage, 0, 0, null);

	      Paint deafaultPaint = new Paint();
	      deafaultPaint.setAntiAlias(false);
	//    canvas.drawRect(0, height, width, height + reflectionGap,deafaultPaint);
	      canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);
	      Paint paint = new Paint();
	      paint.setAntiAlias(false);

	      /**
	       * 参数一:为渐变起初点坐标x位置,
	       * 参数二:为y轴位置,
	       * 参数三和四:分辨对应渐变终点,
	       * 最后参数为平铺方式,
	       * 这里设置为镜像Gradient是基于Shader类,所以我们通过Paint的setShader方法来设置这个渐变
	       */
	      LinearGradient shader = new LinearGradient(0,originalImage.getHeight(), 0,
	              bitmapWithReflection.getHeight() + reflectionGap,0x70ffffff, 0x00ffffff, TileMode.MIRROR);
	      //设置阴影
	      paint.setShader(shader);
	      paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));
	      //用已经定义好的画笔构建一个矩形阴影渐变效果
	      canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()+ reflectionGap, paint);

	      //创建一个ImageView用来显示已经画好的bitmapWithReflection
	      ImageView imageView = new ImageView(mContext);
	      imageView.setImageBitmap(bitmapWithReflection);
	      //设置imageView大小 ,也就是最终显示的图片大小
	      imageView.setLayoutParams(new GalleryFlow.LayoutParams(200, 300));
	      //imageView.setScaleType(ScaleType.MATRIX);
	      mImages[index++] = imageView;
     }
     return true;
    }

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

public static Bitmap createBitmap (Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)

Since: API Level 1
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.
Parameters

source	The bitmap we are subsetting
x	The x coordinate of the first pixel in source
y	The y coordinate of the first pixel in source
width	The number of pixels in each row
height	The number of rows
m	Optional matrix to be applied to the pixels
filter	true if the source should be filtered. Only applies if the matrix contains more than just translation.
Returns

A bitmap that represents the specified subset of source
Throws

IllegalArgumentException	if the x, y, width, height values are outside of the dimensions of the source bitmap.

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

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

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

 /**
	       * 参数一:为渐变起初点坐标x位置,
	       * 参数二:为y轴位置,
	       * 参数三和四:分辨对应渐变终点,
	       * 最后参数为平铺方式,
	       * 这里设置为镜像Gradient是基于Shader类,所以我们通过Paint的setShader方法来设置这个渐变
	       */
	      LinearGradient shader = new LinearGradient(0,originalImage.getHeight(), 0,
	              bitmapWithReflection.getHeight() + reflectionGap,0x70ffffff, 0x00ffffff, TileMode.MIRROR);

    看完倒影,再来看一下偏转,在main.xml文件中:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    >
    <nsouth.jonas.android.GalleryFlow
	    android:layout_width="match_parent"
	    android:layout_height="match_parent"
	    android:gravity="center_vertical"
	    android:id="@+id/gallery"
 	/>
</LinearLayout>

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

public class GalleryFlow extends Gallery{
	private Camera mCamera = new Camera();//相机类
    private int mMaxRotationAngle = 60;//最大转动角度
    private int mMaxZoom = -280;////最大缩放值
    private int mCoveflowCenter;//半径值

    public GalleryFlow(Context context) {
        super(context);
        //支持转换 ,执行getChildStaticTransformation方法
        this.setStaticTransformationsEnabled(true);
    }

    public GalleryFlow(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setStaticTransformationsEnabled(true);
    }

    public GalleryFlow(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setStaticTransformationsEnabled(true);
    }

    /**
     * 获取旋转最大角度
     * @return
     */
    public int getMaxRotationAngle() {
        return mMaxRotationAngle;
    }

    /**
     * 设置旋转最大角度
     * @param maxRotationAngle
     */
    public void setMaxRotationAngle(int maxRotationAngle) {
        mMaxRotationAngle = maxRotationAngle;
    }

    /**
     * 获取最大缩放值
     * @return
     */
    public int getMaxZoom() {
        return mMaxZoom;
    }

    /**
     * 设置最大缩放值
     * @param maxZoom
     */
    public void setMaxZoom(int maxZoom) {
        mMaxZoom = maxZoom;
    }

    /**
     * 获取半径值
     * @return
     */
    private int getCenterOfCoverflow() {
        return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2
                        + getPaddingLeft();
    }

    /**
     * @param view
     * @return
     */
    private static int getCenterOfView(View view) {
        return view.getLeft() + view.getWidth() / 2;
    }   

   //控制gallery中每个图片的旋转(重写的gallery中方法)
    protected boolean getChildStaticTransformation(View child, Transformation t) {
        //取得当前子view的半径值
        final int childCenter = getCenterOfView(child);
        final int childWidth = child.getWidth();
        //旋转角度
        int rotationAngle = 0;
        //重置转换状态
        t.clear();
        //设置转换类型
        t.setTransformationType(Transformation.TYPE_MATRIX);
        //如果图片位于中心位置不需要进行旋转
        if (childCenter == mCoveflowCenter) {
            transformImageBitmap((ImageView) child, t, 0);
        } else {
            //根据图片在gallery中的位置来计算图片的旋转角度
            rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
            System.out.println("rotationAngle:" +rotationAngle);
            //如果旋转角度绝对值大于最大旋转角度返回(-mMaxRotationAngle或mMaxRotationAngle;)
            if (Math.abs(rotationAngle) > mMaxRotationAngle) {
                rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;
            }
            transformImageBitmap((ImageView) child, t, rotationAngle);
        }
        return true;
    }

    /**
     *
     */
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mCoveflowCenter = getCenterOfCoverflow();
        super.onSizeChanged(w, h, oldw, oldh);
    }

    private void transformImageBitmap(ImageView child, Transformation t,
                    int rotationAngle) {
        //对效果进行保存
        mCamera.save();
        final Matrix imageMatrix = t.getMatrix();
        //图片高度
        final int imageHeight = child.getLayoutParams().height;
        //图片宽度
        final int imageWidth = child.getLayoutParams().width;

        //返回旋转角度的绝对值
        final int rotation = Math.abs(rotationAngle);

        // 在Z轴上正向移动camera的视角,实际效果为放大图片。
        // 如果在Y轴上移动,则图片上下移动;X轴上对应图片左右移动。
        mCamera.translate(0.0f, 0.0f, 100.0f);
        // As the angle of the view gets less, zoom in
        if (rotation < mMaxRotationAngle) {
            float zoomAmount = (float) (mMaxZoom + (rotation * 1.5));
            mCamera.translate(0.0f, 0.0f, zoomAmount);
        }
        // 在Y轴上旋转,对应图片竖向向里翻转。
        // 如果在X轴上旋转,则对应图片横向向里翻转。
        mCamera.rotateY(rotationAngle);
        mCamera.getMatrix(imageMatrix);
        imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));
        imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));
        mCamera.restore();
    }
}

主要的方法就是:

//控制gallery中每个图片的旋转(重写的gallery中方法)
    protected boolean getChildStaticTransformation(View child, Transformation t) {
        //取得当前子view的半径值
        final int childCenter = getCenterOfView(child);
        final int childWidth = child.getWidth();
        //旋转角度
        int rotationAngle = 0;
        //重置转换状态
        t.clear();
        //设置转换类型
        t.setTransformationType(Transformation.TYPE_MATRIX);
        //如果图片位于中心位置不需要进行旋转
        if (childCenter == mCoveflowCenter) {
            transformImageBitmap((ImageView) child, t, 0);
        } else {
            //根据图片在gallery中的位置来计算图片的旋转角度
            rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
            System.out.println("rotationAngle:" +rotationAngle);
            //如果旋转角度绝对值大于最大旋转角度返回(-mMaxRotationAngle或mMaxRotationAngle;)
            if (Math.abs(rotationAngle) > mMaxRotationAngle) {
                rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;
            }
            transformImageBitmap((ImageView) child, t, rotationAngle);
        }
        return true;
    }

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

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

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

private void transformImageBitmap(ImageView child, Transformation t,
                    int rotationAngle) {
        //对效果进行保存
        mCamera.save();
        final Matrix imageMatrix = t.getMatrix();
        //图片高度
        final int imageHeight = child.getLayoutParams().height;
        //图片宽度
        final int imageWidth = child.getLayoutParams().width;

        //返回旋转角度的绝对值
        final int rotation = Math.abs(rotationAngle);

        // 在Z轴上正向移动camera的视角,实际效果为放大图片。
        // 如果在Y轴上移动,则图片上下移动;X轴上对应图片左右移动。
        mCamera.translate(0.0f, 0.0f, 100.0f);
        // As the angle of the view gets less, zoom in
        if (rotation < mMaxRotationAngle) {
            float zoomAmount = (float) (mMaxZoom + (rotation * 1.5));
            mCamera.translate(0.0f, 0.0f, zoomAmount);
        }
        // 在Y轴上旋转,对应图片竖向向里翻转。
        // 如果在X轴上旋转,则对应图片横向向里翻转。
        mCamera.rotateY(rotationAngle);
        mCamera.getMatrix(imageMatrix);
        imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));
        imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));
        mCamera.restore();
    }

主要进行翻转操作。

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

    private boolean isScrollingLeft(MotionEvent e1, MotionEvent e2) {
            return e2.getX() > e1.getX();
        }  

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            // e1是按下的事件,e2是抬起的事件
            int keyCode;
            if (isScrollingLeft(e1, e2)) {
                keyCode = KeyEvent.KEYCODE_DPAD_LEFT;
            } else {
                keyCode = KeyEvent.KEYCODE_DPAD_RIGHT;
            }
            onKeyDown(keyCode, null);
            return true;
        }  

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


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



声明: 本文由( 张飞不张,文采横飞 )原创编译,转载请保留链接: 自定义带倒影和偏转的超炫Gallery

自定义带倒影和偏转的超炫Gallery:目前有21 条留言

  1. 21楼
    hejinhui1314:

    不错,谢谢楼主分享~

    2012-04-10 12:36 [回复]
  2. [reply]hejinhui1314[/reply]
    呵呵,共同学习。。。

    2012-04-10 12:53 [回复]
  3. [reply]hejinhui1314[/reply]
    觉得好,就帮忙顶一下吧,哈哈。

    2012-04-10 15:39 [回复]
  4. 18楼
    zmyde2010:

    多谢分享~

    2012-04-10 16:32 [回复]
  5. [reply]zmyde2010[/reply]
    帮顶下就不成吗???怒了。。。。

    2012-04-10 16:36 [回复]
  6. 16楼
    dajianshi:

    确实不错,顶你

    2012-04-10 23:40 [回复]
  7. [reply]dajianshi[/reply]
    哈哈,谢谢,好好学习,天天向上。。。

    2012-04-10 23:51 [回复]
  8. 太强大

    2012-04-11 14:03 [回复]
  9. [reply]Kevin_jiang2011[/reply]
    有用就好。。。

    2012-04-11 15:12 [回复]
  10. 看起来不错,但用起来总觉得不太顺手

    2012-04-11 16:07 [回复]
  11. [reply]Gongqingshuai[/reply]
    嗯,滑动太快是吧,呵呵,你可以自己修改一下,欢迎探讨啊。如果有好的改进,也请教教我,呵呵。

    2012-04-11 16:36 [回复]
  12. 10楼
    ch5378:

    很好。顶一个。。。

    2012-04-12 11:55 [回复]
  13. 9楼
    yclmy:

    很强大

    2012-04-19 14:40 [回复]
  14. [reply]yclmy[/reply]
    呵呵,慢慢研究。。。

    2012-05-29 11:49 [回复]
  15. 这个效果很好啊 学习

    2012-06-08 16:36 [回复]
  16. [reply]penglijiang[/reply]
    呵呵 从 网上找来学习的。。。

    2012-06-08 16:49 [回复]
  17. 很实用的东西

    2012-08-20 10:40 [回复]
  18. 4楼
    wcnmcsnm:

    我去。。。双击了下顶。。。居然直接+2了=。=
    楼主文章都很好,支持你!

    2012-09-28 16:00 [回复]
  19. [reply]wcnmcsnm[/reply]
    什么时候,我自己能独立写出这样的代码就好了。。。。

    2012-09-28 16:32 [回复]
  20. 想学习下。。。。

    2012-11-19 11:06 [回复]
  21. [reply]YangWangXingFuwhy[/reply]
    想看,直接由代码。。。

    2012-11-19 12:06 [回复]

发表评论


QQ群互动

Linux系统与内核学习群:194051772

WP建站技术学习交流群:194062106

魔豆之路QR

魔豆的Linux内核之路

魔豆的Linux内核之路

优秀工程师当看优秀书籍

优秀程序员,要看优秀书!

赞助商广告

友荐云推荐