android UI——具有裁剪功能的imageview
阿新 • • 發佈:2019-02-16
從事android工作已經有半年了,積累了不少經驗,現在來部落格將一些自己的程式碼和知識整理下,也看能不能幫助下別人吧,自己也是一致靠著前輩們的努力一點一點積攢知識的。
這次我就來說下如何去實現一個裁剪圖片控制元件。正如很多程式中有的那樣,使用者可以通過操作一個檢視框對載入的圖片進行裁剪,而如何實現這樣的控制元件呢?
很簡單,實際上就是重寫一個ImageView類,然後在原有的view上繪製線條,並記錄矩形區域,標示需要裁剪的範圍。
之後通過canvas,將原bitmap繪製在指定的區域中,獲取到所需要的bitmap
程式碼比較簡單,如下所示。
public class CropImageView extends ImageView { private final static int PRESS_LEFT = 0x00; private final static int PRESS_UP = 0x01; private final static int PRESS_RIGHT = 0x02; private final static int PRESS_DOWN = 0x03; // 源影象 private Bitmap bitmap; Paint mPaint; // 變換矩陣 Matrix matrix; // 要裁剪的矩形區域 Rect mCurrentRect; // 上下左右四條邊的觸控區域 Rect[] rect = new Rect[4]; private final static int PADDING = 30; int min_width = 0; int max_width = 1280; int min_height = 0; int max_height = 800; //標識當前觸控的邊 int touch_edge; //上一次觸控的座標 Pos last_touch; public CropImageView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mCurrentRect = new Rect(); touch_edge = -1; } @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); int action = event.getAction(); Pos pos = new Pos(event.getX(), event.getY()); switch (action) { case MotionEvent.ACTION_DOWN: for (int i = 0; i < rect.length; i++) { if (rect[i].contains(pos.x, pos.y)) { touch_edge = i; break; } } break; case MotionEvent.ACTION_MOVE: // 移動幅度過小或者沒有觸到邊界則不進行修改 if (touch_edge == -1 || (pos.x == last_touch.x && pos.y == last_touch.y)) break; switch (touch_edge) { case PRESS_LEFT: mCurrentRect.left = Math.min( max_width, Math.max(min_width, mCurrentRect.left - last_touch.x + pos.x)); rect[touch_edge].left = mCurrentRect.left - PADDING; rect[touch_edge].right = mCurrentRect.left + PADDING; break; case PRESS_UP: mCurrentRect.top = Math.min( max_height, Math.max(min_height, mCurrentRect.top - last_touch.y + pos.y)); rect[touch_edge].top = mCurrentRect.top - PADDING; rect[touch_edge].bottom = mCurrentRect.top + PADDING; break; case PRESS_RIGHT: mCurrentRect.right = Math.min( max_width, Math.max(min_width, mCurrentRect.right - last_touch.x + pos.x)); rect[touch_edge].left = mCurrentRect.right - PADDING; rect[touch_edge].right = mCurrentRect.right + PADDING; break; case PRESS_DOWN: mCurrentRect.bottom = Math.min( max_height, Math.max(min_height, mCurrentRect.bottom - last_touch.y + pos.y)); rect[touch_edge].top = mCurrentRect.bottom - PADDING; rect[touch_edge].bottom = mCurrentRect.bottom + PADDING; break; } invalidate(); break; case MotionEvent.ACTION_UP: touch_edge = -1; break; } last_touch = pos; return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 繪製矩形區域 drawRect(canvas); } private void drawRect(Canvas canvas) { mPaint.setStyle(Style.STROKE); mPaint.setStrokeMiter(6); mPaint.setStrokeWidth(3); mPaint.setColor(Color.RED); canvas.drawRect(mCurrentRect, mPaint); } public Bitmap applyCrop() { return Bitmap.createBitmap(bitmap, mCurrentRect.left, mCurrentRect.top, mCurrentRect.right - mCurrentRect.left, mCurrentRect.bottom - mCurrentRect.top, matrix, false); } public void setBitmap(Bitmap pBitmap) { this.bitmap = pBitmap; this.setImageBitmap(bitmap); if (pBitmap == null) return; float scale = bitmap.getHeight() / (float) getHeight(); min_width = (int) (getWidth() - bitmap.getWidth() / scale) / 2; max_width = (int) (getWidth() + bitmap.getWidth() / scale) / 2; min_height = 0; max_height = getHeight(); mCurrentRect = new Rect(min_width + PADDING, min_height + PADDING, max_width - PADDING, max_height - PADDING); // 初始化四條邊的矩形區域,寬度為10 rect[PRESS_LEFT] = new Rect(mCurrentRect.left - PADDING, mCurrentRect.top, mCurrentRect.left + PADDING, mCurrentRect.bottom); rect[PRESS_UP] = new Rect(mCurrentRect.left, mCurrentRect.top - PADDING, mCurrentRect.right, mCurrentRect.top + PADDING); rect[PRESS_RIGHT] = new Rect(mCurrentRect.right - PADDING, mCurrentRect.top, mCurrentRect.right + PADDING, mCurrentRect.bottom); rect[PRESS_DOWN] = new Rect(mCurrentRect.left, mCurrentRect.bottom - PADDING, mCurrentRect.right, mCurrentRect.bottom + PADDING); } public String saveBitmap() { String path = null; float scale = bitmap.getHeight() / (float) getHeight(); Bitmap bmp = Bitmap.createScaledBitmap(bitmap, (int) (bitmap.getWidth() / scale), (int) (bitmap.getHeight() / scale), false); if (bmp != null && mCurrentRect != null) { Bitmap bmpDest = Bitmap .createBitmap(bmp, mCurrentRect.left - min_width, mCurrentRect.top, mCurrentRect.right - mCurrentRect.left, mCurrentRect.bottom - mCurrentRect.top); bmp = bmpDest; } // 將bmp儲存到臨時檔案 try { File folder = new File(IConstant.SAVE_PATH); if (!folder.exists()) folder.mkdir(); File tmpFile = File.createTempFile("result", ".jpg", folder); tmpFile.deleteOnExit(); FileOutputStream os = new FileOutputStream(tmpFile); bmp.compress(CompressFormat.JPEG, 100, os); os.close(); path = tmpFile.getAbsolutePath(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return path; } class Pos { public int x; public int y; public Pos(int px, int py) { this.x = px; this.y = py; } public Pos(float px, float py) { this((int) px, (int) py); } } }