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

Android开发之实现最简单最酷炫的3D图片浏览效果(一)

2016-08-16 23:05 861 查看

一、原理

整体实现是以手机屏幕的正中间位置为对称轴,位于正中间的图片显示最大,也最亮,同时左右两边的图片以最中间位置为对称轴,分别旋转对应的角度,同时亮度调整为适当的比例,已达到对称的效果。具体的3D浏览图片效果,我是通过自定义Gallery来实现的,创建一个类GalleryFlow,继承Gallery,在这个类中进行图像的旋转、缩放,亮度设置等操作。同时,在这个类中,我创建了一个相机对象camera来设置图像的变化效果;同时自定义一个图像的适配器类ImageAdapter,这个类继承BaseAdapter,主要是实现界面图片的显示,以及创建带有倒影的图片。

二、实现

1、自定义适配器ImageAdapter

显示图片的适配器,这个类继承BaseAdapter,完成图像的基本显示,同时将原有图片生成带有倒影的图片进行显示。具体的实现为,在构造方法中将界面中的上下文信息,和存放图片id的数组传递过来,通过传递的图片id数组生成对应的ImageView数组,用来存放带有图片信息的ImageView对象。在createRefectedBitmap()方法中将原有图片处理成带有倒影效果的图片存放在ImageView对象中,然后将ImageView对象存放在ImageView数组中。

具体实现的代码如下:

<span style="font-size:14px;"> package com.lyz.gallery.activity;
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;

/**
* 自定义图片显示的适配器ImageAdapter
* @author liuyazhuang
*
*/
public class ImageAdapter extends BaseAdapter {

private Context context;
private int[] imageIds;
private ImageView[] images;

//构造方法
public ImageAdapter(Context context, int[] imageIds) {
this.context = context;
this.imageIds = imageIds;
//存放图片的数组
images = new ImageView[imageIds.length];
}

@Override
public int getCount() {
return images.length;
}

@Override
public Object getItem(int position) {
return images[position];
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
return images[position];
}

/**
* 创建带有倒影的图片
*/
public void createRefectedBitmap() {
//原图片与倒影图片之间的距离
int refectionGap = 4;
//向图片数组中加入图片
for(int i = 0; i < imageIds.length; i++){
int imageId = imageIds[i];
//原图片
Bitmap resourceBitmap = BitmapFactory.decodeResource(context.getResources(), imageId);
int width = resourceBitmap.getWidth();
int height = resourceBitmap.getHeight();
//倒影图片
//reource:原图片
//x,y:生成倒影图片的起始位置
//width,heiht:生成倒影图片宽和高
//Matrix m:用来设置图片的样式(倒影)
Matrix m = new Matrix();
//x:水平翻转;y:垂直翻转 1支持; -1翻转
m.setScale(1, -1);
Bitmap refrectionBitmap = Bitmap.createBitmap(resourceBitmap, 0, height / 2, width, height / 2,m, false);
//合成的带有倒影的图片
Bitmap bitmap = Bitmap.createBitmap(width, height + height/2, Config.ARGB_8888);
//创建画布
Canvas canvas = new Canvas(bitmap);
//绘制原图片
canvas.drawBitmap(resourceBitmap, 0, 0, null);
//绘制原图片与倒影之间的间隔
Paint defaultPaint = new Paint();
canvas.drawRect(0, height, width, height + refectionGap, defaultPaint);
//绘制倒影图片
canvas.drawBitmap(refrectionBitmap, 0, height + refectionGap, null);

//ps中的渐变和遮罩效果
Paint paint = new Paint();
//设置遮罩效果
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
//设置渐变效果
//设置着色器为遮罩着色
LinearGradient shader = new LinearGradient(0, height, 0, bitmap.getHeight(), 0x70ffffff, 0x00ffffff, TileMode.CLAMP);
paint.setShader(shader);
canvas.drawRect(0, height, width, bitmap.getHeight(), paint);

//创建BitmapDrawable图片
BitmapDrawable bd = new BitmapDrawable(bitmap);
//消除图片锯齿效果,使图片平滑
bd.setAntiAlias(true);

ImageView imageView = new ImageView(context);
imageView.setImageDrawable(bd);
//设置图片大小
imageView.setLayoutParams(new GalleryFlow.LayoutParams(160, 240));
//将图片放置在images数组中
images[i] = imageView;
}
}
} </span>

