首页 > 代码库 > Android图片裁剪——自定义裁剪工具
Android图片裁剪——自定义裁剪工具
上次弄完调用系统裁剪之后,我又试着做一个自定义的裁剪工具。
老习惯,文章开始前还是先把我参考的资料贴出来。您愿意节省点时间看别人的更好的就直接从下面链接跳走~愿意看看我怎么做的那就先谢谢了!
GitHub上老外做的一个非常棒的demo,代码也很漂亮
android自定义view实现裁剪图片功能,不使用系统的
第一个链接代码写的太好了,不过很多我用不上,也不需要那么麻烦的文件结构;第二个代码比较简单,但有些地方还是有借鉴意义的。
下面是我的代码,时间紧,就先不写太详细了:
注意几点:
我是在平板上做的测试,代码可能不适应手机,这个很好改..
我写这个是当作从外部传递一个绝对路径进来再做裁剪的,所以图省事儿就在设备里/sdcard/下放了一张图片,从mainActivity传进去..所以运行前自己先随便整个图片进去..或者自己改代码..
这个做起来不难.就是特麻烦.我也是粗略做做..UI什么的都没去搞..有空再弄吧..好歹也是个能用用的工具..
做好了会传到github上..到时候发链接..
activity_main.xml
1 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:id="@+id/scrollview" 4 android:layout_width="wrap_content" 5 android:layout_height="wrap_content" > 6 7 <LinearLayout 8 android:layout_width="match_parent" 9 android:layout_height="wrap_content"10 android:layout_marginLeft="30dp"11 android:layout_marginRight="30dp"12 android:orientation="vertical" >13 14 <Button15 android:id="@+id/btn_crop"16 android:layout_width="wrap_content"17 android:layout_height="wrap_content"18 android:text="Crop" />19 20 <Button21 android:id="@+id/btn_cancel"22 android:layout_width="wrap_content"23 android:layout_height="wrap_content"24 android:text="Cancel" />25 26 <com.example.crop_image_my.MyCropView27 android:id="@+id/myCropView"28 android:layout_width="900dp"29 android:layout_height="600dp"30 android:src="@drawable/violetsky" />31 32 <ImageView33 android:id="@+id/croppedImageView"34 android:layout_width="wrap_content"35 android:layout_height="wrap_content" />36 </LinearLayout>37 38 </ScrollView>
mainActivity.java
1 package com.example.crop_image_my; 2 3 import android.os.Bundle; 4 import android.app.Activity; 5 import android.graphics.Bitmap; 6 import android.view.Menu; 7 import android.view.MotionEvent; 8 import android.view.View; 9 import android.view.View.OnClickListener;10 import android.widget.Button;11 import android.widget.ImageView;12 import android.widget.ScrollView;13 14 public class MainActivity extends Activity implements OnClickListener {15 16 private MyCropView myCropView;17 private Button btnCrop;18 private Button btnCancel;19 private ImageView croppedImageView;20 private ScrollView sv;21 22 // 假设从图片选择器传递来的图片路径如下23 private static final String CROP_IMAGE_PATH = "/sdcard/crop.jpg";24 25 @Override26 protected void onCreate(Bundle savedInstanceState) {27 super.onCreate(savedInstanceState);28 setContentView(R.layout.activity_main);29 30 myCropView = (MyCropView) findViewById(R.id.myCropView);31 btnCrop = (Button) findViewById(R.id.btn_crop);32 btnCancel = (Button) findViewById(R.id.btn_cancel);33 croppedImageView = (ImageView) findViewById(R.id.croppedImageView);34 sv = (ScrollView) findViewById(R.id.scrollview);35 36 myCropView.setBmpPath(CROP_IMAGE_PATH);37 btnCrop.setOnClickListener(this);38 btnCancel.setOnClickListener(this);39 40 sv.setOnTouchListener(new View.OnTouchListener() {41 42 @Override43 public boolean onTouch(View v, MotionEvent event) {44 // TODO Auto-generated method stub45 myCropView.getParent().requestDisallowInterceptTouchEvent(false);46 return false;47 }48 });49 }50 51 @Override52 public void onClick(View v) {53 // TODO Auto-generated method stub54 switch (v.getId()) {55 case R.id.btn_crop:56 Bitmap croppedImage = myCropView.getCroppedImage();57 58 croppedImageView.setImageBitmap(croppedImage);59 break;60 case R.id.btn_cancel:61 62 break;63 default:64 break;65 }66 }67 68 @Override69 public boolean onCreateOptionsMenu(Menu menu) {70 // Inflate the menu; this adds items to the action bar if it is present.71 getMenuInflater().inflate(R.menu.activity_main, menu);72 return true;73 }74 75 }
MyCropView.java
1 package com.example.crop_image_my; 2 3 import android.content.Context; 4 import android.drm.DrmStore.RightsStatus; 5 import android.graphics.Bitmap; 6 import android.graphics.BitmapFactory; 7 import android.graphics.Canvas; 8 import android.graphics.Color; 9 import android.graphics.Paint; 10 import android.graphics.Paint.Style; 11 import android.graphics.PointF; 12 import android.graphics.RectF; 13 import android.util.AttributeSet; 14 import android.view.MotionEvent; 15 import android.view.View; 16 import android.widget.Toast; 17 18 public class MyCropView extends View { 19 20 // Private Constants /////////////////////////////////////////////////////// 21 private static final float BMP_LEFT = 0f; 22 private static final float BMP_TOP = 20f; 23 24 private static final float DEFAULT_BORDER_RECT_WIDTH = 200f; 25 private static final float DEFAULT_BORDER_RECT_HEIGHT = 200f; 26 27 private static final int POS_TOP_LEFT = 0; 28 private static final int POS_TOP_RIGHT = 1; 29 private static final int POS_BOTTOM_LEFT = 2; 30 private static final int POS_BOTTOM_RIGHT = 3; 31 private static final int POS_TOP = 4; 32 private static final int POS_BOTTOM = 5; 33 private static final int POS_LEFT = 6; 34 private static final int POS_RIGHT = 7; 35 private static final int POS_CENTER = 8; 36 37 // this constant would be best to use event number 38 private static final float BORDER_LINE_WIDTH = 6f; 39 private static final float BORDER_CORNER_LENGTH = 30f; 40 private static final float TOUCH_FIELD = 10f; 41 42 // Member Variables //////////////////////////////////////////////////////// 43 private String mBmpPath; 44 private Bitmap mBmpToCrop; 45 private RectF mBmpBound; 46 private Paint mBmpPaint; 47 48 private Paint mBorderPaint;// 裁剪区边框 49 private Paint mGuidelinePaint; 50 private Paint mCornerPaint; 51 private Paint mBgPaint; 52 53 private RectF mDefaultBorderBound; 54 private RectF mBorderBound; 55 56 private PointF mLastPoint = new PointF(); 57 58 private float mBorderWidth; 59 private float mBorderHeight; 60 61 private int touchPos; 62 63 // Constructors //////////////////////////////////////////////////////////// 64 public MyCropView(Context context) { 65 super(context); 66 // TODO Auto-generated constructor stub 67 init(context); 68 } 69 70 public MyCropView(Context context, AttributeSet attrs) { 71 super(context, attrs); 72 init(context); 73 } 74 75 // View Methods //////////////////////////////////////////////////////////// 76 @Override 77 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 78 // TODO Auto-generated method stub 79 // super.onSizeChanged(w, h, oldw, oldh); 80 } 81 82 @Override 83 protected void onDraw(Canvas canvas) { 84 // TODO Auto-generated method stub 85 // super.onDraw(canvas); 86 if (mBmpPath != null) { 87 canvas.drawBitmap(mBmpToCrop, null, mBmpBound, mBmpPaint); 88 canvas.drawRect(mBorderBound.left, mBorderBound.top, mBorderBound.right, mBorderBound.bottom, mBorderPaint); 89 drawGuidlines(canvas); 90 drawBackground(canvas); 91 } 92 } 93 94 @Override 95 public boolean onTouchEvent(MotionEvent event) { 96 // TODO Auto-generated method stub 97 // super.onTouchEvent(event); 98 switch (event.getAction()) { 99 case MotionEvent.ACTION_DOWN:100 setLastPosition(event);101 getParent().requestDisallowInterceptTouchEvent(true);102 // onActionDown(event.getX(), event.getY());103 touchPos = detectTouchPosition(event.getX(), event.getY());104 break;105 case MotionEvent.ACTION_MOVE:106 onActionMove(event.getX(), event.getY());107 setLastPosition(event);108 break;109 case MotionEvent.ACTION_UP:110 break;111 }112 113 return true;114 }115 116 // Public Methods //////////////////////////////////////////////////////////117 public String getBmpPath() {118 return mBmpPath;119 }120 121 public void setBmpPath(String picPath) {122 this.mBmpPath = picPath;123 setBmp();124 }125 126 public Bitmap getCroppedImage() {127 // 先不考虑图片被压缩的情况 就当作现在的图片就是1:1的128 129 return Bitmap.createBitmap(mBmpToCrop, (int) mBorderBound.left, (int) mBorderBound.top, (int) mBorderWidth,130 (int) mBorderHeight);131 }132 133 // Private Methods /////////////////////////////////////////////////////////134 private void init(Context context) {135 136 mBmpPaint = new Paint();137 // 以下是抗锯齿138 mBmpPaint.setAntiAlias(true);// 防止边缘的锯齿139 mBmpPaint.setFilterBitmap(true);// 对位图进行滤波处理140 141 mBorderPaint = new Paint();142 mBorderPaint.setStyle(Style.STROKE);143 mBorderPaint.setColor(Color.parseColor("#AAFFFFFF"));144 mBorderPaint.setStrokeWidth(BORDER_LINE_WIDTH);145 146 mGuidelinePaint = new Paint();147 mGuidelinePaint.setColor(Color.parseColor("#AAFFFFFF"));148 mGuidelinePaint.setStrokeWidth(1f);149 150 mCornerPaint = new Paint();151 152 mBgPaint = new Paint();153 mBgPaint.setColor(Color.parseColor("#B0000000"));154 mBgPaint.setAlpha(150);155 156 }157 158 private void setBmp() {159 mBmpToCrop = BitmapFactory.decodeFile(mBmpPath);160 161 mBmpBound = new RectF();162 mBmpBound.left = BMP_LEFT;163 mBmpBound.top = BMP_TOP;164 mBmpBound.right = mBmpBound.left + mBmpToCrop.getWidth();165 mBmpBound.bottom = mBmpBound.top + mBmpToCrop.getHeight();166 167 // 使裁剪框一开始出现在图片的中心位置168 mDefaultBorderBound = new RectF();169 mDefaultBorderBound.left = (mBmpBound.left + mBmpBound.right - DEFAULT_BORDER_RECT_WIDTH) / 2;170 mDefaultBorderBound.top = (mBmpBound.top + mBmpBound.bottom - DEFAULT_BORDER_RECT_HEIGHT) / 2;171 mDefaultBorderBound.right = mDefaultBorderBound.left + DEFAULT_BORDER_RECT_WIDTH;172 mDefaultBorderBound.bottom = mDefaultBorderBound.top + DEFAULT_BORDER_RECT_HEIGHT;173 174 mBorderBound = new RectF();175 mBorderBound.left = mDefaultBorderBound.left;176 mBorderBound.top = mDefaultBorderBound.top;177 mBorderBound.right = mDefaultBorderBound.right;178 mBorderBound.bottom = mDefaultBorderBound.bottom;179 180 getBorderEdgeLength();181 invalidate();182 }183 184 private void drawBackground(Canvas canvas) {185 186 /*-187 -------------------------------------188 | top |189 -------------------------------------190 | | | |<——————————mBmpBound191 | | | |192 | left | | right |193 | | | |194 | | <─┼───────┼────mBorderBound195 -------------------------------------196 | bottom |197 -------------------------------------198 */199 200 // Draw "top", "bottom", "left", then "right" quadrants.201 // because the border line width is larger than 1f, in order to draw a complete border rect ,202 // i have to change zhe rect coordinate to draw203 float delta = BORDER_LINE_WIDTH / 2;204 float left = mBorderBound.left - delta;205 float top = mBorderBound.top - delta;206 float right = mBorderBound.right + delta;207 float bottom = mBorderBound.bottom + delta;208 209 // -------------------------------------------------------------------------------移动到上下两端会多出来阴影210 canvas.drawRect(mBmpBound.left, mBmpBound.top, mBmpBound.right, top, mBgPaint);211 canvas.drawRect(mBmpBound.left, bottom, mBmpBound.right, mBmpBound.bottom, mBgPaint);212 canvas.drawRect(mBmpBound.left, top, left, bottom, mBgPaint);213 canvas.drawRect(right, top, mBmpBound.right, bottom, mBgPaint);214 }215 216 // 画裁剪区域中间的参考线217 private void drawGuidlines(Canvas canvas) {218 // Draw vertical guidelines.219 final float oneThirdCropWidth = mBorderBound.width() / 3;220 221 final float x1 = mBorderBound.left + oneThirdCropWidth;222 canvas.drawLine(x1, mBorderBound.top, x1, mBorderBound.bottom, mGuidelinePaint);223 final float x2 = mBorderBound.right - oneThirdCropWidth;224 canvas.drawLine(x2, mBorderBound.top, x2, mBorderBound.bottom, mGuidelinePaint);225 226 // Draw horizontal guidelines.227 final float oneThirdCropHeight = mBorderBound.height() / 3;228 229 final float y1 = mBorderBound.top + oneThirdCropHeight;230 canvas.drawLine(mBorderBound.left, y1, mBorderBound.right, y1, mGuidelinePaint);231 final float y2 = mBorderBound.bottom - oneThirdCropHeight;232 canvas.drawLine(mBorderBound.left, y2, mBorderBound.right, y2, mGuidelinePaint);233 }234 235 private void onActionDown(float x, float y) {236 237 }238 239 private void onActionMove(float x, float y) {240 float deltaX = x - mLastPoint.x;241 float deltaY = y - mLastPoint.y;242 // 这里先不考虑裁剪框放最大的情况243 switch (touchPos) {244 case POS_CENTER:245 mBorderBound.left += deltaX;246 // fix border position247 if (mBorderBound.left < mBmpBound.left)248 mBorderBound.left = mBmpBound.left;249 if (mBorderBound.left > mBmpBound.right - mBorderWidth)250 mBorderBound.left = mBmpBound.right - mBorderWidth;251 252 mBorderBound.top += deltaY;253 if (mBorderBound.top < mBmpBound.top)254 mBorderBound.top = mBmpBound.top;255 256 if (mBorderBound.top > mBmpBound.bottom - mBorderHeight)257 mBorderBound.top = mBmpBound.bottom - mBorderHeight;258 259 mBorderBound.right = mBorderBound.left + mBorderWidth;260 mBorderBound.bottom = mBorderBound.top + mBorderHeight;261 262 break;263 264 case POS_TOP:265 resetTop(deltaY);266 break;267 case POS_BOTTOM:268 resetBottom(deltaY);269 break;270 case POS_LEFT:271 resetLeft(deltaX);272 break;273 case POS_RIGHT:274 resetRight(deltaX);275 break;276 case POS_TOP_LEFT:277 resetTop(deltaY);278 resetLeft(deltaX);279 break;280 case POS_TOP_RIGHT:281 resetTop(deltaY);282 resetRight(deltaX);283 break;284 case POS_BOTTOM_LEFT:285 resetBottom(deltaY);286 resetLeft(deltaX);287 break;288 case POS_BOTTOM_RIGHT:289 resetBottom(deltaY);290 resetRight(deltaX);291 break;292 default:293 294 break;295 }296 invalidate();297 }298 299 private void onActionUp(float x, float y) {300 301 }302 303 private int detectTouchPosition(float x, float y) {304 if (x > mBorderBound.left + TOUCH_FIELD && x < mBorderBound.right - TOUCH_FIELD305 && y > mBorderBound.top + TOUCH_FIELD && y < mBorderBound.bottom - TOUCH_FIELD)306 return POS_CENTER;307 308 if (x > mBorderBound.left + BORDER_CORNER_LENGTH && x < mBorderBound.right - BORDER_CORNER_LENGTH) {309 if (y > mBorderBound.top - TOUCH_FIELD && y < mBorderBound.top + TOUCH_FIELD)310 return POS_TOP;311 if (y > mBorderBound.bottom - TOUCH_FIELD && y < mBorderBound.bottom + TOUCH_FIELD)312 return POS_BOTTOM;313 }314 315 if (y > mBorderBound.top + BORDER_CORNER_LENGTH && y < mBorderBound.bottom - BORDER_CORNER_LENGTH) {316 if (x > mBorderBound.left - TOUCH_FIELD && x < mBorderBound.left + TOUCH_FIELD)317 return POS_LEFT;318 if (x > mBorderBound.right - TOUCH_FIELD && x < mBorderBound.right + TOUCH_FIELD)319 return POS_RIGHT;320 }321 322 // 前面的逻辑已经排除掉了几种情况 所以后面的 ┏ ┓ ┗ ┛ 边角就按照所占区域的方形来判断就可以了323 if (x > mBorderBound.left - TOUCH_FIELD && x < mBorderBound.left + BORDER_CORNER_LENGTH) {324 if (y > mBorderBound.top - TOUCH_FIELD && y < mBorderBound.top + BORDER_CORNER_LENGTH)325 return POS_TOP_LEFT;326 if (y > mBorderBound.bottom - BORDER_CORNER_LENGTH && y < mBorderBound.bottom + TOUCH_FIELD)327 return POS_BOTTOM_LEFT;328 }329 330 if (x > mBorderBound.right - BORDER_CORNER_LENGTH && x < mBorderBound.right + TOUCH_FIELD) {331 if (y > mBorderBound.top - TOUCH_FIELD && y < mBorderBound.top + BORDER_CORNER_LENGTH)332 return POS_TOP_RIGHT;333 if (y > mBorderBound.bottom - BORDER_CORNER_LENGTH && y < mBorderBound.bottom + TOUCH_FIELD)334 return POS_BOTTOM_RIGHT;335 }336 337 return -1;338 }339 340 private void setLastPosition(MotionEvent event) {341 mLastPoint.x = event.getX();342 mLastPoint.y = event.getY();343 }344 345 private void getBorderEdgeLength() {346 mBorderWidth = mBorderBound.width();347 mBorderHeight = mBorderBound.height();348 }349 350 private void getBorderEdgeWidth() {351 mBorderWidth = mBorderBound.width();352 }353 354 private void getBorderEdgeHeight() {355 mBorderHeight = mBorderBound.height();356 }357 358 private void resetLeft(float delta) {359 mBorderBound.left += delta;360 361 getBorderEdgeWidth();362 fixBorderLeft();363 }364 365 private void resetTop(float delta) {366 mBorderBound.top += delta;367 getBorderEdgeHeight();368 fixBorderTop();369 }370 371 private void resetRight(float delta) {372 mBorderBound.right += delta;373 374 getBorderEdgeWidth();375 fixBorderRight();376 377 }378 379 private void resetBottom(float delta) {380 mBorderBound.bottom += delta;381 382 getBorderEdgeHeight();383 fixBorderBottom();384 }385 386 private void fixBorderLeft() {387 // fix left388 if (mBorderBound.left < mBmpBound.left)389 mBorderBound.left = mBmpBound.left;390 if (mBorderWidth < 2 * BORDER_CORNER_LENGTH)391 mBorderBound.left = mBorderBound.right - 2 * BORDER_CORNER_LENGTH;392 }393 394 private void fixBorderTop() {395 // fix top396 if (mBorderBound.top < mBmpBound.top)397 mBorderBound.top = mBmpBound.top;398 if (mBorderHeight < 2 * BORDER_CORNER_LENGTH)399 mBorderBound.top = mBorderBound.bottom - 2 * BORDER_CORNER_LENGTH;400 }401 402 private void fixBorderRight() {403 // fix right404 if (mBorderBound.right > mBmpBound.right)405 mBorderBound.right = mBmpBound.right;406 if (mBorderWidth < 2 * BORDER_CORNER_LENGTH)407 mBorderBound.right = mBorderBound.left + 2 * BORDER_CORNER_LENGTH;408 }409 410 private void fixBorderBottom() {411 // fix bottom412 if (mBorderBound.bottom > mBmpBound.bottom)413 mBorderBound.bottom = mBmpBound.bottom;414 if (mBorderHeight < 2 * BORDER_CORNER_LENGTH)415 mBorderBound.bottom = mBorderBound.top + 2 * BORDER_CORNER_LENGTH;416 }417 }
Android图片裁剪——自定义裁剪工具
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。