Android手势滑动实现两点触摸缩放图片
程序员文章站
2024-02-19 22:37:52
学习安卓手势滑动,多点触摸放大缩小图片,分享给大家供大家参考,具体代码如下
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多点触摸放大缩小图片的示例代码,希望对大家的学习有所帮助。