編輯:關於Android編程
本文實例實現的主要功能是在ImageView中識別手勢用以控制圖片放大或縮小,具有一定的參考價值,分享給大家。
public class MatrixImageView extends ImageView { private GestureDetector mGestureDetector; private Matrix mMatrix = new Matrix(); private float mImageWidth; private float mImageHeight; private float mScale; private OnMovingListener mMoveListener; private OnSingleTapListener mSingleTapListener; public MatrixImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public MatrixImageView(Context context) { super(context, null); init(); } private void init() { MatrixTouchListener listener = new MatrixTouchListener(); setOnTouchListener(listener); mGestureDetector = new GestureDetector(getContext(), new GestureListener(listener)); setBackgroundColor(Color.BLACK); setScaleType(ScaleType.FIT_CENTER); } public void setOnMovingListener(OnMovingListener listener) { mMoveListener = listener; } public void setOnSingleTapListener(OnSingleTapListener onSingleTapListener) { this.mSingleTapListener = onSingleTapListener; } @Override public void setImageBitmap(Bitmap bm) { super.setImageBitmap(bm); if (getWidth() == 0) { ViewTreeObserver vto = getViewTreeObserver(); vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { public boolean onPreDraw() { initData(); MatrixImageView.this.getViewTreeObserver() .removeOnPreDrawListener(this); return true; } }); } else { initData(); } } private void initData() { mMatrix.set(getImageMatrix()); float[] values = new float[9]; mMatrix.getValues(values); mImageWidth = getWidth() / values[Matrix.MSCALE_X]; mImageHeight = (getHeight() - values[Matrix.MTRANS_Y] * 2) / values[Matrix.MSCALE_Y]; mScale = values[Matrix.MSCALE_X]; } public class MatrixTouchListener implements OnTouchListener { private static final int MODE_DRAG = 1; private static final int MODE_ZOOM = 2; private static final int MODE_UNABLE = 3; private static final float MAX_SCALE = 6; private static final float DOUBLE_CLICK_SACLE = 2; private int mMode = 0; private float mStartDis; private Matrix mCurrentMatrix = new Matrix(); private boolean mLeftDragable; private boolean mRightDragable; private boolean mFirstMove = false; private PointF mStartPoint = new PointF(); @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: mMode = MODE_DRAG; mStartPoint.set(event.getX(), event.getY()); isMatrixEnable(); startDrag(); checkDragable(); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: reSetMatrix(); stopDrag(); break; case MotionEvent.ACTION_MOVE: if (mMode == MODE_ZOOM) { setZoomMatrix(event); } else if (mMode == MODE_DRAG) { setDragMatrix(event); } else { stopDrag(); } break; case MotionEvent.ACTION_POINTER_DOWN: if (mMode == MODE_UNABLE) return true; mMode = MODE_ZOOM; mStartDis = distance(event); break; case MotionEvent.ACTION_POINTER_UP: break; default: break; } return mGestureDetector.onTouchEvent(event); } private void startDrag() { if (mMoveListener != null) mMoveListener.startDrag(); } private void stopDrag() { if (mMoveListener != null) mMoveListener.stopDrag(); } private void checkDragable() { mLeftDragable = true; mRightDragable = true; mFirstMove = true; float[] values = new float[9]; getImageMatrix().getValues(values); if (values[Matrix.MTRANS_X] >= 0) mRightDragable = false; if ((mImageWidth) * values[Matrix.MSCALE_X] + values[Matrix.MTRANS_X] <= getWidth()) { mLeftDragable = false; } } public void setDragMatrix(MotionEvent event) { if (isZoomChanged()) { float dx = event.getX() - mStartPoint.x; float dy = event.getY() - mStartPoint.y; if (Math.sqrt(dx * dx + dy * dy) > 10f) { mStartPoint.set(event.getX(), event.getY()); mCurrentMatrix.set(getImageMatrix()); float[] values = new float[9]; mCurrentMatrix.getValues(values); dy = checkDyBound(values, dy); dx = checkDxBound(values, dx, dy); mCurrentMatrix.postTranslate(dx, dy); setImageMatrix(mCurrentMatrix); } } else { stopDrag(); } } private boolean isZoomChanged() { float[] values = new float[9]; getImageMatrix().getValues(values); float scale = values[Matrix.MSCALE_X]; return scale != mScale; } private float checkDyBound(float[] values, float dy) { float height = getHeight(); if (mImageHeight * values[Matrix.MSCALE_Y] < height) return 0; if (values[Matrix.MTRANS_Y] + dy > 0) dy = -values[Matrix.MTRANS_Y]; else if (values[Matrix.MTRANS_Y] + dy < -(mImageHeight * values[Matrix.MSCALE_Y] - height)) dy = -(mImageHeight * values[Matrix.MSCALE_Y] - height) - values[Matrix.MTRANS_Y]; return dy; } private float checkDxBound(float[] values, float dx, float dy) { float width = getWidth(); if (!mLeftDragable && dx < 0) { if (Math.abs(dx) * 0.4f > Math.abs(dy) && mFirstMove) { stopDrag(); } return 0; } if (!mRightDragable && dx > 0) { if (Math.abs(dx) * 0.4f > Math.abs(dy) && mFirstMove) { stopDrag(); } return 0; } mLeftDragable = true; mRightDragable = true; if (mFirstMove) mFirstMove = false; if (mImageWidth * values[Matrix.MSCALE_X] < width) { return 0; } if (values[Matrix.MTRANS_X] + dx > 0) { dx = -values[Matrix.MTRANS_X]; } else if (values[Matrix.MTRANS_X] + dx < -(mImageWidth * values[Matrix.MSCALE_X] - width)) { dx = -(mImageWidth * values[Matrix.MSCALE_X] - width) - values[Matrix.MTRANS_X]; } return dx; } private void setZoomMatrix(MotionEvent event) { if (event.getPointerCount() < 2) return; float endDis = distance(event); if (endDis > 10f) { float scale = endDis / mStartDis; mStartDis = endDis; mCurrentMatrix.set(getImageMatrix()); float[] values = new float[9]; mCurrentMatrix.getValues(values); scale = checkMaxScale(scale, values); PointF centerF = getCenter(scale, values); mCurrentMatrix.postScale(scale, scale, centerF.x, centerF.y); setImageMatrix(mCurrentMatrix); } } private PointF getCenter(float scale, float[] values) { if (scale * values[Matrix.MSCALE_X] < mScale || scale >= 1) { return new PointF(getWidth() / 2, getHeight() / 2); } float cx = getWidth() / 2; float cy = getHeight() / 2; if ((getWidth() / 2 - values[Matrix.MTRANS_X]) * scale < getWidth() / 2) cx = 0; if ((mImageWidth * values[Matrix.MSCALE_X] + values[Matrix.MTRANS_X]) * scale < getWidth()) cx = getWidth(); return new PointF(cx, cy); } private float checkMaxScale(float scale, float[] values) { if (scale * values[Matrix.MSCALE_X] > MAX_SCALE) scale = MAX_SCALE / values[Matrix.MSCALE_X]; return scale; } private void reSetMatrix() { if (checkRest()) { mCurrentMatrix.set(mMatrix); setImageMatrix(mCurrentMatrix); } else { float[] values = new float[9]; getImageMatrix().getValues(values); float height = mImageHeight * values[Matrix.MSCALE_Y]; if (height < getHeight()) { float topMargin = (getHeight() - height) / 2; if (topMargin != values[Matrix.MTRANS_Y]) { mCurrentMatrix.set(getImageMatrix()); mCurrentMatrix.postTranslate(0, topMargin - values[Matrix.MTRANS_Y]); setImageMatrix(mCurrentMatrix); } } } } private boolean checkRest() { float[] values = new float[9]; getImageMatrix().getValues(values); float scale = values[Matrix.MSCALE_X]; return scale < mScale; } private void isMatrixEnable() { if (getScaleType() != ScaleType.CENTER) { setScaleType(ScaleType.MATRIX); } else { mMode = MODE_UNABLE; } } private float distance(MotionEvent event) { float dx = event.getX(1) - event.getX(0); float dy = event.getY(1) - event.getY(0); return (float) Math.sqrt(dx * dx + dy * dy); } public void onDoubleClick() { float scale = isZoomChanged() ? 1 : DOUBLE_CLICK_SACLE; mCurrentMatrix.set(mMatrix); mCurrentMatrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2); setImageMatrix(mCurrentMatrix); } } private class GestureListener extends SimpleOnGestureListener { private final MatrixTouchListener mTouchListener; public GestureListener(MatrixTouchListener listener) { this.mTouchListener = listener; } @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onDoubleTap(MotionEvent e) { mTouchListener.onDoubleClick(); return true; } @Override public boolean onSingleTapUp(MotionEvent e) { return super.onSingleTapUp(e); } @Override public void onLongPress(MotionEvent e) { super.onLongPress(e); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return super.onScroll(e1, e2, distanceX, distanceY); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return super.onFling(e1, e2, velocityX, velocityY); } @Override public void onShowPress(MotionEvent e) { super.onShowPress(e); } @Override public boolean onDoubleTapEvent(MotionEvent e) { return super.onDoubleTapEvent(e); } @Override public boolean onSingleTapConfirmed(MotionEvent e) { if (mSingleTapListener != null) mSingleTapListener.onSingleTap(e); return super.onSingleTapConfirmed(e); } } public interface OnMovingListener { public void startDrag(); public void stopDrag(); } public interface OnSingleTapListener { public void onSingleTap(MotionEvent e); } }
我對其中定義OnSingleTapListener接口的方法稍作了一些修改,為onSingleTap回調方法增加了MotionEvent類型的參數,來方便我們根據用戶具體的事件內容作出對應的控制。
以上就是本文的全部內容,希望對大家學習Android軟件編程有所幫助。
Android 7.1.1 鎖屏界面啟動流程。前幾天遇到一個低概率復現鎖屏界面不顯示,只顯示狀態欄的問題,跟了下鎖屏界面啟動顯示的流程,在這分享下,也方便以後自己查看。前
今天隨便逛逛CSDN,看到主頁上推薦了一篇文章Android 快速開發系列 打造萬能的ListView GridView 適配器,剛好這兩天寫項目自己也封裝了類似的Com
Volley的核心結構如下所示:今天主要看Network相關:Network整體功能介紹:通過實現了Network接口的類(這裡是BasicNetwork),執行從Req
SQLite是Android系統內置的數據庫,是一種輕量級的關系型數據庫,它運算速度快,占用資源少,非常適合在移動設備上使用。同時,它不僅支持標准的SQL語法,還遵循了數