Android自定义View之Gallery实现3D图片播放器

转载请注明出处:http://blog.csdn.net/joker_ya/article/details/40456373

最近在学习自定义View。刚好有讲到Gallery控件,所以今天就弄出来和大家一起分享分享。


首先我们来看看效果吧:


ps:不知道为什么,上传的gif图都不会动的。这让我很困扰!

接下来就是贴代码了,先看看目录:

MainActivity.java主Activity文件内容比较简单,没什么好说的:

package com.example.mygallerydemo;

import com.example.mygallery.MyGallery;
import com.example.mygalleryadapter.MyAdapter;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;

/**
 * 
 * @author Joker_Ya
 * 
 */
public class MainActivity extends ActionBarActivity {

	private MyGallery myGallery;
	private MyAdapter adapter;
	private int[] imageIds = new int[] { R.drawable.girl1, R.drawable.girl2,
			R.drawable.girl3, R.drawable.girl4, R.drawable.girl5,
			R.drawable.girl6 };

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		myGallery = (MyGallery) findViewById(R.id.my_gallery);

		adapter = new MyAdapter(this, imageIds);
		adapter.createReflectedBitmap();

		myGallery.setAdapter(adapter);
	}

}


接下来就是MyAdapter.java了,该类继承BaseAdapter,并对图片资源进行了投影操作:
package com.example.mygalleryadapter;

import com.example.mygallery.MyGallery;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
/**
 * 
 * @author Joker_Ya
 *
 */
public class MyAdapter extends BaseAdapter {
	private Context context;
	private int[] imageIds;
	private ImageView[] images;

	public MyAdapter(Context context, int[] imageIds) {
		super();
		this.context = context;
		this.imageIds = imageIds;
		images = new ImageView[imageIds.length];
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return images.length;
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(int position, View arg1, ViewGroup arg2) {
		// TODO Auto-generated method stub
		return images[position];
	}

	/**
	 * 生成带有阴影效果的图片
	 */
	@SuppressWarnings("deprecation")
	public void createReflectedBitmap() {
		// TODO Auto-generated method stub
		int index = 0;
		int ReflectionGap = 4;// 原图片于倒影之间的距离

		for (int imageId : imageIds) {
			// 源图片
			Bitmap resourceBitmap = BitmapFactory.decodeResource(
					context.getResources(), imageId);
			// 得到源图片的宽高
			int width = resourceBitmap.getWidth();
			int height = resourceBitmap.getHeight();

			Matrix matrix = new Matrix();
			// x水平翻转 y垂直翻转 1 正常 -1翻转
			matrix.setScale(1, -1);
			// 生成倒影图片(设置其宽为源图片的宽 高为源图片高的一半)
			// Bitmap.createBitmap(source, x, y, width, height, m, filter);
			// Bitmap source 源图片
			// x,y 生成倒影图片的起始位置 左上角
			// width,height 图片的宽高
			// Matrix m 用来 设置图片的样式 (倒影)

			Bitmap reflectionBitmap = Bitmap.createBitmap(resourceBitmap, 0,
					height / 2, width, height / 2, matrix, false);
			// 生成带有倒影的图片 宽为源图片的宽(width)
			// 高为源图片的高(height)加上倒影图片的高度(height/2)
			Bitmap bitmap = Bitmap.createBitmap(width, height + height / 2,
					Config.ARGB_8888);
			// 以带有倒影图片的宽高生成一样大小的画布
			Canvas canvas = new Canvas(bitmap);
			// 绘制源图片
			canvas.drawBitmap(resourceBitmap, 0, 0, null);
			// 绘制矩形--原图片于倒影之间的距离
			Paint defpaint = new Paint();
			canvas.drawRect(0, height, width, height + ReflectionGap, defpaint);
			// 绘制倒影图片
			canvas.drawBitmap(reflectionBitmap, 0, height + ReflectionGap, null);

			Paint paint = new Paint();
			// 遮罩
			paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
			// 渐变
			// 0x70ffffff, 0x00ffffff 渐变颜色范围ARGB
			/*
			 * //线性渐变填充 shader着色器 //在位图上Y方向花砖模式 TileMode:(一共有三种)
			 *  CLAMP :如果渲染器超出原始边界范围,会复制范围内边缘染色。 
			 *  REPEAT :横向和纵向的重复渲染器图片,平铺。 
			 *  MIRROR :横向和纵向的重复渲染器图片,这个和REPEAT 重复方式不一样,他是以镜像方式平铺。
			 */
			LinearGradient gradient = new LinearGradient(0, height, 0,
					bitmap.getHeight(), 0x70ffffff, 0x00ffffff, TileMode.CLAMP);
			// 着色器 用来绘制颜色 上色的
			paint.setShader(gradient);
			canvas.drawRect(0, height, width, bitmap.getHeight(), paint);
			// 加入图片
			ImageView imageView = new ImageView(context);
			BitmapDrawable bd = new BitmapDrawable(bitmap);
			// 消除图片锯齿效果 平滑
			bd.setAntiAlias(true);
			imageView.setImageDrawable(bd);
			// 设置图片的大小
			imageView.setLayoutParams(new MyGallery.LayoutParams(320, 480));
			// 将图片加入到ImageView[]数组中去
			images[index++] = imageView;
		}
	}

}

主要的方法createReflectedBitmap()在代码中有详细的说明了,在这就不赘述了。大致的步骤是:得到源图片-->根据源图片绘制阴影图片-->创建一个画布大小为源图片大小加上阴影图片大小-->将源图片和阴影加入到画布-->得到带有阴影的图片效果。

然后就是MyGallery.java,该类实现图片的旋转:

package com.example.mygallery;

import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.Transformation;
import android.widget.Gallery;
import android.widget.ImageView;

/**
 * 
 * @author Joker_Ya
 * 
 */
@SuppressWarnings("deprecation")
public class MyGallery extends Gallery {

