Android-相册效果(图片缩放 自由滑动)
先上图:

很多时候 我们会有这么一个需求:
展示一组图片 每个Item的图片 可以自由拉伸 滑动 焦点不冲突
网上有很多实现方法 通过自定义Gallery和ImageView来实现
个人不是很推荐 在这里推荐有ViewPager加ZoomImageView
ViewPager就不过多解释 主要是ZoomImageView
上代码:
public class ZoomImageView extends ImageView implements OnTouchListener, OnGestureListener{
private int WIDTH;
private int HEIGHT;
private int mStatusHeight;
private static final String TAG = ZoomImageView.class.getSimpleName();
// This is the base transformation which is used to show the image
// initially. The current computation for this shows the image in
// it's entirety, letterboxing as needed. One could choose to
// show the image as cropped instead.
//
// This matrix is recomputed when we go from the thumbnail image to
// the full size image.
protected Matrix mBaseMatrix = new Matrix();
// This is the supplementary transformation which reflects what
// the user has done in terms of zooming and panning.
//
// This matrix reHonagAnGalleryActivitys the same when we go from the
// thumbnail image
// to the full size image.
protected Matrix mSuppMatrix = new Matrix();
// This is the final matrix which is computed as the concatentation
// of the base matrix and the supplementary matrix.
private final Matrix mDisplayMatrix = new Matrix();
// Temporary buffer used for getting the values out of a matrix.
private final float[] mMatrixValues = new float[];
// The current bitmap being displayed.
// protected final RotateBitmap mBitmapDisplayed = new RotateBitmap(null);
protected Bitmap image = null;
int mThisWidth = -, mThisHeight = -;
float mMaxZoom = 4.0f;
float mMinZoom = 0.1f;
private int imageWidth;
private int imageHeight;
private float scaleRate;
public ZoomImageView(Context context) {
super(context);
init();
}
public ZoomImageView(Context context, int imageWidth, int imageHeight) {
super(context);
this.imageHeight = imageHeight;
this.imageWidth = imageWidth;
init();
}
public ZoomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void arithScaleRate() {
float scaleWidth = WIDTH / (float) imageWidth;
float scaleHeight = HEIGHT / (float) imageHeight;
scaleRate = Math.min(scaleWidth, scaleHeight);
if (scaleRate > ) {
scaleRate = 1f;
}
}
public float getScaleRate() {
return scaleRate;
}
public int getImageWidth() {
return imageWidth;
}
public void setImageWidth(int imageWidth) {
this.imageWidth = imageWidth;
}
public int getImageHeight() {
return imageHeight;
}
public void setImageHeight(int imageHeight) {
this.imageHeight = imageHeight;
}
protected Handler mHandler = new Handler();
@Override
public void setImageResource(int resId) {
Bitmap bit = BitmapFactory.decodeResource(getResources(), resId);
setImageBitmap(bit);
}
@Override
public void setImageBitmap(Bitmap bitmap) {
super.setImageBitmap(bitmap);
this.imageHeight = bitmap.getHeight();
this.imageWidth = bitmap.getWidth();
image = bitmap;
requestImage();
}
public void requestImage() {
arithScaleRate();
zoomTo(scaleRate, WIDTH / 2f, WIDTH / 2f);
layoutToCenter();
}
// Center as much as possible in one or both axis. Centering is
// defined as follows: if the image is scaled down below the
// view's dimensions then center it (literally). If the image
// is scaled larger than the view and is translated out of view
// then translate it back into view (i.e. eliminate black bars).
protected void center(boolean horizontal, boolean vertical) {
// if (mBitmapDisplayed.getBitmap() == null) {
// return;
// }
if (image == null) {
return;
}
Matrix m = getImageViewMatrix();
RectF rect = new RectF(, , image.getWidth(), image.getHeight());
// RectF rect = new RectF(0, 0, imageWidth*getScale(),
// imageHeight*getScale());
m.mapRect(rect);
float height = rect.height();
float width = rect.width();
float deltaX = , deltaY = ;
if (vertical) {
int viewHeight = getHeight();
if (height < viewHeight) {
deltaY = (viewHeight - height) / - rect.top;
} else if (rect.top > ) {
deltaY = -rect.top;
} else if (rect.bottom < viewHeight) {
deltaY = getHeight() - rect.bottom;
}
}
if (horizontal) {
int viewWidth = getWidth();
if (width < viewWidth) {
deltaX = (viewWidth - width) / - rect.left;
} else if (rect.left > ) {
deltaX = -rect.left;
} else if (rect.right < viewWidth) {
deltaX = viewWidth - rect.right;
}
}
postTranslate(deltaX, deltaY);
setImageMatrix(getImageViewMatrix());
}
public void setStatusHeight(int height) {
HEIGHT -= height;
}
private void init() {
// except the height of the top bar
DisplayMetrics dm = getResources().getDisplayMetrics();
WIDTH = dm.widthPixels;
HEIGHT = dm.heightPixels;
// HEIGHT -= getResources().getDimension(R.dimen.top_bar_height);
setScaleType(ImageView.ScaleType.MATRIX);
setOnTouchListener(this);
mDetector = new GestureDetector(getContext(), this);
}
public void layoutToCenter() {
float width = imageWidth * getScale();
float height = imageHeight * getScale();
float fill_width = WIDTH - width;
float fill_height = HEIGHT - height;
float tran_width = 0f;
float tran_height = 0f;
if (fill_width > )
tran_width = fill_width / ;
if (fill_height > )
tran_height = fill_height / ;
float v[] = new float[];
Matrix m = getImageMatrix();
m.getValues(v);
float left = v[Matrix.MTRANS_X];
float top = v[Matrix.MTRANS_Y];
tran_width -= left;
tran_height -= top;
postTranslate(tran_width, tran_height);
// setImageMatrix(getImageViewMatrix());
}
protected float getValue(Matrix matrix, int whichValue) {
matrix.getValues(mMatrixValues);
// mMinZoom = (BrowsePictureActivity.screenWidth / 2f) / imageWidth;
mMinZoom = ;
return mMatrixValues[whichValue];
}
// Get the scale factor out of the matrix.
protected float getScale(Matrix matrix) {
return getValue(matrix, Matrix.MSCALE_X);
}
protected float getScale() {
return getScale(mSuppMatrix);
}
// Combine the base matrix and the supp matrix to make the final matrix.
protected Matrix getImageViewMatrix() {
// The final matrix is computed as the concatentation of the base matrix
// and the supplementary matrix.
mDisplayMatrix.set(mBaseMatrix);
mDisplayMatrix.postConcat(mSuppMatrix);
return mDisplayMatrix;
}
static final float SCALE_RATE = 1.25F;
// Sets the maximum zoom, which is a scale relative to the base matrix. It
// is calculated to show the image at 400% zoom regardless of screen or
// image orientation. If in the future we decode the full 3 megapixel image,
// rather than the current 1024x768, this should be changed down to 200%.
protected float maxZoom() {
if (image == null) {
return 1F;
}
float fw = (float) image.getWidth() / (float) mThisWidth;
float fh = (float) image.getHeight() / (float) mThisHeight;
float max = Math.max(fw, fh) * ;
return max;
}
protected void zoomTo(float scale, float centerX, float centerY) {
zoomTo(scale, centerX, centerY, true);
}
protected void zoomTo(float scale, float centerX, float centerY,
boolean limit) {
if (limit) {
if (scale > mMaxZoom) {
scale = mMaxZoom;
} else if (scale < mMinZoom) {
scale = mMinZoom;
}
}
float oldScale = getScale();
float deltaScale = scale / oldScale;
mSuppMatrix.postScale(deltaScale, deltaScale, centerX, centerY);
setImageMatrix(getImageViewMatrix());
center(true, true);
}
protected void zoomTo(final float scale, final float centerX,
final float centerY, final float durationMs) {
final float incrementPerMs = (scale - getScale()) / durationMs;
final float oldScale = getScale() + mMinZoom;
final long startTime = System.currentTimeMillis();
mHandler.post(new Runnable() {
public void run() {
long now = System.currentTimeMillis();
float currentMs = Math.min(durationMs, now - startTime);
float target = oldScale + (incrementPerMs * currentMs);
zoomTo(target, centerX, centerY);
if (currentMs < durationMs) {
mHandler.post(this);
}
}
});
}
protected void zoomBigToSmall(final float scale, final float centerX,
final float centerY, final float durationMs) {
final float incrementPerMs = (scale - getScale()) / durationMs;
final float oldScale = getScale() + mMaxZoom;
final long startTime = System.currentTimeMillis();
mHandler.post(new Runnable() {
public void run() {
long now = System.currentTimeMillis();
float currentMs = Math.min(durationMs, now - startTime);
float target = oldScale + (incrementPerMs * currentMs);
zoomTo(target, centerX, centerY);
if (currentMs < durationMs) {
mHandler.post(this);
}
}
});
}
protected void zoomTo(float scale) {
float cx = getWidth() / 2F;
float cy = getHeight() / 2F;
zoomTo(scale, cx, cy);
}
protected void zoomToPoint(float scale, float pointX, float pointY) {
float cx = getWidth() / 2F;
float cy = getHeight() / 2F;
panBy(cx - pointX, cy - pointY);
zoomTo(scale, cx, cy);
}
protected void zoomIn() {
zoomIn(SCALE_RATE);
}
protected void zoomOut() {
zoomOut(SCALE_RATE);
}
protected void zoomIn(float rate) {
if (getScale() >= mMaxZoom) {
return; // Don't let the user zoom into the molecular level.
} else if (getScale() <= mMinZoom) {
return;
}
if (image == null) {
return;
}
float cx = getWidth() / 2F;
float cy = getHeight() / 2F;
mSuppMatrix.postScale(rate, rate, cx, cy);
setImageMatrix(getImageViewMatrix());
}
protected void zoomOut(float rate) {
if (image == null) {
return;
}
float cx = getWidth() / 2F;
float cy = getHeight() / 2F;
// Zoom out to at most 1x.
Matrix tmp = new Matrix(mSuppMatrix);
tmp.postScale(1F / rate, 1F / rate, cx, cy);
if (getScale(tmp) < 1F) {
mSuppMatrix.setScale(1F, 1F, cx, cy);
} else {
mSuppMatrix.postScale(1F / rate, 1F / rate, cx, cy);
}
setImageMatrix(getImageViewMatrix());
center(true, true);
}
public void postTranslate(float dx, float dy) {
mSuppMatrix.postTranslate(dx, dy);
setImageMatrix(getImageViewMatrix());
}
private float mdy = 0.0f;
protected void postTransVerticalDuration(final float dy,
final float durationMs) {
final float incrementPerMs = dy / durationMs;
final long startTime = System.currentTimeMillis();
mdy = 0.0f;
mHandler.post(new Runnable() {
public void run() {
long now = System.currentTimeMillis();
float currentMs = Math.min(durationMs, now - startTime);
postTranslate(, incrementPerMs * currentMs - mdy);
mdy = incrementPerMs * currentMs;
if (currentMs < durationMs) {
mHandler.post(this);
}
}
});
}
private float mdx = 0.0f;
protected void postTransHorizontalDuration(final float dx,
final float durationMs) {
final float incrementPerMs = dx / durationMs;
final long startTime = System.currentTimeMillis();
mdx = 0.0f;
mHandler.post(new Runnable() {
public void run() {
long now = System.currentTimeMillis();
float currentMs = Math.min(durationMs, now - startTime);
postTranslate(incrementPerMs * currentMs - mdx, );
mdx = incrementPerMs * currentMs;
if (currentMs < durationMs) {
mHandler.post(this);
}
}
});
}
protected void panBy(float dx, float dy) {
postTranslate(dx, dy);
setImageMatrix(getImageViewMatrix());
}
private float mDeltaX, mDeltaY;
private float sx, sy;
private float width, height;
private float values[] = new float[];
private float baseValue;
private float originalScale;
private final int NONE = ;
private final int DRAG = ;
private final int ZOOM = ;
private int mMod = ;
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mDetector != null) {
mDetector.onTouchEvent(event);
}
final ZoomImageView imageView = this;
final int sWidth = WIDTH;
final int sHeight = HEIGHT;
width = imageView.getScale() * imageView.getImageWidth();
height = imageView.getScale() * imageView.getImageHeight();
Matrix matrix = imageView.getImageMatrix();
matrix.getValues(values);
float x = event.getX();
float y = event.getY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mMod = DRAG;
baseValue = ;
originalScale = imageView.getScale();
mDeltaX = ;
mDeltaY = ;
sx = x;
sy = y;
break;
case MotionEvent.ACTION_POINTER_DOWN:
mMod = ZOOM;
break;
case MotionEvent.ACTION_MOVE:
if (event.getPointerCount() == ) {
mMod = ZOOM;
}
float deltaX = sx - x;
float deltaY = sy - y;
sx = x;
sy = y;
if (deltaX != 0.0f) {
mDeltaX = deltaX;
}
if (deltaY != 0.0f) {
mDeltaY = deltaY;
}
switch (mMod) {
case DRAG:
final float left = values[Matrix.MTRANS_X];
final float right = left + width;
if(right < sWidth && Math.abs(right - sWidth) >= 0.0001f && right < width) {
v.getParent().requestDisallowInterceptTouchEvent(false);
}
else if(right > width) {
v.getParent().requestDisallowInterceptTouchEvent(false);
}
else {
v.getParent().requestDisallowInterceptTouchEvent(true);
}
if (width < sWidth) {
deltaX = 0.0f;
mDeltaX = deltaX;
}
if (height < sHeight) {
deltaY = 0.0f;
mDeltaY = deltaY;
}
imageView.postTranslate(-deltaX, -deltaY);
break;
case ZOOM:
if (event.getPointerCount() < ) {
return true;
}
float dx = event.getX() - event.getX();
float dy = event.getY() - event.getY();
float value = FloatMath.sqrt(dx * dx + dy * dy);
if (baseValue == ) {
baseValue = value;
} else {
float scale = value / baseValue;
// scale the image
imageView.zoomTo(originalScale * scale,
(event.getX() + event.getX()) / ,
(event.getY() + event.getY()) / , false);
}
break;
default:
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
final float left = values[Matrix.MTRANS_X];
final float right = left + width;
final float top = values[Matrix.MTRANS_Y];
final float bottom = top + height;
switch (mMod) {
case DRAG:
final float startX = mDeltaX;
final float startY = mDeltaY;
if (startX != ) {
if (right < sWidth) {
// ((ViewPager) v.getParent()).requestDisallowInterceptTouchEvent(false);
postTransHorizontalDuration(sWidth - right, 200.0f);
}
if (left >= ) {
postTransHorizontalDuration(-left, 200.0f);
}
}
if (startY != ) {
if (bottom < sHeight) {
postTransVerticalDuration(sHeight - bottom, 200.0f);
}
if (top > ) {
postTransVerticalDuration(-top, 200.0f);
}
}
break;
case ZOOM:
final float sr = getScaleRate();
final float scale = getScale();
mDoubleClick = false;
if (sr > scale) {
imageView.zoomTo(sr, sWidth / , sHeight / , 200.0f);
return true;
} else if (mMaxZoom < scale) {
imageView.zoomBigToSmall(sr, sWidth / , sHeight / ,
300.0f);
return true;
}
break;
}
mMod = NONE;
break;
default:
}
return true;
}
private boolean mDoubleClick;
private GestureDetector mDetector;
private OnSimpleListener listener;
public void doubleClick() {
float scale = getScale();
if (!mDoubleClick) {
zoomTo(1.0f);
mDoubleClick = true;
} else if (scale == 1.0f) {
zoomTo(2.0f);
} else if (scale == 2.0f) {
zoomTo(4.0f);
} else if (scale == 4.0f) {
zoomTo(1.0f);
}
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
if(listener != null) {
listener.setOnSimpleClickListenr();
}
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
return false;
}
public interface OnSimpleListener {
void setOnSimpleClickListenr();
}
public void setOnSimpleClickListenr(OnSimpleListener listener) {
this.listener = listener;
}
}
为了不和ViewPager的滑动冲突 主要是在action_move里面加了一个判断:
final float left = values[Matrix.MTRANS_X];
final float right = left + width; if(right < sWidth && Math.abs(right - sWidth) >= 0.0001f && right < width) {
v.getParent().requestDisallowInterceptTouchEvent(false);
}
else if(right > width) {
v.getParent().requestDisallowInterceptTouchEvent(false);
}
else {
v.getParent().requestDisallowInterceptTouchEvent(true);
}
需要源码的M我~~~
Android-相册效果(图片缩放 自由滑动)的更多相关文章
- Android 简单的图片缩放方法
很简单的一个图片缩放方法,注意要比例设置正确否则可能会内存溢出 相关问题 java.lang.IllegalArgumentException: bitmap size exceeds 32bits ...
- Android实现本地图片选择及预览缩放效果仿春雨医生
在做项目时常常会遇到选择本地图片的需求.曾经都是懒得写直接调用系统方法来选择图片.可是这样并不能实现多选效果.近期又遇到了,所以还是写一个demo好了.以后也方便使用.还是首先来看看效果 显示的图片使 ...
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
仿照微信,朋友圈分享图片功能 .可以进行图片的多张选择,拍照添加图片,以及进行图片的预览,预览时可以进行缩放,并且可以删除选中状态的图片 .很不错的源码,大家有需要可以下载看看 . 微信 微信 微信 ...
- [Android实例教程] 教你如何拍照+相册选择图片+剪裁图片完整实现
[Android实例教程] 教你如何拍照+相册选择图片+剪裁图片完整实现 今天做Android项目的时候要用到图片选择,要实现拍照获取图片和从相册获取图片,并且要求在获取完之后可以裁剪,试了很多方法之 ...
- android多点触控自由对图片缩放
在系统的相册中,观看相片就可以用多个手指进行缩放. 要实现这个功能,只需要这几步: 1.新建项目,在项目中新建一个ZoomImage.java public class ZoomImageView e ...
- Android相机、相册获取图片显示并保存到SD卡
Android相机.相册获取图片显示并保存到SD卡 [复制链接] 电梯直达 楼主 发表于 2013-3-13 19:51:43 | 只看该作者 |只看大图 本帖最后由 happy小妖同学 ...
- android 照相或从相册获取图片并裁剪
照相或从相册获取图片并裁剪 在android应用中很多时候都要获取图片(例如获取用户的头像)就需要从用户手机上获取图片.可以直接照,也可以从用户SD卡上获取图片,但获取到的图片未必能达到要求.所以要对 ...
- Android调用相册截取图片遇到的问题
1.在Android中可以使用如下的方式来调用相册,选择图片进行裁剪使用,昨天在开发的时候遇到一个问题 private void cropBigImageUri(Uri uri, int output ...
- android关于图片缩放
网上有许多关于图片缩放的demo,本人都感觉不怎么好用,最近在github看到了 一个简单的支持多指缩放图片的Android View类 gesture-imageview (地址:https://g ...
随机推荐
- oracle中存储过程的使用
存储过程 刚开始我接触到数据库的时候,感觉存储过程是很难的,但是当你看完我给你列举的例子,你就能够轻松的掌握存储过程的创建和使用了. 存储过程是在大型数据库系统中存储过程在数据库中经过第一次编译后就不 ...
- UITableViewCell 高度计算从混沌初始到天地交泰
[原创]UITableViewCell 高度计算从混沌初始到天地交泰 本文主要基予iOS UITableViewCell 高度自适应计算问题展开陈述,废话少说直入正题: UITableView控件可能 ...
- 中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030
中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030 内容详见: http://www.360doc.com/content/11/1004/12/6139921_1 ...
- 修改placeholder颜色
#contact_info为textarea的ID #contact_info::-webkit-input-placeholder{ color:#999;}#contact_info:-moz-p ...
- WTL 中的常见问题汇总
1.CRect,CPoint,CSize的使用 WTL提供了CString,CRect,CPoint和CSize,可能后来版本的ATL也提供了,WTL作者推荐使用ATL的实现,所以:#include ...
- svn 钩子 post-commit 出现255错误解决办法
首先检查代码中是否有可执行命令 #!/bin/sh 然后 检查post-commit权限 post-commit 脚本文件的权限不对,post-commit 脚本必须有 +x 权限. chown sv ...
- day19 数据库的初步认识
一:数据库的概念 数据库:一个用于储存数据并可以对之进行管理和使用的软件系统. sql:struct(结构) query(查询) language(语言) 结构化查询语言: 其实是一种国际化语言标 ...
- Apache的多路处理模块MPM:Prefork Worker Event
如何确认当前apache使用哪种模式 通过/etc/init.d/httpd中的来确认系统apache的运行脚本路径 apachectl=/usr/sbin/apachectl httpd=${HTT ...
- 1.Bloom filter
Bloom filter 是由 Howard Bloom 在 1970 年提出的二进制向量数据结构,它具有很好的空间和时间效率,被用来检测一个元素是不是集合中的一个成员,这种检测只会对在集合内的数据错 ...
- Linux下STM32开发环境的搭建
目录 一.概述 1.目的 2.开发环境描述 3.Eclipse构建的STM32集成开发环境结构 4.GDB / GDB Server 调试模型 二.搭建步骤 三.详细的搭建过程 1.安装eclipse ...