欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android手势滑动实现两点触摸缩放图片

程序员文章站 2024-02-23 14:37:28
学习安卓手势滑动,多点触摸放大缩小图片,分享给大家供大家参考,具体代码如下 1.布局文件如下main.xml

学习安卓手势滑动,多点触摸放大缩小图片,分享给大家供大家参考,具体代码如下
1.布局文件如下main.xml

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:orientation="vertical" >

 <!-- 引用自定义控件 -->
 <com.ymw.zoomimage.zoomimageview
  android:id="@+id/image"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" >
 </com.ymw.zoomimage.zoomimageview>

</linearlayout>

2.自定义缩放图片控件zoomimageview.java代码:

package com.ymw.zoomimage;

import java.util.observable;
import java.util.observer;

import android.content.context;
import android.graphics.bitmap;
import android.graphics.canvas;
import android.graphics.paint;
import android.graphics.rect;
import android.util.attributeset;
import android.util.log;
import android.view.motionevent;
import android.view.view;

public class zoomimageview extends view implements observer {

 /** paint object used when drawing bitmap. */
 private final paint mpaint = new paint(paint.filter_bitmap_flag);

 /** rectangle used (and re-used) for cropping source image. */
 private final rect mrectsrc = new rect();

 /** rectangle used (and re-used) for specifying drawing area on canvas. */
 private final rect mrectdst = new rect();

 /** object holding aspect quotient */
 private final aspectquotient maspectquotient = new aspectquotient();

 /** the bitmap that we're zooming in, and drawing on the screen. */
 private bitmap mbitmap;

 /** state of the zoom. */
 private zoomstate mstate;

 private basiczoomcontrol mzoomcontrol;
 private basiczoomlistener mzoomlistener;

 public zoomimageview(context context, attributeset attrs) {
  super(context, attrs);

  mzoomcontrol = new basiczoomcontrol();

  mzoomlistener = new basiczoomlistener();
  mzoomlistener.setzoomcontrol(mzoomcontrol);

  setzoomstate(mzoomcontrol.getzoomstate());

  setontouchlistener(mzoomlistener);

  mzoomcontrol.setaspectquotient(getaspectquotient());
 }

 public void zoomimage(float f, float x, float y) {
  mzoomcontrol.zoom(f, x, y);
 }

 public void setimage(bitmap bitmap) {
  mbitmap = bitmap;

  maspectquotient.updateaspectquotient(getwidth(), getheight(),
    mbitmap.getwidth(), mbitmap.getheight());
  maspectquotient.notifyobservers();

  invalidate();
 }

 private void setzoomstate(zoomstate state) {
  if (mstate != null) {
   mstate.deleteobserver(this);
  }

  mstate = state;
  mstate.addobserver(this);

  invalidate();
 }

 private aspectquotient getaspectquotient() {
  return maspectquotient;
 }

