package laladin.album;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
/**
* ImageView Tonuch
* @author Laladin.SYD
*
*/
public class MyImageView extends ImageView {
static final int NONE = 0;
// 拖动中
static final int DRAG = 1;
// 缩放中
static final int ZOOM = 2;
// 放大ing
static final int BIGGER = 3;
// 缩小ing
static final int SMALLER = 4;
//关闭缩放动画
static final int OPENSCALE=1;
//关闭移动动画
static final int OPENTRANS=2;
// 当前的事件
private int mode = NONE;
// 两触点距离
private float beforeLenght;
// 两触点距离
private float afterLenght;
// 缩放的比例 X Y方向都是这个值 越大缩放的越快
private float scale = 0.06f;
/* 处理拖动 变量 */
private int screenW;
private int screenH;
private int start_x;
private int start_y;
private int stop_x;
private int stop_y;
private TranslateAnimation trans;
/* Bitmap的宽高 */
private int bmWidth;
private int bmHeight;
// 处理超出边界的动画
private Bitmap bitmap;
private float maxScale = 2.0f;
private float minScale = 1.0f;
//记录初始宽度,用于缩放回弹
private int startWidth = 0;
private float piovtX=0.5f;
private float piovtY=0.5f;
//默认开启所有动画
private int AnimSwitch=OPENSCALE|OPENTRANS;
/**
* 构造函数
*
* @param context
* 相关上下文
* @param w
* 容器的宽
* @param h
* 容器的高
*/
public MyImageView(Context context, int w, int h) {
super(context);
this.setPadding(0, 0, 0, 0);
screenW = w;
screenH = h;
}
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
//重置startWidth
startWidth=0;
bmWidth = bm.getWidth();
bmHeight = bm.getHeight();
if (bitmap != null && !bitmap.isRecycled())
bitmap.recycle();
bitmap = bm;
}
/**
* 释放ImageView的Bitmap
*/
public void recycle() {
setImageBitmap(null);
if (bitmap != null && !bitmap.isRecycled())
bitmap.recycle();
}
/**
* 计算两点间的距离
*/
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private float[] center;
/**
* 计算两点间的中心点
*/
private float[] centerPostion(MotionEvent event) {
float[] center = new float[2];
float x = event.getX(0);
float y = event.getY(0);
float x1 = event.getX(1);
float y1 = event.getY(1);
/* x,y分别的距离 */
center[0] = Math.abs((x1 - x) / 2);
center[1] = Math.abs((y1 - y) / 2);
center[0] = Math.max(x, x1) - center[0];
center[1] = Math.max(y, y1) - center[1];
return center;
}
/**
* 设置ImageView大小等于显示的内容大小
*/
public void setRect() {
float scale = Math.min((float) getWidth() / (float) bmWidth,
(float) getHeight() / (float) bmHeight);
int w = (int) ((float) bmWidth * scale) + 1;
int h = (int) ((float) bmHeight * scale) + 1;
// int t=(screenH-h)/2;
// int l=(screenW-w)/2;
int t = getTop();
int l = getLeft();
layout(l, t, l + w, t + h);
}
/**
* 处理各种移动回弹
*
* @param disX
* X的偏移
* @param disY
* Y的偏移
*/
public void Rebound(int disX, int disY) {
this.layout(getLeft() + disX, getTop() + disY, getLeft() + disX
+ getWidth(), getTop() + disY + getHeight());
if((AnimSwitch&OPENTRANS)==0)
return;
trans = new TranslateAnimation(-disX, 0, -disY, 0);
trans.setInterpolator(new AccelerateInterpolator());
trans.setDuration(300);
this.startAnimation(trans);
}
/**
* 处理各种缩放回弹
*/
public boolean ReScale() {
float scaleX = 1f;
float scaleY = 1f;
int width=getWidth();
int height=getHeight();
int l,t,r,b;
if (center==null) return false;
if (getWidth() > startWidth * maxScale) {
while(getWidth()>startWidth * maxScale){
l = this.getLeft() + (int) (center[0] * this.getWidth());
t = this.getTop() + (int) (center[1] * this.getHeight());
r = this.getRight() - (int) ((scale - center[0]) * this.getWidth());
b = this.getBottom()- (int) ((scale - center[1]) * this.getHeight());
this.setFrame(l, t, r, b);
}
scaleX=(float)width/(float)getWidth();
scaleY=(float)height/(float)getHeight();
}
if (getWidth() < startWidth * minScale) {
while(getWidth() < startWidth * minScale){
l = this.getLeft() - (int) (center[0] * this.getWidth());
t = this.getTop() - (int) (center[1] * this.getHeight());
r = this.getRight() + (int) ((scale - center[0]) * this.getWidth());
b = this.getBottom()+ (int) ((scale - center[1]) * this.getHeight());
this.setFrame(l, t, r, b);
}
scaleX=(float)width/(float)getWidth();
scaleY=(float)height/(float)getHeight();
}
if (scaleX == 1f && scaleY == 1f)
return false;
if((AnimSwitch&OPENSCALE)==0){
setRect();
onRebound();
return true;
}
ScaleAnimation scaleanim = new ScaleAnimation(scaleX, 1f, scaleY, 1f,
ScaleAnimation.RELATIVE_TO_SELF, piovtX,
ScaleAnimation.RELATIVE_TO_SELF, piovtY);
scaleanim.setDuration(300);
scaleanim.setInterpolator(new AccelerateInterpolator());
scaleanim.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation paramAnimation) {}
@Override
public void onAnimationRepeat(Animation paramAnimation) {}
@Override
public void onAnimationEnd(Animation paramAnimation) {
setRect();
onRebound();
}
});
this.startAnimation(scaleanim);
return true;
}
/**
* 处理超范围回弹
*/
private void onRebound() {
/* 判断是否超出范围 并处理 */
int disX = 0,
disY = 0;
if (getHeight() < screenH) {
disY = (screenH - getHeight()) / 2 - getTop();
}
if (getWidth() < screenW) {
disX = (screenW - getWidth()) / 2 - getLeft();
}
if (getHeight() >= screenH) {
if (getTop() > 0)
disY = -getTop();
if (getBottom() < screenH)
disY = screenH - getBottom();
}
if (getWidth() >= screenW) {
if (getLeft() > 0)
disX = -getLeft();
if (getRight() < screenW)
disX = screenW - getRight();
}
//开始回弹
Rebound(disX, disY);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
// TODO Auto-generated method stub
super.onLayout(changed, left, top, right, bottom);
if (startWidth == 0) {
startWidth = right - left;
setRect();
AnimSwitch=0;
onRebound();
AnimSwitch=OPENSCALE|OPENTRANS;
}
}
/**
* 处理触碰..
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = DRAG;
stop_x = (int) event.getRawX();
stop_y = (int) event.getRawY();
start_x = (int) event.getX();
start_y = stop_y - this.getTop();
if (event.getPointerCount() == 2)
beforeLenght = spacing(event);
break;
case MotionEvent.ACTION_POINTER_DOWN:
/** 下面三句用于计算缩放中心点位置 **/
center = centerPostion(event);
piovtX=center[0]/getWidth();
piovtY=center[1]/getHeight();
center[0] = (center[0] / getWidth()) * scale;
center[1] = (center[1] / getHeight()) * scale;
if (spacing(event) > 10f) {
mode = ZOOM;
beforeLenght = spacing(event);
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
setRect();
/* 判断是否超过缩放界限 */
if (!ReScale())
onRebound();
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
/* 处理拖动 */
if (mode == DRAG) {
this.setPosition(stop_x - start_x, stop_y - start_y, stop_x
+ this.getWidth() - start_x,
stop_y - start_y + this.getHeight());
stop_x = (int) event.getRawX();
stop_y = (int) event.getRawY();
}
/* 处理缩放 */
else if (mode == ZOOM) {
if (spacing(event) > 10f) {
afterLenght = spacing(event);
float gapLenght = afterLenght - beforeLenght;
if (gapLenght == 0) {
break;
} else if (Math.abs(gapLenght) > 5f) {
if (gapLenght > 0) {
this.setScale(scale, BIGGER);
} else {
this.setScale(scale, SMALLER);
}
beforeLenght = afterLenght;
}
}
}
break;
}
return true;
}
/**
* 实现处理缩放
*/
private void setScale(float temp, int flag) {
int l = 0, t = 0, r = 0, b = 0;
if (flag == BIGGER) {
l = this.getLeft() - (int) (center[0] * this.getWidth());
t = this.getTop() - (int) (center[1] * this.getHeight());
r = this.getRight() + (int) ((scale - center[0]) * this.getWidth());
b = this.getBottom()+ (int) ((scale - center[1]) * this.getHeight());
} else if (flag == SMALLER) {
l = this.getLeft() + (int) (center[0] * this.getWidth());
t = this.getTop() + (int) (center[1] * this.getHeight());
r = this.getRight() - (int) ((scale - center[0]) * this.getWidth());
b = this.getBottom()- (int) ((scale - center[1]) * this.getHeight());
}
this.setFrame(l, t, r, b);
}
/**
* 实现处理拖动
*/
private void setPosition(int left, int top, int right, int bottom) {
this.layout(left, top, right, bottom);
}
}
分享到:
相关推荐
在这个案例中,我们关注的是一个自定义的ImageView,它不仅支持单点缩放和回弹,还能进行拖拽操作,并且能够实现多点触控的缩放功能。这样的组件在创建交互式图片查看器或者画廊应用时非常有用。下面我们将详细讨论...
自定义ImageView实现缩放和回弹效果,需要结合手势识别、动画以及物理模拟等技术。通过这种方式,我们可以为用户提供更加自然、流畅的交互体验。在实际项目中,还可以根据需求添加更多细节,如平移、旋转等功能,...
本教程将深入探讨如何创建一个自定义的ImageView,实现多点触控功能,以支持图片的自由移动和缩放,同时解决与ViewPager的兼容性问题。 首先,我们需要了解多点触控的基本原理。在Android中,多点触控是通过`...
总之,实现一个支持手势滑动和多点触摸缩放的自定义ImageView,需要深入了解Android的触摸事件机制、Matrix变换以及手势识别的相关知识。通过结合这些技术,我们可以创建出更加灵活、互动性更强的图片查看组件,提升...
本文将深入探讨如何通过自定义ImageView来实现图片的缩放功能。在Android的UI设计中,ImageView通常用于显示图像,但默认情况下,它并不支持复杂的交互操作,如平移、缩放等。为了满足这些需求,我们需要对其进行...
我们可以在自定义ImageView中集成这些库,通过重写`onLayout()`或`onDraw()`方法,实现图片的下载、缓存和绘制。 在具体实现图片缩放时,有几种常见的策略。一种是按需缩放,即只在显示图片时才进行缩放,这样可以...
总的来说,自定义ImageView实现缩放和回弹效果涉及到了Android的触摸事件处理、动画框架的使用以及对屏幕尺寸和图片尺寸的理解。这是一个涉及到多方面技术的综合实践,对于提升Android应用的用户体验有着重要的作用...
本篇文章将详细介绍如何通过自定义ImageView类来实现这一功能,并结合Glide库加载网络图片,使得顶部两个角为圆角,底部两个角为直角。 首先,我们要创建一个新的自定义ImageView类。这个类需要继承自Android的...
该自定义控件实现的主要功能是控件的拖动和缩放(注意:不是对控件中的图片进行操作,话说很多帖子都把这两个混了),其中缩放可以按照三个方向进行,就是水平、竖直和等比例。双击操作只做了一个提示,长按加上了一...
本文将深入探讨如何自定义一个名为`MutiTouchImageView`的ImageView,它支持手势操作,包括移动、缩放和旋转图像。这对于创建交互式的应用界面,如图片查看器或编辑器等场景非常有用。 首先,我们需要继承`...
在Popupwindow中展示图片并实现缩放,需要处理触摸事件,计算缩放比例,并更新图片的大小和位置。 2. **自定义ImageView**:系统提供的ImageView默认只支持简单的图片显示,但不包含缩放功能。为了实现图片的缩放,...
今天我们将深入探讨如何使用自定义ImageView实现图片的放大和缩小功能。自定义ImageView不仅能够提供更灵活的图像展示方式,还能优化性能,避免系统默认ImageView在处理大图时可能出现的内存问题。 首先,我们创建...
本文将深入探讨如何通过自定义ImageView来实现旋转动画,让图片在XYZ轴上动态展示,为用户带来更加生动的视觉效果。 首先,我们需要创建一个新的类,继承自Android的内置ImageView类。这个新类将作为我们自定义的...
Android实现圆形、圆角、椭圆自定义ImageView,使用Xfermode渲染模式渲染图形实现的,代码有注释,读起来通俗易懂,有需要的可以下载哈 Android实现圆形、圆角、椭圆自定义ImageView,使用Xfermode渲染模式渲染图形...
概述:通过自定义ImageView控件,在xml布局里面调用自定的组件实现图片的缩放。 /** * 自定义的ImageView控制,可对图片进行多点触控缩放和拖动 * * @author qiuwanyong */ public class MyImageView extends ...
本文将深入探讨如何根据给定的标题“自定义ImageView”来创建一个能够实现“两条直线裁剪图片”以及“处理wrap_content”功能的自定义图像视图。 首先,我们需要了解ImageView的基本概念。ImageView是Android SDK中...