2、自定义Gallery类GalleryFlow

这个类中我们主要实现的是图片的缩放、旋转、亮度调整等操作,下面我们分解来看这个类。

(1)成员变量
这里的成员变量主要是:最大的旋转角度、最大缩放值、记录中间点的位置、相机对象

具体实现代码如下:

<span style="font-size:14px;"> //最大的旋转角度
private int maxRotateAngle = 50;
//最大缩放值
private int maxZoom = -250;
//记录中间点的位置
private int currentOfGallery;
//创建相机对象
private Camera camera = new Camera(); </span>
(2)构造方法
我在这里复写了Gallery的三个构造方法,并在每个构造方法中分别调用了setStaticTransformationsEnabled(true);方法,这个方法的作用是:指定图形是否变化 false:否  true:是。当我们调用了setStaticTransformationsEnabled方法时,Android就会回调下面的getChildStaticTransformation方法

具体实现代码如下:

<span style="font-size:14px;"> public GalleryFlow(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setStaticTransformationsEnabled(true);
}

public GalleryFlow(Context context, AttributeSet attrs) {
super(context, attrs);
//指定图形是否变化 false:否 true:是
setStaticTransformationsEnabled(true);
}

public GalleryFlow(Context context) {
super(context);
setStaticTransformationsEnabled(true);
} </span>
(3)getChildStaticTransformation方法
这个方法是调用了setStaticTransformationsEnabled时,Android会回调的一个方法,我在这个方法中完成的操作主要是:计算图像的旋转角度,设置图片的变形样式,同时调用图片变形的放方法transformationBitmap来达到图片变形的效果。

具体实现的代码如下:

<span style="font-size:14px;"> @Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
//得到图片的中心点
int currentOfChild = getCurrentOfView(child);
int width = child.getLayoutParams().width;
int height = child.getLayoutParams().height;
//旋转的角度
int rotateAngle = 0;
t.clear();
//设置图片变形样式
t.setTransformationType(Transformation.TYPE_MATRIX);
//位置中心点位置
if(currentOfChild == currentOfGallery){
transformationBitmap((ImageView)child, t, 0);
}else{ //不是中心位置
rotateAngle = (int) ((float)(currentOfGallery - currentOfChild) / width * maxRotateAngle);
if(Math.abs(rotateAngle) > maxRotateAngle){
rotateAngle = rotateAngle < 0 ? -maxRotateAngle : maxRotateAngle;
}
//图片变形
transformationBitmap((ImageView)child, t, rotateAngle);
}
return true;
} </span>
(4)图片变形方法transformationBitmap
这个方法主要完成的操作就是通过相机对象来完成对图像的变形操作。

具体实现代码如下:

<span style="font-size:14px;"> /**
* 图片变形
* @param child
* @param t
* @param i
*/
private void transformationBitmap(ImageView child, Transformation t, int rotateAngle) {
//保存图像变化的效果
camera.save();
Matrix imageMatrix = 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(imageMatrix);

imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));
imageMatrix.postTranslate(imageWidth / 2, imageHeight / 2);
//还原图像变化的效果
camera.restore();
} </span>
(5)获取Gallery展示图片的中心点方法
具体实现代码如下:

<span style="font-size:14px;"> /**
* 获取Gallery展示图片的中心点
* @return
*/
public int getCurrentOfGallery(){
return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();
} </span>
(6)获取图片中心点方法
具体实现代码如下:

<span style="font-size:14px;"> /**
* 获取图片中心点
* @param view
* @return
*/
public int getCurrentOfView(View view){
return view.getLeft() + view.getWidth() / 2;
} </span>
(7)onSizeChanged方法
这个方法是当屏幕大小变化的时候,Android自动回调的方法,我在这个方法中的操作就是将获取到的Gallery展示图片的中心点赋值给成员变量currentOfGallery。

具体代码如下:

<span style="font-size:14px;"> @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
currentOfGallery = getCurrentOfGallery();
super.onSizeChanged(w, h, oldw, oldh);
} </span>
(8)完整代码如下:
<span style="font-size:14px;"> package com.lyz.gallery.activity;

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

