其实实现这个效果很简单,下面作一个简单的介绍

一,创建倒影效果

这个基本思路是:

1,创建一个源图一样的图,利用martrix将图片旋转180度。这个倒影图的高是源图的一半。

Matrix matrix = new Matrix();
// 1表示放大比例,不放大也不缩小。
// -1表示在y轴上相反,即旋转180度。
matrix.preScale(1, -1);
Bitmap reflectionBitmap = Bitmap.createBitmap(
srcBitmap,
0,
srcBitmap.getHeight() / 2,  // top为源图的一半
srcBitmap.getWidth(),       // 宽度与源图一样
srcBitmap.getHeight() / 2,  // 高度与源图的一半
matrix,
false);

2,创建一个最终效果的图,即源图 + 间隙 + 倒影。

final int REFLECTION_GAP = 5;
Bitmap bitmapWithReflection = Bitmap.createBitmap(
reflectionWidth,
srcHeight + reflectionHeight + REFLECTION_GAP,
Config.ARGB_8888);

3,依次将源图、倒影图绘制在最终的bitmap上面。

// Prepare the canvas to draw stuff.
Canvas canvas = new Canvas(bitmapWithReflection);
// Draw the original bitmap.
canvas.drawBitmap(srcBitmap, 0, 0, null);
// Draw the reflection bitmap.
canvas.drawBitmap(reflectionBitmap, 0, srcHeight + REFLECTION_GAP, null);

4,创建LinearGradient,从而给定一个由上到下的渐变色。

Paint paint = new Paint();
paint.setAntiAlias(true);
LinearGradient shader = new LinearGradient(
0,
srcHeight,
0,
bitmapWithReflection.getHeight() + REFLECTION_GAP,
0x70FFFFFF,
0x00FFFFFF,
TileMode.MIRROR);
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));
// Draw the linear shader.
canvas.drawRect(
0,
srcHeight,
srcWidth,
bitmapWithReflection.getHeight() + REFLECTION_GAP,
paint);

二,扩展Gallery

扩展系统的gallery,我们需要重写两个方法,getChildStaticTransformation()和getChildDrawingOrder(),同时,要使这两个方法能被调用,必须执行如下两行代码,文档上面是有说明的。

// Enable set transformation.
this.setStaticTransformationsEnabled(true);
// Enable set the children drawing order.
this.setChildrenDrawingOrderEnabled(true);

getChildDrawingOrder的实现

@Override
protected int getChildDrawingOrder(int childCount, int i)
{
// Current selected index.
int selectedIndex = getSelectedItemPosition() - getFirstVisiblePosition();
if (selectedIndex < 0)
{
return i;
}
if (i < selectedIndex)
{
return i;
}
else if (i >= selectedIndex)
{
return childCount - 1 - i + selectedIndex;
}
else
{
return i;
}
}

这里为什么要计算drawing order,因为从上图中看到,我们的效果是:中间左边的顺序是 0, 1, 2,右边的child覆盖左边的child,而在中间右边的顺序正好相反,左边的覆盖右边的,所以我们要重写这个方法,而gallery自身的实现,不是这种效果。