 @override
 protected void ondraw(canvas canvas) {
  if (mbitmap != null && mstate != null) {

   log.d("zoomimageview", "ondraw");

   final float aspectquotient = maspectquotient.get();

   final int viewwidth = getwidth();
   final int viewheight = getheight();
   final int bitmapwidth = mbitmap.getwidth();
   final int bitmapheight = mbitmap.getheight();

   log.d("zoomimageview", "viewwidth = " + viewwidth);
   log.d("zoomimageview", "viewheight = " + viewheight);
   log.d("zoomimageview", "bitmapwidth = " + bitmapwidth);
   log.d("zoomimageview", "bitmapheight = " + bitmapheight);

   final float panx = mstate.getpanx();
   final float pany = mstate.getpany();
   final float zoomx = mstate.getzoomx(aspectquotient) * viewwidth
     / bitmapwidth;
   final float zoomy = mstate.getzoomy(aspectquotient) * viewheight
     / bitmapheight;

   // setup source and destination rectangles
   mrectsrc.left = (int) (panx * bitmapwidth - viewwidth / (zoomx * 2));
   mrectsrc.top = (int) (pany * bitmapheight - viewheight
     / (zoomy * 2));
   mrectsrc.right = (int) (mrectsrc.left + viewwidth / zoomx);
   mrectsrc.bottom = (int) (mrectsrc.top + viewheight / zoomy);
   // mrectdst.left = getleft();
   mrectdst.left = 0;
   mrectdst.top = 0;
   // mrectdst.right = getright();
   mrectdst.right = getwidth();
   mrectdst.bottom = getheight();

   // adjust source rectangle so that it fits within the source image.
   if (mrectsrc.left < 0) {
    mrectdst.left += -mrectsrc.left * zoomx;
    mrectsrc.left = 0;
   }
   if (mrectsrc.right > bitmapwidth) {
    mrectdst.right -= (mrectsrc.right - bitmapwidth) * zoomx;
    mrectsrc.right = bitmapwidth;
   }
   if (mrectsrc.top < 0) {
    mrectdst.top += -mrectsrc.top * zoomy;
    mrectsrc.top = 0;
   }
   if (mrectsrc.bottom > bitmapheight) {
    mrectdst.bottom -= (mrectsrc.bottom - bitmapheight) * zoomy;
    mrectsrc.bottom = bitmapheight;
   }

   mrectdst.left = 0;
   mrectdst.top = 0;
   mrectdst.right = viewwidth;
   mrectdst.bottom = viewheight;

   log.d("zoomimageview", "mrectsrc.top" + mrectsrc.top);
   log.d("zoomimageview", "mrectsrc.bottom" + mrectsrc.bottom);
   log.d("zoomimageview", "mrectsrc.left" + mrectsrc.left);
   log.d("zoomimageview", "mrectsrc.right" + mrectsrc.right);

   log.d("zoomimageview", "mrectdst.top" + mrectdst.top);
   log.d("zoomimageview", "mrectdst.bottom" + mrectdst.bottom);
   log.d("zoomimageview", "mrectdst.left" + mrectdst.left);
   log.d("zoomimageview", "mrectdst.right" + mrectdst.right);

   canvas.drawbitmap(mbitmap, mrectsrc, mrectdst, mpaint);
  }
 }

 @override
 protected void onlayout(boolean changed, int left, int top, int right,
   int bottom) {
  super.onlayout(changed, left, top, right, bottom);

  maspectquotient.updateaspectquotient(right - left, bottom - top,
    mbitmap.getwidth(), mbitmap.getheight());
  maspectquotient.notifyobservers();
 }

 @override
 public void update(observable observable, object data) {
  invalidate();
 }

 private class basiczoomlistener implements view.ontouchlistener {

  /** zoom control to manipulate */
  private basiczoomcontrol mzoomcontrol;

  private float mfirstx = -1;
  private float mfirsty = -1;
  private float msecondx = -1;
  private float msecondy = -1;

  private int moldcounts = 0;

  /**
   * sets the zoom control to manipulate
   * 
   * @param control
   *   zoom control
   */
  public void setzoomcontrol(basiczoomcontrol control) {
   mzoomcontrol = control;
  }

  public boolean ontouch(view v, motionevent event) {

   switch (event.getaction()) {
   case motionevent.action_down:
    moldcounts = 1;
    mfirstx = event.getx();
    mfirsty = event.gety();
    break;
   case motionevent.action_move: {
    float ffirstx = event.getx();
    float ffirsty = event.gety();

    int ncounts = event.getpointercount();

    if (1 == ncounts) {
     moldcounts = 1;
     float dx = (ffirstx - mfirstx) / v.getwidth();
     float dy = (ffirsty - mfirsty) / v.getheight();
     mzoomcontrol.pan(-dx, -dy);
    } else if (1 == moldcounts) {
     msecondx = event.getx(event.getpointerid(ncounts - 1));
     msecondy = event.gety(event.getpointerid(ncounts - 1));
     moldcounts = ncounts;
    } else {
     float fsecondx = event
       .getx(event.getpointerid(ncounts - 1));
     float fsecondy = event
       .gety(event.getpointerid(ncounts - 1));

     double nlengthold = getlength(mfirstx, mfirsty, msecondx,
       msecondy);
     double nlengthnow = getlength(ffirstx, ffirsty, fsecondx,
       fsecondy);

     float d = (float) ((nlengthnow - nlengthold) / v.getwidth());

     mzoomcontrol.zoom((float) math.pow(20, d),
       ((ffirstx + fsecondx) / 2 / v.getwidth()),
       ((ffirsty + fsecondy) / 2 / v.getheight()));

     msecondx = fsecondx;
     msecondy = fsecondy;
    }
    mfirstx = ffirstx;
    mfirsty = ffirsty;

    break;
   }

   }

   return true;
  }

