`
laladin.syd
  • 浏览: 8361 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

自定义ImageView,使用onLayout实现多点缩放,回弹

阅读更多

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);
 }
}
 
分享到:
评论
1 楼 u011260990 2015-04-01  
你好,你上面的实例怎么让图片刚开始的scaleType为centerCrop现实啊

相关推荐

    自定义ImageView(可单点缩放回弹、拖拽、多点缩放)

    在这个案例中,我们关注的是一个自定义的ImageView,它不仅支持单点缩放和回弹,还能进行拖拽操作,并且能够实现多点触控的缩放功能。这样的组件在创建交互式图片查看器或者画廊应用时非常有用。下面我们将详细讨论...

    Android自定义ImageView实现缩放,回弹效果

    自定义ImageView实现缩放和回弹效果,需要结合手势识别、动画以及物理模拟等技术。通过这种方式,我们可以为用户提供更加自然、流畅的交互体验。在实际项目中,还可以根据需求添加更多细节,如平移、旋转等功能,...

    自定义ImageView实现多点触控源码

    本教程将深入探讨如何创建一个自定义的ImageView,实现多点触控功能,以支持图片的自由移动和缩放,同时解决与ViewPager的兼容性问题。 首先,我们需要了解多点触控的基本原理。在Android中,多点触控是通过`...

    android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果

    总之,实现一个支持手势滑动和多点触摸缩放的自定义ImageView,需要深入了解Android的触摸事件机制、Matrix变换以及手势识别的相关知识。通过结合这些技术,我们可以创建出更加灵活、互动性更强的图片查看组件,提升...

    自定义ImageView实现图片的缩放功能

    本文将深入探讨如何通过自定义ImageView来实现图片的缩放功能。在Android的UI设计中,ImageView通常用于显示图像,但默认情况下,它并不支持复杂的交互操作,如平移、缩放等。为了满足这些需求,我们需要对其进行...

    自定义ImageView图片缩放

    我们可以在自定义ImageView中集成这些库,通过重写`onLayout()`或`onDraw()`方法,实现图片的下载、缓存和绘制。 在具体实现图片缩放时,有几种常见的策略。一种是按需缩放,即只在显示图片时才进行缩放,这样可以...

    android自定义ImageView实现缩放,回弹效果.pdf

    总的来说,自定义ImageView实现缩放和回弹效果涉及到了Android的触摸事件处理、动画框架的使用以及对屏幕尺寸和图片尺寸的理解。这是一个涉及到多方面技术的综合实践,对于提升Android应用的用户体验有着重要的作用...

    自定义ImageView,实现指定任意角为圆角

    本篇文章将详细介绍如何通过自定义ImageView类来实现这一功能,并结合Glide库加载网络图片,使得顶部两个角为圆角,底部两个角为直角。 首先,我们要创建一个新的自定义ImageView类。这个类需要继承自Android的...

    自定义Imageview控件实现多种手势操作 (拖动、水平缩放、竖直缩放、等比例缩放、双击、长按)

    该自定义控件实现的主要功能是控件的拖动和缩放(注意:不是对控件中的图片进行操作,话说很多帖子都把这两个混了),其中缩放可以按照三个方向进行,就是水平、竖直和等比例。双击操作只做了一个提示,长按加上了一...

    Demo.rar Popupwindow中图片的缩放,activity中图片缩放自定义ImageView

    在Popupwindow中展示图片并实现缩放,需要处理触摸事件,计算缩放比例,并更新图片的大小和位置。 2. **自定义ImageView**:系统提供的ImageView默认只支持简单的图片显示,但不包含缩放功能。为了实现图片的缩放,...

    Android 自定义ImageView(移动、缩放、旋转)

    本文将深入探讨如何自定义一个名为`MutiTouchImageView`的ImageView,它支持手势操作,包括移动、缩放和旋转图像。这对于创建交互式的应用界面,如图片查看器或编辑器等场景非常有用。 首先,我们需要继承`...

    android自定义imageview实现放大缩小

    今天我们将深入探讨如何使用自定义ImageView实现图片的放大和缩小功能。自定义ImageView不仅能够提供更灵活的图像展示方式,还能优化性能,避免系统默认ImageView在处理大图时可能出现的内存问题。 首先,我们创建...

    android自定义ImageView实现旋转动画

    本文将深入探讨如何通过自定义ImageView来实现旋转动画,让图片在XYZ轴上动态展示,为用户带来更加生动的视觉效果。 首先,我们需要创建一个新的类,继承自Android的内置ImageView类。这个新类将作为我们自定义的...

    Android实现圆形、圆角、椭圆自定义ImageView(源代码)

    Android实现圆形、圆角、椭圆自定义ImageView,使用Xfermode渲染模式渲染图形实现的,代码有注释,读起来通俗易懂,有需要的可以下载哈 Android实现圆形、圆角、椭圆自定义ImageView,使用Xfermode渲染模式渲染图形...

    Android通过自定义ImageView控件实现图片的缩放和拖动的实现代码

    概述:通过自定义ImageView控件,在xml布局里面调用自定的组件实现图片的缩放。 /** * 自定义的ImageView控制,可对图片进行多点触控缩放和拖动 * * @author qiuwanyong */ public class MyImageView extends ...

    Android开发之ImageView通过matrix实现两点缩放和图片拖动

    然而,仅靠基本的ImageView功能,我们往往无法满足一些复杂的交互需求,比如用户可以对图片进行拖动和双指缩放。这种功能通常需要借助Matrix类来实现。Matrix是Android图形系统中的一个关键类,它允许我们对坐标系统...

Global site tag (gtag.js) - Google Analytics