转载请注明原文出处:奔跑的蜗牛(袁方的技术博客)点击打开链接
原始图片:
点击放大按钮,或两手拖拉屏幕。
上代码:
public class main extends Activity { /** Called when the activity is first created. */ private ImageZoomView mZoomView; private ZoomState mZoomState; private Bitmap mBitmap; private SimpleZoomListener mZoomListener; private ProgressBar progressBar; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { progressBar.setVisibility(View.GONE); mZoomView.setImage(mBitmap); mZoomState = new ZoomState(); mZoomView.setZoomState(mZoomState); mZoomListener = new SimpleZoomListener(); mZoomListener.setZoomState(mZoomState); mZoomView.setOnTouchListener(mZoomListener); resetZoomState(); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 隐藏顶部程序名称 写在setContentView(R.layout.xxxx);之前,不然报错 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); requestWindowFeature(Window.FEATURE_NO_TITLE); // 隐藏状态栏 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_image); mZoomView = (ImageZoomView) findViewById(R.id.zoomView); progressBar = (ProgressBar) findViewById(R.id.progress_large); progressBar.setVisibility(View.VISIBLE); Thread thread = new Thread(new Runnable() { @Override public void run() { /* * 加载网络图片 load form url */ // mBitmap = // ImageDownloader.getInstance().getBitmap(url); mBitmap = BitmapFactory.decodeResource( main.this.getResources(), R.drawable.test); handler.sendEmptyMessage(0); } }); thread.start(); ZoomControls zoomCtrl = (ZoomControls) findViewById(R.id.zoomCtrl); zoomCtrl.setOnZoomInClickListener(new OnClickListener() { @Override public void onClick(View v) { float z = mZoomState.getZoom() + 0.25f; mZoomState.setZoom(z); mZoomState.notifyObservers(); } }); zoomCtrl.setOnZoomOutClickListener(new OnClickListener() { @Override public void onClick(View v) { float z = mZoomState.getZoom() - 0.25f; mZoomState.setZoom(z); mZoomState.notifyObservers(); } }); } @Override protected void onDestroy() { super.onDestroy(); if (mBitmap != null) mBitmap.recycle(); } private void resetZoomState() { mZoomState.setPanX(0.5f); mZoomState.setPanY(0.5f); mZoomState.setZoom(1f); mZoomState.notifyObservers(); } }
public class ImageZoomView extends View implements Observer { private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); private final Rect mRectSrc = new Rect(); private final Rect mRectDst = new Rect(); private float mAspectQuotient; private Bitmap mBitmap; private ZoomState mState; public ImageZoomView(Context context, AttributeSet attrs) { super(context, attrs); } public void setZoomState(ZoomState state) { if (mState != null) { mState.deleteObserver(this); } mState = state; mState.addObserver(this); invalidate(); } protected void onDraw(Canvas canvas) { if (mBitmap != null && mState != null) { final int viewWidth = getWidth(); final int viewHeight = getHeight(); final int bitmapWidth = mBitmap.getWidth(); final int bitmapHeight = mBitmap.getHeight(); final float panX = mState.getPanX(); final float panY = mState.getPanY(); final float zoomX = mState.getZoomX(mAspectQuotient) * viewWidth / bitmapWidth; final float zoomY = mState.getZoomY(mAspectQuotient) * 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.top = getTop(); mRectDst.right = getRight(); mRectDst.bottom = getBottom(); // 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; } canvas.drawBitmap(mBitmap, mRectSrc, mRectDst, mPaint); } } public void update(Observable observable, Object data) { invalidate(); } private void calculateAspectQuotient() { if (mBitmap != null) { mAspectQuotient = (((float) mBitmap.getWidth()) / mBitmap .getHeight()) / (((float) getWidth()) / getHeight()); } } public void setImage(Bitmap bitmap) { mBitmap = bitmap; calculateAspectQuotient(); invalidate(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); calculateAspectQuotient(); } }
public class SimpleZoomListener implements View.OnTouchListener { public enum ControlType { PAN, ZOOM } @SuppressWarnings("unused") private ControlType mControlType = ControlType.PAN; private ZoomState mState; private float mX; private float mY; private float mGap; public void setZoomState(ZoomState state) { mState = state; } public void setControlType(ControlType controlType) { mControlType = controlType; } public boolean onTouch(View v, MotionEvent event) { final int action = event.getAction(); int pointCount = event.getPointerCount(); if (pointCount == 1) { final float x = event.getX(); final float y = event.getY(); switch (action) { case MotionEvent.ACTION_DOWN: mX = x; mY = y; break; case MotionEvent.ACTION_MOVE: { final float dx = (x - mX) / v.getWidth(); final float dy = (y - mY) / v.getHeight(); mState.setPanX(mState.getPanX() - dx); mState.setPanY(mState.getPanY() - dy); mState.notifyObservers(); mX = x; mY = y; break; } } } if (pointCount == 2) { final float x0 = event.getX(event.getPointerId(0)); final float y0 = event.getY(event.getPointerId(0)); final float x1 = event.getX(event.getPointerId(1)); final float y1 = event.getY(event.getPointerId(1)); final float gap = getGap(x0, x1, y0, y1); switch (action) { case MotionEvent.ACTION_POINTER_2_DOWN: case MotionEvent.ACTION_POINTER_1_DOWN: mGap = gap; break; case MotionEvent.ACTION_POINTER_1_UP: mX = x1; mY = y1; break; case MotionEvent.ACTION_POINTER_2_UP: mX = x0; mY = y0; break; case MotionEvent.ACTION_MOVE: { final float dgap = (gap - mGap) / mGap; // Log.d("Gap", String.valueOf(dgap)); Log.d("Gap", String.valueOf((float) Math.pow(20, dgap))); mState.setZoom(mState.getZoom() * (float) Math.pow(5, dgap)); mState.notifyObservers(); mGap = gap; break; } } } return true; } private float getGap(float x0, float x1, float y0, float y1) { return (float) Math.pow( Math.pow((x0 - x1), 2) + Math.pow((y0 - y1), 2), 0.5); } }
public class ZoomState extends Observable { private float mZoom; private float mPanX; private float mPanY; public float getPanX() { return mPanX; } public float getPanY() { return mPanY; } public float getZoom() { return mZoom; } public void setPanX(float panX) { if (panX != mPanX) { mPanX = panX; setChanged(); } } public void setPanY(float panY) { if (panY != mPanY) { mPanY = panY; setChanged(); } } public void setZoom(float zoom) { if (zoom != mZoom) { mZoom = zoom; setChanged(); } } public float getZoomX(float aspectQuotient) { return Math.min(mZoom, mZoom * aspectQuotient); } public float getZoomY(float aspectQuotient) { return Math.min(mZoom, mZoom / aspectQuotient); } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent"> <RelativeLayout android:id="@+id/zoomViewRelativeLayout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_above="@+id/zoomControlRelativeLayout" android:layout_marginBottom="2px" > <whu.iss.activity.ImageZoomView android:id="@+id/zoomView" android:layout_width="fill_parent" android:layout_height="fill_parent" > </whu.iss.activity.ImageZoomView> <ProgressBar android:id="@+id/progress_large" android:layout_height="wrap_content" android:layout_width="wrap_content" style="?android:attr/progressBarStyleLarge" android:visibility="gone" android:layout_centerInParent="true"/> </RelativeLayout> <RelativeLayout android:id="@+id/zoomControlRelativeLayout" android:layout_width="fill_parent" android:layout_height="50px" android:layout_alignParentBottom="true" > <ZoomControls android:id="@+id/zoomCtrl" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:gravity="center" > </ZoomControls> </RelativeLayout> </RelativeLayout> </LinearLayout>
工程下载地址:点击打开链接 另补充 Android Gallery3D 源码 已编译 :地址http://download.csdn.net/detail/yf210yf/4102113