@Override
protected boolean getChildStaticTransformation(View child, Transformation t)
{
super.getChildStaticTransformation(child, t);
final int childCenter = getCenterOfView(child);
final int childWidth  = child.getWidth();
int rotationAngle = 0;
t.clear();
t.setTransformationType(Transformation.TYPE_MATRIX);
// If the child is in the center, we do not rotate it.
if (childCenter == mCoveflowCenter)
{
transformImageBitmap(child, t, 0);
}
else
{
// Calculate the rotation angle.
rotationAngle = (int)(((float)(mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
// Make the angle is not bigger than maximum.
if (Math.abs(rotationAngle) > mMaxRotationAngle)
{
rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;
}
transformImageBitmap(child, t, rotationAngle);
}
return true;
}

这个方法就是根据child来计算它的transformation(变换),我们需要去修改它里面的matrix,从而达到旋转的效果。根据位置和角度来计算的matrix的方法写在另外一个方法transformImageBitmap中实现。

  • transformImageBitmap()的实现
  • private void transformImageBitmap(View child, Transformation t, int rotationAngle)
    {
    mCamera.save();
    final Matrix imageMatrix = t.getMatrix();
    final int imageHeight = child.getHeight();
    final int imageWidth  = child.getWidth();
    final int rotation    = Math.abs(rotationAngle);
    // Zoom on Z axis.
    mCamera.translate(0, 0, mMaxZoom);
    if (rotation < mMaxRotationAngle)
    {
    float zoomAmount = (float)(mMaxZoom + rotation * 1.5f);
    mCamera.translate(0, 0, zoomAmount);
    }
    // Rotate the camera on Y axis.
    mCamera.rotateY(rotationAngle);
    // Get the matrix from the camera, in fact, the matrix is S (scale) transformation.
    mCamera.getMatrix(imageMatrix);
    // The matrix final is T2 * S * T1, first translate the center point to (0, 0),
    // then scale, and then translate the center point to its original point.
    // T * S * T
    // S * T1
    imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));
    // (T2 * S) * T1
    imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));
    mCamera.restore();
    }

    这里,简单说明一个,

    第一,先在Z轴上平称,其实就是得到一个缩放矩阵变换,我这里简写为 S。

    第二,是利用camera这个类来生成matrix,其实mCamera.rotateY就是围绕Y轴旋转。这里生成了一个旋转矩阵,记为 R 。经过这两步,此时调用mCamera.getMatrix(imageMatrix); 从Camera中得到matrix,此时这个矩阵中包含了S * R。

    第三,最关键是下面两句

// S * T1
imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));
// (T2 * S) * T1
imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));

由于这里涉及到旋转与缩放,缩放操作其实应该是针对Child中点进行了,这里就是作一个平衡操作,我们必须是先平移,再缩放,再平移回原来位置,所以,我们最终的矩阵变换应该是这样的:

M = T * (S * R) * T1   (这里在T1表示与T相反)。

三,完整代码