  private double getlength(float x1, float y1, float x2, float y2) {
   return math.sqrt(math.pow(x1 - x2, 2) + math.pow(y1 - y2, 2));
  }
 }

 private class basiczoomcontrol implements observer {

  /** minimum zoom level limit */
  private static final float min_zoom = 1;

  /** maximum zoom level limit */
  private static final float max_zoom = 16;

  /** zoom state under control */
  private final zoomstate mstate = new zoomstate();

  /** object holding aspect quotient of view and content */
  private aspectquotient maspectquotient;

  /**
   * set reference object holding aspect quotient
   * 
   * @param aspectquotient
   *   object holding aspect quotient
   */
  public void setaspectquotient(aspectquotient aspectquotient) {
   if (maspectquotient != null) {
    maspectquotient.deleteobserver(this);
   }

   maspectquotient = aspectquotient;
   maspectquotient.addobserver(this);
  }

  /**
   * get zoom state being controlled
   * 
   * @return the zoom state
   */
  public zoomstate getzoomstate() {
   return mstate;
  }

  /**
   * zoom
   * 
   * @param f
   *   factor of zoom to apply
   * @param x
   *   x-coordinate of invariant position
   * @param y
   *   y-coordinate of invariant position
   */
  public void zoom(float f, float x, float y) {

   // log.d("zoom", "zoom f = " + f);

   final float aspectquotient = maspectquotient.get();

   final float prevzoomx = mstate.getzoomx(aspectquotient);
   final float prevzoomy = mstate.getzoomy(aspectquotient);

   mstate.setzoom(mstate.getzoom() * f);
   limitzoom();

   final float newzoomx = mstate.getzoomx(aspectquotient);
   final float newzoomy = mstate.getzoomy(aspectquotient);

   // pan to keep x and y coordinate invariant
   mstate.setpanx(mstate.getpanx() + (x - .5f)
     * (1f / prevzoomx - 1f / newzoomx));
   mstate.setpany(mstate.getpany() + (y - .5f)
     * (1f / prevzoomy - 1f / newzoomy));

   limitpan();

   mstate.notifyobservers();
  }

  /**
   * pan
   * 
   * @param dx
   *   amount to pan in x-dimension
   * @param dy
   *   amount to pan in y-dimension
   */
  public void pan(float dx, float dy) {
   final float aspectquotient = maspectquotient.get();

   mstate.setpanx(mstate.getpanx() + dx
     / mstate.getzoomx(aspectquotient));
   mstate.setpany(mstate.getpany() + dy
     / mstate.getzoomy(aspectquotient));

   limitpan();

   mstate.notifyobservers();
  }

  /**
   * help function to figure out max delta of pan from center position.
   * 
   * @param zoom
   *   zoom value
   * @return max delta of pan
   */
  private float getmaxpandelta(float zoom) {
   return math.max(0f, .5f * ((zoom - 1) / zoom));
  }

  /**
   * force zoom to stay within limits
   */
  private void limitzoom() {
   if (mstate.getzoom() < min_zoom) {
    mstate.setzoom(min_zoom);
   } else if (mstate.getzoom() > max_zoom) {
    mstate.setzoom(max_zoom);
   }
  }

