
一、自定义imageview的实现,实现了放大与缩小.
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);
ZoomState());
setOnTouchListener(mZoomListener);
mZoomControl.setAspectQuotient(getAspectQuotient());
}public void zoomImage(float f, float x, float y) {(f, x, y);
}public void setImage(Bitmap bitmap) {mBitmap = bitmap;
try {mAspectQuotient.updateAspectQuotient(getWidth(), getHeight(),
Width(), Height());
}catch (Exception e){e.printStackTrace();
}ifyObservers();
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 = ();
final int viewWidth = getWidth();
final int viewHeight = getHeight();
final int bitmapWidth = Width();
final int bitmapHeight = Height();
Log.d("ZoomImageView", "viewWidth = " + viewWidth);
Log.d("ZoomImageView", "viewHeight = " + viewHeight);
Log.d("ZoomImageView", "bitmapWidth = " + bitmapWidth);
Log.d("ZoomImageView", "bitmapHeight = " + bitmapHeight);
final float panX = PanX();
final float panY = PanY();
final float zoomX = ZoomX(aspectQuotient) * viewWidth/ bitmapWidth;
final float zoomY = ZoomY(aspectQuotient) * viewHeight/ bitmapHeight;
// Setup source and destination rectangles
mRectSrc.left = (int) (panX * bitmapWidth - viewWidth / (zoomX * 2));
p = (int) (panY * bitmapHeight - viewHeight/ (zoomY * 2));
mRectSrc.right = (int) (mRectSrc.left + viewWidth / zoomX);
mRectSrc.bottom = (int) (p + viewHeight / zoomY);
// mRectDst.left = getLeft();
mRectDst.left = 0;
p = 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 (p < 0) {p += -p * zoomY;
p = 0;
}if (mRectSrc.bottom > bitmapHeight) {mRectDst.bottom -= (mRectSrc.bottom - bitmapHeight) * zoomY;
mRectSrc.bottom = bitmapHeight;
}mRectDst.left = 0;
p = 0;
mRectDst.right = viewWidth;
mRectDst.bottom = viewHeight;
Log.d("ZoomImageView", p" + p);
Log.d("ZoomImageView", "mRectSrc.bottom" + mRectSrc.bottom);
Log.d("ZoomImageView", "mRectSrc.left" + mRectSrc.left);
Log.d("ZoomImageView", "mRectSrc.right" + mRectSrc.right);
Log.d("ZoomImageView", p" + p);
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) {Layout(changed, left, top, right, bottom);
try {mAspectQuotient.updateAspectQuotient(right - left, bottom - top,
Width(), Height());
}catch (Exception e){e.printStackTrace();
}ifyObservers();
}@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 (Action()) {case MotionEvent.ACTION_DOWN:mOldCounts = 1;
mFirstX = X();
mFirstY = Y();
break;
case MotionEvent.ACTION_MOVE: {float fFirstX = X();
float fFirstY = Y();
int nCounts = PointerCount();
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 = PointerId(nCounts - 1));
mSecondY = PointerId(nCounts - 1));
mOldCounts = nCounts;
} else {float fSecondX = PointerId(nCounts - 1));
float fSecondY = PointerId(nCounts - 1));
double nLengthOld = getLength(mFirstX, mFirstY, mSecondX,
mSecondY);
double nLengthNow = getLength(fFirstX, fFirstY, fSecondX,
fSecondY);
float d = (float) ((nLengthNow - nLengthOld) / v.getWidth());
((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 = ();
final float prevZoomX = ZoomX(aspectQuotient);
final float prevZoomY = ZoomY(aspectQuotient);
mState.Zoom() * f);
limitZoom();
final float newZoomX = ZoomX(aspectQuotient);
final float newZoomY = ZoomY(aspectQuotient);
// Pan to keep x and y coordinate invariant
mState.PanX() + (x - .5f)* (1f / prevZoomX - 1f / newZoomX));
mState.PanY() + (y - .5f)* (1f / prevZoomY - 1f / newZoomY));
limitPan();
ifyObservers();
}/**
* 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 = ();
mState.PanX() + dx/ ZoomX(aspectQuotient));
mState.PanY() + dy/ ZoomY(aspectQuotient));
limitPan();
ifyObservers();
}/**
* 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 (Zoom() < MIN_ZOOM) {mState.setZoom(MIN_ZOOM);
} else if (Zoom() > MAX_ZOOM) {mState.setZoom(MAX_ZOOM);
}}/**
* Force pan to stay within limits
*/
private void limitPan() {final float aspectQuotient = ();
final float zoomX = ZoomX(aspectQuotient);
final float zoomY = ZoomY(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 (PanX() < panMinX) {mState.setPanX(panMinX);
}if (PanX() > panMaxX) {mState.setPanX(panMaxX);
}if (PanY() < panMinY) {mState.setPanY(panMinY);
}if (PanY() > 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();
}}}
}
要使用这个自定义view,就在配置文件中定义,显示的方法就是setImage(bitmap);ZoomImageView iv = new ZoomImageView(this,null); Bitmap bitmap = BitmapUtil.lessenUriImage(this,imageurl); iv.setImage(bitmap);
本文发布于:2024-02-04 11:52:55,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170706554455312.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
| 留言与评论(共有 0 条评论) |