/**
* 自定义Gallery
* @author liuyazhuang
*
*/
public class GalleryFlow extends Gallery {
//最大的旋转角度
private int maxRotateAngle = 50;
//最大缩放值
private int maxZoom = -250;
//记录中间点的位置
private int currentOfGallery;
//创建相机对象
private Camera camera = new Camera();

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

public GalleryFlow(Context context, AttributeSet attrs) {
super(context, attrs);
//指定图形是否变化 false:否 true:是
setStaticTransformationsEnabled(true);
}

public GalleryFlow(Context context) {
super(context);
setStaticTransformationsEnabled(true);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
currentOfGallery = getCurrentOfGallery();
super.onSizeChanged(w, h, oldw, oldh);
}

@Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
//得到图片的中心点
int currentOfChild = getCurrentOfView(child);
int width = child.getLayoutParams().width;
int height = child.getLayoutParams().height;
//旋转的角度
int rotateAngle = 0;
t.clear();
//设置图片变形样式
t.setTransformationType(Transformation.TYPE_MATRIX);
//位置中心点位置
if(currentOfChild == currentOfGallery){
transformationBitmap((ImageView)child, t, 0);
}else{ //不是中心位置
rotateAngle = (int) ((float)(currentOfGallery - currentOfChild) / width * maxRotateAngle);
if(Math.abs(rotateAngle) > maxRotateAngle){
rotateAngle = rotateAngle < 0 ? -maxRotateAngle : maxRotateAngle;
}
//图片变形
transformationBitmap((ImageView)child, t, rotateAngle);
}
return true;
}

/**
* 图片变形
* @param child
* @param t
* @param i
*/
private void transformationBitmap(ImageView child, Transformation t, int rotateAngle) {
//保存图像变化的效果
camera.save();
Matrix imageMatrix = 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(imageMatrix);

imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));
imageMatrix.postTranslate(imageWidth / 2, imageHeight / 2);
//还原图像变化的效果
camera.restore();
}

/**
* 获取Gallery展示图片的中心点
* @return
*/
public int getCurrentOfGallery(){
return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();
}

/**
* 获取图片中心点
* @param view
* @return
*/
public int getCurrentOfView(View view){
return view.getLeft() + view.getWidth() / 2;
}
} </span>

3、MainActivity

这个类主要实现的功能是加载布局文件,构造要显示的图片的id数组,调用ImageAdapter方法实现图片的显示操作。

具体实现的代码如下:

<span style="font-size:14px;"> package com.lyz.gallery.activity;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

/**
* 程序主入口
* @author liuyazhuang
*
*/
public class MainActivity extends Activity {

private GalleryFlow gallery_flow;
//存放图片id的数组
private int[] imageIds;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//构造存放图片id的数组
imageIds = new int[]{
R.drawable.photo1,
R.drawable.photo2,
R.drawable.photo3,
R.drawable.photo4,
R.drawable.photo5,
R.drawable.photo6,
R.drawable.photo7,
R.drawable.photo8
};
gallery_flow = (GalleryFlow) findViewById(R.id.gallery_flow);
//实例化ImageAdapter对象
ImageAdapter adapter = new ImageAdapter(this, imageIds);
//向图片数组中加载图片
adapter.createRefectedBitmap();
gallery_flow.setAdapter(adapter);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

} </span>

4、布局文件activity_main.xml

这个布局文件很简单,就是放置了一个我们自己定义的GalleryFlow控件。

具体实现代码如下:

<span style="font-size:14px;"> <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="@android:color/black">

<com.lyz.gallery.activity.GalleryFlow
android:id="@+id/gallery_flow"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

</RelativeLayout> </span>

5、AndroidManifest.xml

这个文件中没有做任何操作,都是Android自动生成的内容。

具体实现代码如下:

<span style="font-size:14px;"> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lyz.gallery.activity"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.lyz.gallery.activity.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest> </span>

三、运行效果







四、温馨提示

大家可以到链接http://download.csdn.net/detail/l1028386804/9058447下载Android实现3D图片浏览效果示例完整源代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