  /**
   * force pan to stay within limits
   */
  private void limitpan() {
   final float aspectquotient = maspectquotient.get();

   final float zoomx = mstate.getzoomx(aspectquotient);
   final float zoomy = mstate.getzoomy(aspectquotient);

   final float panminx = .5f - getmaxpandelta(zoomx);
   final float panmaxx = .5f + getmaxpandelta(zoomx);
   final float panminy = .5f - getmaxpandelta(zoomy);
   final float panmaxy = .5f + getmaxpandelta(zoomy);

   if (mstate.getpanx() < panminx) {
    mstate.setpanx(panminx);
   }
   if (mstate.getpanx() > panmaxx) {
    mstate.setpanx(panmaxx);
   }
   if (mstate.getpany() < panminy) {
    mstate.setpany(panminy);
   }
   if (mstate.getpany() > panmaxy) {
    mstate.setpany(panmaxy);
   }
  }

  // observable interface implementation

  public void update(observable observable, object data) {
   limitzoom();
   limitpan();
  }
 }

 private class aspectquotient extends observable {

  /**
   * aspect quotient
   */
  private float maspectquotient;

  // public methods

  /**
   * gets aspect quotient
   * 
   * @return the aspect quotient
   */
  public float get() {
   return maspectquotient;
  }

  /**
   * updates and recalculates aspect quotient based on supplied view and
   * content dimensions.
   * 
   * @param viewwidth
   *   width of view
   * @param viewheight
   *   height of view
   * @param contentwidth
   *   width of content
   * @param contentheight
   *   height of content
   */
  public void updateaspectquotient(float viewwidth, float viewheight,
    float contentwidth, float contentheight) {
   final float aspectquotient = (contentwidth / contentheight)
     / (viewwidth / viewheight);

   if (aspectquotient != maspectquotient) {
    maspectquotient = aspectquotient;
    setchanged();
   }
  }
 }

 private class zoomstate extends observable {
  /**
   * zoom level a value of 1.0 means the content fits the view.
   */
  private float mzoom;

  /**
   * pan position x-coordinate x-coordinate of zoom window center
   * position, relative to the width of the content.
   */
  private float mpanx;

  /**
   * pan position y-coordinate y-coordinate of zoom window center
   * position, relative to the height of the content.
   */
  private float mpany;

  // public methods

  /**
   * get current x-pan
   * 
   * @return current x-pan
   */
  public float getpanx() {
   return mpanx;
  }

  /**
   * get current y-pan
   * 
   * @return current y-pan
   */
  public float getpany() {
   return mpany;
  }

  /**
   * get current zoom value
   * 
   * @return current zoom value
   */
  public float getzoom() {
   return mzoom;
  }

  /**
   * help function for calculating current zoom value in x-dimension
   * 
   * @param aspectquotient
   *   (aspect ratio content) / (aspect ratio view)
   * @return current zoom value in x-dimension
   */
  public float getzoomx(float aspectquotient) {
   return math.min(mzoom, mzoom * aspectquotient);
  }

  /**
   * help function for calculating current zoom value in y-dimension
   * 
   * @param aspectquotient
   *   (aspect ratio content) / (aspect ratio view)
   * @return current zoom value in y-dimension
   */
  public float getzoomy(float aspectquotient) {
   return math.min(mzoom, mzoom / aspectquotient);
  }

  /**
   * set pan-x
   * 
   * @param panx
   *   pan-x value to set
   */
  public void setpanx(float panx) {
   if (panx != mpanx) {
    mpanx = panx;
    setchanged();
   }
  }

  /**
   * set pan-y
   * 
   * @param pany
   *   pan-y value to set
   */
  public void setpany(float pany) {
   if (pany != mpany) {
    mpany = pany;
    setchanged();
   }
  }

  /**
   * set zoom
   * 
   * @param zoom
   *   zoom value to set
   */
  public void setzoom(float zoom) {
   if (zoom != mzoom) {
    mzoom = zoom;
    setchanged();
   }
  }
 }
}

3.工程主文件mainactivity.java代码:

package com.ymw.zoomimage;

import android.app.activity;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.os.bundle;

public class mainactivity extends activity {

 private zoomimageview zoomimg;

 @override
 public void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.main);
  zoomimg = (zoomimageview) findviewbyid(r.id.image);
  bitmap bitmap = bitmapfactory.decoderesource(this.getresources(),
    r.drawable.a);
  zoomimg.setimage(bitmap);

 }
}

以上就是android多点触摸放大缩小图片的示例代码,希望对大家的学习有所帮助。