GalleryFlow.java

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;
public class GalleryFlow extends Gallery
{
/**
* The camera class is used to 3D transformation matrix.
*/
private Camera mCamera = new Camera();
/**
* The max rotation angle.
*/
private int mMaxRotationAngle = 60;
/**
* The max zoom value (Z axis).
*/
private int mMaxZoom = -120;
/**
* The center of the gallery.
*/
private int mCoveflowCenter = 0;
public GalleryFlow(Context context)
{
this(context, null);
}
public GalleryFlow(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public GalleryFlow(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
// Enable set transformation.
this.setStaticTransformationsEnabled(true);
// Enable set the children drawing order.
this.setChildrenDrawingOrderEnabled(true);
}
public int getMaxRotationAngle()
{
return mMaxRotationAngle;
}
public void setMaxRotationAngle(int maxRotationAngle)
{
mMaxRotationAngle = maxRotationAngle;
}
public int getMaxZoom()
{
return mMaxZoom;
}
public void setMaxZoom(int maxZoom)
{
mMaxZoom = maxZoom;
}
@Override
protected int getChildDrawingOrder(int childCount, int i)
{
// Current selected index.
int selectedIndex = getSelectedItemPosition() - getFirstVisiblePosition();
if (selectedIndex < 0)
{
return i;
}
if (i < selectedIndex)
{
return i;
}
else if (i >= selectedIndex)
{
return childCount - 1 - i + selectedIndex;
}
else
{
return i;
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
mCoveflowCenter = getCenterOfCoverflow();
super.onSizeChanged(w, h, oldw, oldh);
}
private int getCenterOfView(View view)
{
return view.getLeft() + view.getWidth() / 2;
}
@Override
protected boolean getChildStaticTransformation(View child, Transformation t)
{
super.getChildStaticTransformation(child, t);
final int childCenter = getCenterOfView(child);
final int childWidth  = child.getWidth();
int rotationAngle = 0;
t.clear();
t.setTransformationType(Transformation.TYPE_MATRIX);
// If the child is in the center, we do not rotate it.
if (childCenter == mCoveflowCenter)
{
transformImageBitmap(child, t, 0);
}
else
{
// Calculate the rotation angle.
rotationAngle = (int)(((float)(mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
// Make the angle is not bigger than maximum.
if (Math.abs(rotationAngle) > mMaxRotationAngle)
{
rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;
}
transformImageBitmap(child, t, rotationAngle);
}
return true;
}
private int getCenterOfCoverflow()
{
return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();
}
private void transformImageBitmap(View child, Transformation t, int rotationAngle)
{
mCamera.save();
final Matrix imageMatrix = t.getMatrix();
final int imageHeight = child.getHeight();
final int imageWidth  = child.getWidth();
final int rotation    = Math.abs(rotationAngle);
// Zoom on Z axis.
mCamera.translate(0, 0, mMaxZoom);
if (rotation < mMaxRotationAngle)
{
float zoomAmount = (float)(mMaxZoom + rotation * 1.5f);
mCamera.translate(0, 0, zoomAmount);
}
// Rotate the camera on Y axis.
mCamera.rotateY(rotationAngle);
// Get the matrix from the camera, in fact, the matrix is S (scale) transformation.
mCamera.getMatrix(imageMatrix);
// The matrix final is T2 * S * T1, first translate the center point to (0, 0),
// then scale, and then translate the center point to its original point.
// T * S * T
// S * T1
imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));
// (T2 * S) * T1
imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));
mCamera.restore();
}
}

BitmapUtil.java

package com.lee.gallery3d.utils;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.Drawable;
public class BitmapUtil
{
public static Bitmap createReflectedBitmap(Bitmap srcBitmap)
{
if (null == srcBitmap)
{
return null;
}
// The gap between the reflection bitmap and original bitmap.
final int REFLECTION_GAP = 4;
int srcWidth  = srcBitmap.getWidth();
int srcHeight = srcBitmap.getHeight();
int reflectionWidth  = srcBitmap.getWidth();
int reflectionHeight = srcBitmap.getHeight() / 2;
if (0 == srcWidth || srcHeight == 0)
{
return null;
}
// The matrix
Matrix matrix = new Matrix();
matrix.preScale(1, -1);
try
{
// The reflection bitmap, width is same with original's, height is half of original's.
Bitmap reflectionBitmap = Bitmap.createBitmap(
srcBitmap,
0,
srcHeight / 2,
srcWidth,
srcHeight / 2,
matrix,
false);
if (null == reflectionBitmap)
{
return null;
}
// Create the bitmap which contains original and reflection bitmap.
Bitmap bitmapWithReflection = Bitmap.createBitmap(
reflectionWidth,
srcHeight + reflectionHeight + REFLECTION_GAP,
Config.ARGB_8888);
if (null == bitmapWithReflection)
{
return null;
}
// Prepare the canvas to draw stuff.
Canvas canvas = new Canvas(bitmapWithReflection);
// Draw the original bitmap.
canvas.drawBitmap(srcBitmap, 0, 0, null);
// Draw the reflection bitmap.
canvas.drawBitmap(reflectionBitmap, 0, srcHeight + REFLECTION_GAP, null);
Paint paint = new Paint();
paint.setAntiAlias(true);
LinearGradient shader = new LinearGradient(
0,
srcHeight,
0,
bitmapWithReflection.getHeight() + REFLECTION_GAP,
0x70FFFFFF,
0x00FFFFFF,
TileMode.MIRROR);
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));
// Draw the linear shader.
canvas.drawRect(
0,
srcHeight,
srcWidth,
bitmapWithReflection.getHeight() + REFLECTION_GAP,
paint);
return bitmapWithReflection;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
}

Demo下载

原创来自:http://blog.csdn.net/leehong2005/article/details/8070538

Android gallery 3D效果相关推荐

  1. Android Camera 3D效果

    版本:1.0 日期:2014.4.14 版权:© 2014 kince 转载注明出处 一.概念 在Android中要想实现3D效果,第一个想到的应该就是OpenGL ES,因为在很多基础教材中几乎都提 ...

  2. android立体3D效果_Android实现八大行星绕太阳3D旋转效果

    code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群 作者:史蒂芬诺夫斯基链接:https://www.jianshu.com/p/2954f2ef8ea5声明:本文已获史 ...

  3. android立体3D效果_怀化400T吨龙门剪图纸3d模型_临沂1500T吨剪图纸原理图-皇宏液压...

    皇宏液压为您详细解读yddYIm怀化400T龙门剪图纸3d模型的相关知识与详情,   接触过超影3D印刷的伴侣们,想必必然对陈某们有所理解,超影3D印刷服务商拥有强大的3D印刷经历的团队,不单正在3D ...

  4. android立体3D效果_谷歌裸眼3D动物意外蹿红,掀起一股AR体验小高潮

    疫情在国外来势汹汹,越来越多人不得不长期待在家中.这个时候如果手指闲不住,不如试试在谷歌搜索中检索动物,就会有栩栩如生的 3D"动物"空降你家,而且其违和感已相较之前大大降低. 在 ...

  5. android 卡片3d效果_小米发布伸缩镜头技术:卡片机失业,多摄下岗?

    11月5日消息,小米在今天的MIDC 2020小米开发者大会上,发布了自研的"伸缩式大光圈镜头技术".顾名思义,就是在手机上加入类似卡片相机的可伸缩镜头,从而达到多焦段的拍照效果, ...

  6. android立体3D效果_3D立体画手绘墙体彩绘

    由于绘画表现形式的丰富多样,因此,墙体彩绘也不再仅仅局限于单调的平面图案效果,逼真的3D立体画作为墙体彩绘的一种表现形式,它呈现出来的逼真立体效果被广大时尚有个性的客户所追捧.它能给予人们强大的视觉冲 ...

  7. android立体3D效果_3D立体画,让你身临其境

    墙绘的出现,让墙面看起来更加美观,也提升了整面墙的美感度.从最开始的宗教墙绘,到现在的社区文化墙,家装彩绘,工装墙绘等等,其中有个具有独立风格的墙绘,以其逼真的效果被大众所熟知,那就是3D立体画. ​ ...

  8. android立体3D效果_PS教程:铝膜气球字制作的完整教程,3D立体效果字体的制作...

    这一篇主要是用PS做一种3D立体字体效果,铝膜气球字体,当然学会之后,举一反三,可以做成其他图案的铝膜气球效果. 铝膜气球在目前的各种庆典,婚庆,庆贺宴席上,用的比较普遍:这个字体效果,后期可以用于室 ...

  9. android立体3D效果_3D全息投影和平面投影有什么区别_广州全息投影

    随着时代的发展.科技的进步,3D全息投影已经融入到人们的日常生活当中,给人们带来全新的视觉体验,呈现亦真亦幻的虚拟影像世界,越来越多的行业肯定及选择全息投影技术.那么与传统的平面投影相比,3D全息投影 ...

  10. android shape 3d效果,如何绘制SuperShape3D作为网格?

    我想画一个3D Superformula网格,但不知道我应该如何组织这些面(它们是三角形或四边形).如何绘制SuperShape3D作为网格? 我已经安装了八度并尝试了示例代码.我不知道Gnuplot ...

最新文章

  1. linux命令--提升
  2. 陈顺志 php,芦芽山之情
  3. 手机扫描到WiFi时,WiFi站点知道吗?
  4. 前台传参到后台出现中文乱码问题
  5. Hibernate二级缓存——SessionFactory
  6. 你要的Chrome插件都在这里了
  7. 联想服务器告警信息分析,联想服务器mib分析
  8. 计算机关闭后桌面文件丢失,win7系统电脑关机重启后桌面文件全部不见了的解决方法...
  9. IOS开发之相机、相册页面英文问题
  10. 在ubuntu下安装韦诺之战(一款好玩策略游戏)
  11. Android studio最新版2021安装教程超详细。
  12. 筋斗云接口编程 / 常用操作(二)
  13. web前端零基础html5
  14. 短距离无线通讯-NFC
  15. 7. 常见网络攻击欺骗手段与防护
  16. 两种方法 Find inorder succ of BST
  17. 你不知道Python多能干,小伙子骨骼惊奇不来学习吗?
  18. Python3网络爬虫--爬取有声小说(附源码)
  19. 《痞子衡嵌入式半月刊》 第 34 期
  20. NetBox的简单使用

热门文章

  1. MATLAB数学建模方法与实践(第3版)——读书笔记
  2. 分布式微服框架Dubbo视频教程分享,已更新。
  3. 文章学习_基于HowNet 的词汇语义倾向计算
  4. 图片着色后存储为“JPEG”格式存在明显色差问题解决
  5. PDMS Pipeline Tool 教程(三):材料表
  6. 2022华为软件精英挑战赛复盘
  7. 重磅开源!一款引入实时语音与声纹识别的网络辩论系统!
  8. C语言再学习-- 大端小端详解(转)
  9. 记录php项目遇到502和504 Bad Gateway问题
  10. 超酷的屏幕抠图转场技巧