	private Camera camera = new Camera();// 相机 用于对图片进行变化

	private int maxRotateAngle = 50;// 最大旋转角度
	private int maxZoom = -250;// 最大缩放值

	private int currentOfGallery;// gallery中心点

	public MyGallery(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		// 允许对图片进行修改
		setStaticTransformationsEnabled(true);
	}

	public MyGallery(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		setStaticTransformationsEnabled(true);
	}

	// 获得gallery展示图片的中心点
	public int getCurrentOfGallery() {
		// 返回会gallery的中心点:gallery的宽度减去左右边距的一半再加上左边距就为gallery的中心点
		return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2
				+ getPaddingLeft();
	}

	// 获得图片的中心店
	public int getCurrentOfView(View view) {
		return view.getLeft() + view.getWidth() / 2;
	}

	// 横竖屏改变的时候调用
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		// TODO Auto-generated method stub
		currentOfGallery = getCurrentOfGallery();
		super.onSizeChanged(w, h, oldw, oldh);
	}

	@Override
	protected boolean getChildStaticTransformation(View child, Transformation t) {
		// TODO Auto-generated method stub
		// 得到图片的中心点和宽高
		int currentOfChild = getCurrentOfView(child);
		int width = child.getWidth();
		// int height=child.getLayoutParams().height;
		int rotateAngle = 0;// 旋转角度

		t.clear();
		// 图片变形的风格样式
		t.setTransformationType(Transformation.TYPE_MATRIX);
		Log.v(child.getId() + "currentOfChild", currentOfChild + "");
		Log.v(child.getId() + "currentOfGallery", currentOfGallery + "");
		if (currentOfChild == currentOfGallery) {// 判断图片是否为gallery的中心位置
			// 在中心位置
			transformationBitmap((ImageView) child, t, 0);
		} else {
			// 不在中心位置
			rotateAngle = (int) ((float) (currentOfGallery - currentOfChild)
					/ width * maxRotateAngle);// 获得旋转角度
			if (Math.abs(rotateAngle) > maxRotateAngle) {
				// 旋转角度>最大旋转角度
				// 判断rotateAngle是否小于零 小于则返回-maxRotateAngle 否则返回maxRotateAngle
				rotateAngle = rotateAngle < 0 ? -maxRotateAngle
						: maxRotateAngle;
			}
			transformationBitmap((ImageView) child, t, rotateAngle);
		}
		return true;
	}

	/**
	 * 图片变形
	 * 
	 * @param child
	 *            需要变形的图片
	 * @param t
	 *            变形的风格样式
	 * @param rotateAngle
	 *            旋转角度
	 */
	private void transformationBitmap(ImageView child, Transformation t,
			int rotateAngle) {
		// TODO Auto-generated method stub
		camera.save();// 保存

		Matrix matrix = t.getMatrix();
		int rotate = Math.abs(rotateAngle);
		int imageWidth = child.getWidth();
		int imageHeight = child.getHeight();

		// z轴 正数 图片变大 x水平移动 y垂直移动
		camera.translate(0.0f, 0.0f, 100.0f);

		if (rotate < maxRotateAngle) {
			float zoom = (float) (rotate * 1.5 + maxZoom);
			camera.translate(0.0f, 0.0f, zoom);
			child.setAlpha((int) (255 - rotate * 2.5));
		}
		// 图片向展示中心 进行垂直角度的旋转
		camera.rotateY(rotateAngle);
		camera.getMatrix(matrix);

		// Preconcats matrix相当于右乘矩阵
		// Postconcats matrix相当于左乘矩阵。
		/*
		 * 这两行代码意思可能就不那么明显了,先说如果不加这两行代码,会是一个什么情况, 默认情况下,动画是以对象的左上角为起点的,如果这样的话,
		 * 动画的效果就变成了可见对象在它的左上角开始,逐渐向右下角扩大,这显然不是我们期望的。
		 * 所以我们前面用到的halfWidth,halfHeight就用到了,这里保存了可见对象的一半宽度和高度,也就是中点,
		 * 使用上面这两个方法后,就会改变动画的起始位置,动画默认是从右下角开始扩大的,
		 * 使用matrix.preTranslate(-halfWidth, -halfHeight) 就把扩散点移到了中间,
		 * 同样,动画的起始点为左上角,使用matrix.postTranslate(halfWidth,
		 * halfHeight)就把起始点移到了中间, 这样就实现我们期望的效果了。
		 */
		matrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));
		matrix.postTranslate((imageWidth / 2), (imageHeight / 2));

		camera.restore();// 还原
	}

}


可能是判断中间点的数据有问题,所以才会出现中间图片不是正面显示的效果。


最后是布局文件activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000000"
    tools:context="com.example.mygallerydemo.MainActivity" >

    <com.example.mygallery.MyGallery 
        android:id="@+id/my_gallery"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        />
    
</RelativeLayout>

好了,也没什么好说的了。附上源码下载地址:

源码下载


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值