您的位置:首页 > 移动开发 > Android开发

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

2014-10-25 20:35 555 查看
转载请注明出处:/article/10736890.html

最近在学习自定义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>


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

源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: