一、效果图:
二、首先实现基本的框架
1、创建一个类继承Gallery
public class GalleryView extends Gallery {
public GalleryView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public GalleryView(Context context) {
this(context, null);
}
public GalleryView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
}
2、创建布局,在布局里引用这个类
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.android.imooc.gallery.GalleryView
android:id="@+id/galleryView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</com.android.imooc.gallery.GalleryView>
</LinearLayout>
3、在主页里添加
public class GalleryActivity extends Activity {
private GalleryView mGallery;
private int mResIds[] = {
R.drawable.pic_1,
R.drawable.pic_2,
R.drawable.pic_3,
R.drawable.pic_4,
R.drawable.pic_5,
R.drawable.pic_6,
R.drawable.pic_7,
R.drawable.pic_8
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
mGallery = (GalleryView) findViewById(R.id.galleryView);
mGallery.setAdapter(new GalleryAdapter());
}
private class GalleryAdapter extends BaseAdapter {
@Override
public int getCount() {
return mResIds.length;
}
@Override
public Object getItem(int position) {
return mResIds[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView iv = null;
if (convertView == null) {
iv = new ImageView(GalleryActivity.this);
}else {
iv = (ImageView) convertView;
}
iv.setImageResource(mResIds[position]);
LayoutParams params = new LayoutParams(160, 260);
iv.setLayoutParams(params);
iv.setScaleType(ScaleType.CENTER_CROP);
return iv;
}
}
}
三、图片处理;
1、如果是有倒影的图片,就不能直接iv.setImageResource(mResIds[position]);
而是通过工具类实现了倒影后把图片设置到imageview里
Bitmap reverseBitmap = ImageUtil.getReverseBitmapById(mResIds[position]);
iv.setImageBitmap(reverseBitmap);
2、开始写方法getReverseBitmapById(mResIds[position])
分析:
首先获取原图
然后根据原图创建一张根据y坐标对称的倒立图
把两张图片合成一张图片
把下面的图片加上遮罩
1)创建原图
Bitmap sourceBitmap = BitmapFactory.decodeResource(context.getResources(), resId);
2)绘制原图一半的图片
以下面图片分析,这张图片的x轴是0,y轴是getHeight,
中间点的坐标是(1,getHeight()/2);
//绘制原图的下一半图片
Matrix matrix = new Matrix();
//倒影
matrix.setScale(1, -1);
Bitmap inverseBitmap = Bitmap.createBitmap(sourceBitmap, 0, sourceBitmap.getHeight() / 2, sourceBitmap.getWidth(), sourceBitmap.getHeight()/2, matrix, false);
3)创建合成图片
//合成图片
Bitmap groupbBitmap = Bitmap.createBitmap(sourceBitmap.getWidth(), sourceBitmap.getHeight() + sourceBitmap.getHeight() / 2 + padding,
sourceBitmap.getConfig());
4)根据合成图片创建画板
Canvas canvas = new Canvas(groupbBitmap);
//把原图画在合成图片的上面
canvas.drawBitmap(sourceBitmap, 0, 0, null);
//以图片的左上角与坐标
canvas.drawBitmap(inverseBitmap, 0, sourceBitmap.getHeight() + padding, null);
5)添加遮罩,主要使用了线性渲染器
//添加遮罩
Paint paint = new Paint();
//TileMode.CLAMP表示渲染时一直往下延伸
TileMode tile = TileMode.CLAMP;
LinearGradient shader = new LinearGradient(0, sourceBitmap.getHeight() + padding, 0, groupbBitmap.getHeight(), Color.TRANSPARENT, Color.BLACK, tile);
paint.setShader(shader);
//这里取的是矩形与图片的交集,所以用的是DST_IN
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
gCanvas.drawRect(0, sourceBitmap.getHeight() + padding, sourceBitmap.getWidth(), groupbBitmap.getHeight(), paint);
遮罩模式图
6)全部代码
/**
* 根据图片id获得有倒影的图片
* @param resId
* @return
*/
public static Bitmap getReverseBitmapById(Context context, int resId) {
int padding = context.getResources().getDimensionPixelOffset(R.dimen.image_paddding);//图片的间距
//绘制原图
Bitmap sourceBitmap = BitmapFactory.decodeResource(context.getResources(), resId);
//图片的默认矩阵
// float[] values = {
// 1.0f, 0f, 0f,
// 0f, 1.0f, 0f,
// 0f, 0f, 1.0f
// };
//绘制原图的下一半图片
Matrix matrix = new Matrix();
matrix.setScale(1, -1);
//matrix.setValues(values);
Bitmap inverseBitmap = Bitmap.createBitmap(sourceBitmap, 0, sourceBitmap.getHeight() / 2, sourceBitmap.getWidth(), sourceBitmap.getHeight()/2, matrix, false);
//合成图片
Bitmap groupbBitmap = Bitmap.createBitmap(sourceBitmap.getWidth(), sourceBitmap.getHeight() + sourceBitmap.getHeight() / 2 + padding,
sourceBitmap.getConfig());
Canvas gCanvas = new Canvas(groupbBitmap);
//把原图画在合成图片的上面
gCanvas.drawBitmap(sourceBitmap, 0, 0, null);
//以图片的左上角与坐标
gCanvas.drawBitmap(inverseBitmap, 0, sourceBitmap.getHeight() + padding, null);
//添加遮罩
Paint paint = new Paint();
TileMode tile = TileMode.CLAMP;
LinearGradient shader = new LinearGradient(0, sourceBitmap.getHeight() + padding, 0, groupbBitmap.getHeight(), Color.TRANSPARENT, Color.BLACK, tile);
paint.setShader(shader);
//这里取的是矩形与图片的交集,所以用的是DST_IN
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
gCanvas.drawRect(0, sourceBitmap.getHeight() + padding, sourceBitmap.getWidth(), groupbBitmap.getHeight(), paint);
return groupbBitmap;
}
四、旋转处理
从上面的图片分析:
必须实现三种效果
1)旋转: 中间的图片完全在中间时没有旋转角度,只要移动就有
2)透明度:中间的图片完全显示,旁边的图片有些透明
3)放大效果:中间的图片大,旁边的图片越来越小
那如何实现呢?记得在gallery里有个方法getChildStaticTransformation,就是用来实现子view的变化效果的
好了,开始
1、判断图片是否在中间,只要判断child与gallery的中心点是否一致即可
child.getLeft() + child.width/2 = gallery.widht/2;
2、如果图片不在中间,设
两个中心的距离为dis = 20dp
图片的最大旋转角度 maxDegree = 50°
那图片的旋转角度 = dis / child.width * maxDegree
3、分别获得gallery的中心点与图片的中心点
/**
* gallery中心点
* @return
*/
public int getGalleryCenterX(){
return this.getWidth() / 2;
}
/**
* child中心点
* @return
*/
public int getChildCenterX(View child){
return child.getLeft() + child.getWidth() / 2;
}
4、 得到旋转的角度,设置参数
/**
* 实现子view的变化效果 Transformation指定当前item的效果
*/
@Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
int rotateAngle = 0;
// 如果child的中心点与gallery的中心点不一致,需要计算旋转角度
int childCenterX = getChildCenterX(child);
if (childCenterX != mGalleryCenterX) {
// 两个中心点距离
int distance = mGalleryCenterX - childCenterX;
float percent = distance * 1.0f / child.getWidth();
rotateAngle = (int) (percent * mMaxAngle);// 得到旋转的角度
// 因为distance有可能大于图片的宽度,所以得到角度有可能大于最大的角度
if (Math.abs(rotateAngle) > mMaxAngle) {
rotateAngle = rotateAngle > 0 ? mMaxAngle : -mMaxAngle;
}
}
//设置变化之前,要把上面的一个动画清除
t.clear();
//设置变化的效果为矩阵类型
t.setTransformationType(Transformation.TYPE_MATRIX);
//开始旋转
startAnimate(child, rotateAngle, t);
return true;
}
5、处理动画效果
gallery实现的动画效果必须使用android.graphics.Camera类,
在构造方法里直接
mCamera = new Camera();
mCamera使用时必须先mCamera.save(),结束后mCamera.restore();
/**
* 开始动画效果
* @param child
* @param rotateAngle
* @param t
*/
private void startAnimate(View child, int rotateAngle, Transformation t) {
ImageView iv = (ImageView) child;
int absAngle = Math.abs(rotateAngle);
mCamera.save();
//3.实现放大效果
//仔细看图片,发现图片在x,y轴上都没有变化,但有一边缩小,另一边放大,是如何实现的?
//这里就要用到了z轴了,只要改变轴的数值就能实现了
mCamera.translate(0, 0, 100);
int zoom = -250 + (absAngle * 2);
mCamera.translate(0, 0, zoom);
//2.设置透明度 (0到255) 255完全显示,中间的absAngle=0,所以没有透明度
iv.setAlpha(255- absAngle * 2.5f);
//3.旋转
mCamera.rotateY(rotateAngle);
//4.转换成矩阵
Matrix matrix = t.getMatrix();
//给matrix赋值
mCamera.getMatrix(matrix);
//矩阵前乘
matrix.preTranslate(-iv.getWidth()/2, -iv.getHeight()/2);
//矩阵后乘
matrix.postTranslate(iv.getWidth()/2, iv.getHeight()/2);
}
矩阵后前示意图 (矩阵后乘与其相反移动)
6、现在基本功能都实现了,是不是发现有锯齿不好看,如何去除锯齿呢?
有一个包装类可以实现BitmapDrawable
所以在GalleryAdapter里的适配器的getView方法里就必须改代码
原来是
Bitmap bm = ImageUtil.getReverseBitmapById(GalleryActivity.this, mResIds[position]);
iv.setImageBitmap(bm);
现在加包装
Bitmap bm = ImageUtil.getReverseBitmapById(GalleryActivity.this, mResIds[position]);
//去除锯齿
BitmapDrawable bd = new BitmapDrawable(bm);
bd.setAntiAlias(true);
iv.setImageDrawable(bd);
7、为了提高图片的速度,我使用了lruCache来存取图片,如何实现?
首先在适配器定义
LruCache<String, Bitmap> mCache ;
String key = "key";
在构造方法里初始化mCache
public GalleryAdapter(){
if (mCache == null) {
// 最大使用的内存空间
int maxSize = (int) (Runtime.getRuntime().freeMemory() / 4);
mCache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
}
}
最后在getview方法里
Bitmap bm = mCache.get(key);
if (bm == null) {
bm = ImageUtil.getReverseBitmapById(GalleryActivity.this, mResIds[position]);
}else {
mCache.put(key, bm);
}
五、贴上全部代码
1、主页
/**
* @描述 TODO
* @项目名称 App_imooc
* @包名 com.android.imooc.gallery
* @类名 GalleryActivity
* @author chenlin
* @date 2012年6月5日 下午9:16:33
* @version 1.0
*/
@SuppressWarnings("all")
public class GalleryActivity extends Activity {
private GalleryView mGallery;
private int mResIds[] = {
R.drawable.pic_1,
R.drawable.pic_2,
R.drawable.pic_3,
R.drawable.pic_4,
R.drawable.pic_5,
R.drawable.pic_6,
R.drawable.pic_7,
R.drawable.pic_8
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
mGallery = (GalleryView) findViewById(R.id.galleryView);
mGallery.setAdapter(new GalleryAdapter());
}
private class GalleryAdapter extends BaseAdapter {
LruCache<String, Bitmap> mCache ;
String key = "key";
public GalleryAdapter(){
if (mCache == null) {
// 最大使用的内存空间
int maxSize = (int) (Runtime.getRuntime().freeMemory() / 4);
mCache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
}
}
@Override
public int getCount() {
return mResIds.length;
}
@Override
public Object getItem(int position) {
return mResIds[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView iv = null;
if (convertView == null) {
iv = new ImageView(GalleryActivity.this);
}else {
iv = (ImageView) convertView;
}
Bitmap bm = mCache.get(key);
if (bm == null) {
bm = ImageUtil.getReverseBitmapById(GalleryActivity.this, mResIds[position]);
}else {
mCache.put(key, bm);
}
//去除锯齿
BitmapDrawable bd = new BitmapDrawable(bm);
bd.setAntiAlias(true);
iv.setImageDrawable(bd);
LayoutParams params = new LayoutParams(160, 260);
iv.setLayoutParams(params);
iv.setPadding(0, 0, 10, 0);
iv.setScaleType(ScaleType.FIT_XY);
return iv;
}
}
}
2、自定义gallery视图
/**
* @描述 TODO
* @项目名称 App_imooc
* @包名 com.android.imooc.async
* @类名 GalleryView
* @author chenlin
* @date 2012年6月5日 下午9:14:48
* @version 1.0
*/
@SuppressWarnings("all")
public class GalleryView extends Gallery {
private static final String TAG = "gallery";
private int mGalleryCenterX = 0;
private int mMaxAngle = 50;// 最大旋转角度
private Camera mCamera;
public GalleryView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public GalleryView(Context context) {
this(context, null);
}
public GalleryView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setStaticTransformationsEnabled(true);
mCamera = new Camera();
}
/**
* 实现子view的变化效果 Transformation指定当前item的效果
*/
@Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
int rotateAngle = 0;
// 如果child的中心点与gallery的中心点不一致,需要计算旋转角度
int childCenterX = getChildCenterX(child);
if (childCenterX != mGalleryCenterX) {
// 两个中心点距离
int distance = mGalleryCenterX - childCenterX;
float percent = distance * 1.0f / child.getWidth();
rotateAngle = (int) (percent * mMaxAngle);// 得到旋转的角度
// 因为distance有可能大于图片的宽度,所以得到角度有可能大于最大的角度
if (Math.abs(rotateAngle) > mMaxAngle) {
rotateAngle = rotateAngle > 0 ? mMaxAngle : -mMaxAngle;
}
}
//设置变化之前,要把上面的一个动画清除
t.clear();
//设置变化的效果为矩阵类型
t.setTransformationType(Transformation.TYPE_MATRIX);
//开始旋转
startAnimate(child, rotateAngle, t);
return true;
}
/**
* 开始动画效果
* @param child
* @param rotateAngle
* @param t
*/
private void startAnimate(View child, int rotateAngle, Transformation t) {
//if (child instanceof ImageView) {
ImageView iv = (ImageView) child;
int absAngle = Math.abs(rotateAngle);
mCamera.save();
//3.实现放大效果
//仔细看图片,发现图片在x,y轴上都没有变化,但有一边缩小,另一边放大,是如何实现的?
//这里就要用到了z轴了,只要改变轴的数值就能实现了
mCamera.translate(0, 0, 100);
int zoom = -250 + (absAngle * 2);
mCamera.translate(0, 0, zoom);
//2.设置透明度 (0到255) 255完全显示,中间的absAngle=0,所以没有透明度
iv.setAlpha((int) (255 - absAngle * 2.5));
//3.旋转
mCamera.rotateY(rotateAngle);
//4.转换成矩阵
Matrix matrix = t.getMatrix();
//给matrix赋值
mCamera.getMatrix(matrix);
//矩阵前乘
matrix.preTranslate(-iv.getWidth()/2, -iv.getHeight()/2);
//矩阵后乘
matrix.postTranslate(iv.getWidth()/2, iv.getHeight()/2);
mCamera.restore();
//}
}
/**
* gallery中心点
*
* @return
*/
public int getGalleryCenterX() {
return this.getWidth() / 2;
}
/**
* child中心点
*
* @return
*/
public int getChildCenterX(View child) {
return child.getLeft() + child.getWidth() / 2;
}
/**
* 设置最大旋转角度
*
* @param maxAngel
*/
public void setAngle(int maxAngel) {
this.mMaxAngle = maxAngel;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mGalleryCenterX = getGalleryCenterX();
Logger.i(TAG, "mGalleryCenterX = " + mGalleryCenterX);
Logger.i(TAG, "w/2 = " + w / 2);
super.onSizeChanged(w, h, oldw, oldh);
}
}
3、工具类
/**
* @描述 图片处理工具
* @项目名称 App_imooc
* @包名 com.android.imooc.gallery
* @类名 ImageUtil
* @author chenlin
* @date 2012年9月5日 下午10:05:38
* @version 1.0
*/
public class ImageUtil {
/**
* 根据图片id获得有倒影的图片
* @param resId
* @return
*/
public static Bitmap getReverseBitmapById(Context context, int resId) {
int padding = context.getResources().getDimensionPixelOffset(R.dimen.image_paddding);//图片的间距
//绘制原图
Bitmap sourceBitmap = BitmapFactory.decodeResource(context.getResources(), resId);
//图片的默认矩阵
// float[] values = {
// 1.0f, 0f, 0f,
// 0f, 1.0f, 0f,
// 0f, 0f, 1.0f
// };
//绘制原图的下一半图片
Matrix matrix = new Matrix();
matrix.setScale(1, -1);
//matrix.setValues(values);
Bitmap inverseBitmap = Bitmap.createBitmap(sourceBitmap, 0, sourceBitmap.getHeight() / 2, sourceBitmap.getWidth(), sourceBitmap.getHeight()/2, matrix, false);
//合成图片
Bitmap groupbBitmap = Bitmap.createBitmap(sourceBitmap.getWidth(), sourceBitmap.getHeight() + sourceBitmap.getHeight() / 2 + padding,
sourceBitmap.getConfig());
Canvas gCanvas = new Canvas(groupbBitmap);
//把原图画在合成图片的上面
gCanvas.drawBitmap(sourceBitmap, 0, 0, null);
//以图片的左上角与坐标
gCanvas.drawBitmap(inverseBitmap, 0, sourceBitmap.getHeight() + padding, null);
//添加遮罩
Paint paint = new Paint();
TileMode tile = TileMode.CLAMP;
LinearGradient shader = new LinearGradient(0, sourceBitmap.getHeight() + padding, 0, groupbBitmap.getHeight(), 0x70ffffff, Color.TRANSPARENT, tile);
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
gCanvas.drawRect(0, sourceBitmap.getHeight() + padding, sourceBitmap.getWidth(), groupbBitmap.getHeight(), paint);
return groupbBitmap;
}
}
六、源码下载
链接:http://pan.baidu.com/s/1boAkuy7 密码:kdx8
———————————————————————
(java 架构师全套教程,共760G, 让你从零到架构师,每月轻松拿3万)
有需求者请进站查看,非诚勿扰
https://item.taobao.com/item.htm?spm=686.1000925.0.0.4a155084hc8wek&id=555888526201
01.高级架构师四十二个阶段高
02.Java高级系统培训架构课程148课时
03.Java高级互联网架构师课程
04.Java互联网架构Netty、Nio、Mina等-视频教程
05.Java高级架构设计2016整理-视频教程
06.架构师基础、高级片
07.Java架构师必修linux运维系列课程
08.Java高级系统培训架构课程116课时
(送:hadoop系列教程,java设计模式与数据结构, Spring Cloud微服务, SpringBoot入门)
——————————————————————–