转载请注明原文出处:奔跑的蜗牛(袁方的技术博客)点击打开链接
原始图片:
点击放大按钮,或两手拖拉屏幕。
上代码:
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>