上次弄完调用系统裁剪之后,我又试着做一个自定义的裁剪工具。

原文地址请保留http://www.cnblogs.com/rossoneri/p/3988405.html

老习惯,文章开始前还是先把我参考的资料贴出来。您愿意节省点时间看别人的更好的就直接从下面链接跳走~愿意看看我怎么做的那就先谢谢了!

GitHub上老外做的一个非常棒的demo,代码也很漂亮

android自定义view实现裁剪图片功能,不使用系统的

第一个链接代码写的太好了,不过很多我用不上,也不需要那么麻烦的文件结构;第二个代码比较简单,但有些地方还是有借鉴意义的。

下面是我的代码,时间紧,就先不写太详细了:

注意几点:

我是在平板上做的测试,代码可能不适应手机,这个很好改..

我写这个是当作从外部传递一个绝对路径进来再做裁剪的,所以图省事儿就在设备里/sdcard/下放了一张图片,从mainActivity传进去..所以运行前自己先随便整个图片进去..或者自己改代码..

这个做起来不难.就是特麻烦.我也是粗略做做..UI什么的都没去搞..有空再弄吧..好歹也是个能用用的工具..

做好了会传到github上..到时候发链接..

activity_main.xml

 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/scrollview"
android:layout_width="wrap_content"
android:layout_height="wrap_content" > <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:orientation="vertical" > <Button
android:id="@+id/btn_crop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Crop" /> <Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel" /> <com.example.crop_image_my.MyCropView
android:id="@+id/myCropView"
android:layout_width="900dp"
android:layout_height="600dp"
android:src="@drawable/violetsky" /> <ImageView
android:id="@+id/croppedImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout> </ScrollView>

mainActivity.java

 package com.example.crop_image_my;

 import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ScrollView; public class MainActivity extends Activity implements OnClickListener { private MyCropView myCropView;
private Button btnCrop;
private Button btnCancel;
private ImageView croppedImageView;
private ScrollView sv; // 假设从图片选择器传递来的图片路径如下
private static final String CROP_IMAGE_PATH = "/sdcard/crop.jpg"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); myCropView = (MyCropView) findViewById(R.id.myCropView);
btnCrop = (Button) findViewById(R.id.btn_crop);
btnCancel = (Button) findViewById(R.id.btn_cancel);
croppedImageView = (ImageView) findViewById(R.id.croppedImageView);
sv = (ScrollView) findViewById(R.id.scrollview); myCropView.setBmpPath(CROP_IMAGE_PATH);
btnCrop.setOnClickListener(this);
btnCancel.setOnClickListener(this); sv.setOnTouchListener(new View.OnTouchListener() { @Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
myCropView.getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
});
} @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.btn_crop:
Bitmap croppedImage = myCropView.getCroppedImage(); croppedImageView.setImageBitmap(croppedImage);
break;
case R.id.btn_cancel: break;
default:
break;
}
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
} }

MyCropView.java

 package com.example.crop_image_my;

 import android.content.Context;
import android.drm.DrmStore.RightsStatus;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast; public class MyCropView extends View { // Private Constants ///////////////////////////////////////////////////////
private static final float BMP_LEFT = 0f;
private static final float BMP_TOP = 20f; private static final float DEFAULT_BORDER_RECT_WIDTH = 200f;
private static final float DEFAULT_BORDER_RECT_HEIGHT = 200f; private static final int POS_TOP_LEFT = 0;
private static final int POS_TOP_RIGHT = 1;
private static final int POS_BOTTOM_LEFT = 2;
private static final int POS_BOTTOM_RIGHT = 3;
private static final int POS_TOP = 4;
private static final int POS_BOTTOM = 5;
private static final int POS_LEFT = 6;
private static final int POS_RIGHT = 7;
private static final int POS_CENTER = 8; // this constant would be best to use event number
private static final float BORDER_LINE_WIDTH = 6f;
private static final float BORDER_CORNER_LENGTH = 30f;
private static final float TOUCH_FIELD = 10f; // Member Variables ////////////////////////////////////////////////////////
private String mBmpPath;
private Bitmap mBmpToCrop;
private RectF mBmpBound;
private Paint mBmpPaint; private Paint mBorderPaint;// 裁剪区边框
private Paint mGuidelinePaint;
private Paint mCornerPaint;
private Paint mBgPaint; private RectF mDefaultBorderBound;
private RectF mBorderBound; private PointF mLastPoint = new PointF(); private float mBorderWidth;
private float mBorderHeight; private int touchPos; // Constructors ////////////////////////////////////////////////////////////
public MyCropView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init(context);
} public MyCropView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
} // View Methods ////////////////////////////////////////////////////////////
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// TODO Auto-generated method stub
// super.onSizeChanged(w, h, oldw, oldh);
} @Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
// super.onDraw(canvas);
if (mBmpPath != null) {
canvas.drawBitmap(mBmpToCrop, null, mBmpBound, mBmpPaint);
canvas.drawRect(mBorderBound.left, mBorderBound.top, mBorderBound.right, mBorderBound.bottom, mBorderPaint);
drawGuidlines(canvas);
drawBackground(canvas);
}
} @Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
// super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setLastPosition(event);
getParent().requestDisallowInterceptTouchEvent(true);
// onActionDown(event.getX(), event.getY());
touchPos = detectTouchPosition(event.getX(), event.getY());
break;
case MotionEvent.ACTION_MOVE:
onActionMove(event.getX(), event.getY());
setLastPosition(event);
break;
case MotionEvent.ACTION_UP:
break;
} return true;
} // Public Methods //////////////////////////////////////////////////////////
public String getBmpPath() {
return mBmpPath;
} public void setBmpPath(String picPath) {
this.mBmpPath = picPath;
setBmp();
} public Bitmap getCroppedImage() {
// 先不考虑图片被压缩的情况 就当作现在的图片就是1:1的 return Bitmap.createBitmap(mBmpToCrop, (int) mBorderBound.left, (int) mBorderBound.top, (int) mBorderWidth,
(int) mBorderHeight);
} // Private Methods /////////////////////////////////////////////////////////
private void init(Context context) { mBmpPaint = new Paint();
// 以下是抗锯齿
mBmpPaint.setAntiAlias(true);// 防止边缘的锯齿
mBmpPaint.setFilterBitmap(true);// 对位图进行滤波处理 mBorderPaint = new Paint();
mBorderPaint.setStyle(Style.STROKE);
mBorderPaint.setColor(Color.parseColor("#AAFFFFFF"));
mBorderPaint.setStrokeWidth(BORDER_LINE_WIDTH); mGuidelinePaint = new Paint();
mGuidelinePaint.setColor(Color.parseColor("#AAFFFFFF"));
mGuidelinePaint.setStrokeWidth(1f); mCornerPaint = new Paint(); mBgPaint = new Paint();
mBgPaint.setColor(Color.parseColor("#B0000000"));
mBgPaint.setAlpha(150); } private void setBmp() {
mBmpToCrop = BitmapFactory.decodeFile(mBmpPath); mBmpBound = new RectF();
mBmpBound.left = BMP_LEFT;
mBmpBound.top = BMP_TOP;
mBmpBound.right = mBmpBound.left + mBmpToCrop.getWidth();
mBmpBound.bottom = mBmpBound.top + mBmpToCrop.getHeight(); // 使裁剪框一开始出现在图片的中心位置
mDefaultBorderBound = new RectF();
mDefaultBorderBound.left = (mBmpBound.left + mBmpBound.right - DEFAULT_BORDER_RECT_WIDTH) / 2;
mDefaultBorderBound.top = (mBmpBound.top + mBmpBound.bottom - DEFAULT_BORDER_RECT_HEIGHT) / 2;
mDefaultBorderBound.right = mDefaultBorderBound.left + DEFAULT_BORDER_RECT_WIDTH;
mDefaultBorderBound.bottom = mDefaultBorderBound.top + DEFAULT_BORDER_RECT_HEIGHT; mBorderBound = new RectF();
mBorderBound.left = mDefaultBorderBound.left;
mBorderBound.top = mDefaultBorderBound.top;
mBorderBound.right = mDefaultBorderBound.right;
mBorderBound.bottom = mDefaultBorderBound.bottom; getBorderEdgeLength();
invalidate();
} private void drawBackground(Canvas canvas) { /*-
-------------------------------------
| top |
-------------------------------------
| | | |<——————————mBmpBound
| | | |
| left | | right |
| | | |
| | <─┼───────┼────mBorderBound
-------------------------------------
| bottom |
-------------------------------------
*/ // Draw "top", "bottom", "left", then "right" quadrants.
// because the border line width is larger than 1f, in order to draw a complete border rect ,
// i have to change zhe rect coordinate to draw
float delta = BORDER_LINE_WIDTH / 2;
float left = mBorderBound.left - delta;
float top = mBorderBound.top - delta;
float right = mBorderBound.right + delta;
float bottom = mBorderBound.bottom + delta; // -------------------------------------------------------------------------------移动到上下两端会多出来阴影
canvas.drawRect(mBmpBound.left, mBmpBound.top, mBmpBound.right, top, mBgPaint);
canvas.drawRect(mBmpBound.left, bottom, mBmpBound.right, mBmpBound.bottom, mBgPaint);
canvas.drawRect(mBmpBound.left, top, left, bottom, mBgPaint);
canvas.drawRect(right, top, mBmpBound.right, bottom, mBgPaint);
} // 画裁剪区域中间的参考线
private void drawGuidlines(Canvas canvas) {
// Draw vertical guidelines.
final float oneThirdCropWidth = mBorderBound.width() / 3; final float x1 = mBorderBound.left + oneThirdCropWidth;
canvas.drawLine(x1, mBorderBound.top, x1, mBorderBound.bottom, mGuidelinePaint);
final float x2 = mBorderBound.right - oneThirdCropWidth;
canvas.drawLine(x2, mBorderBound.top, x2, mBorderBound.bottom, mGuidelinePaint); // Draw horizontal guidelines.
final float oneThirdCropHeight = mBorderBound.height() / 3; final float y1 = mBorderBound.top + oneThirdCropHeight;
canvas.drawLine(mBorderBound.left, y1, mBorderBound.right, y1, mGuidelinePaint);
final float y2 = mBorderBound.bottom - oneThirdCropHeight;
canvas.drawLine(mBorderBound.left, y2, mBorderBound.right, y2, mGuidelinePaint);
} private void onActionDown(float x, float y) { } private void onActionMove(float x, float y) {
float deltaX = x - mLastPoint.x;
float deltaY = y - mLastPoint.y;
// 这里先不考虑裁剪框放最大的情况
switch (touchPos) {
case POS_CENTER:
mBorderBound.left += deltaX;
// fix border position
if (mBorderBound.left < mBmpBound.left)
mBorderBound.left = mBmpBound.left;
if (mBorderBound.left > mBmpBound.right - mBorderWidth)
mBorderBound.left = mBmpBound.right - mBorderWidth; mBorderBound.top += deltaY;
if (mBorderBound.top < mBmpBound.top)
mBorderBound.top = mBmpBound.top; if (mBorderBound.top > mBmpBound.bottom - mBorderHeight)
mBorderBound.top = mBmpBound.bottom - mBorderHeight; mBorderBound.right = mBorderBound.left + mBorderWidth;
mBorderBound.bottom = mBorderBound.top + mBorderHeight; break; case POS_TOP:
resetTop(deltaY);
break;
case POS_BOTTOM:
resetBottom(deltaY);
break;
case POS_LEFT:
resetLeft(deltaX);
break;
case POS_RIGHT:
resetRight(deltaX);
break;
case POS_TOP_LEFT:
resetTop(deltaY);
resetLeft(deltaX);
break;
case POS_TOP_RIGHT:
resetTop(deltaY);
resetRight(deltaX);
break;
case POS_BOTTOM_LEFT:
resetBottom(deltaY);
resetLeft(deltaX);
break;
case POS_BOTTOM_RIGHT:
resetBottom(deltaY);
resetRight(deltaX);
break;
default: break;
}
invalidate();
} private void onActionUp(float x, float y) { } private int detectTouchPosition(float x, float y) {
if (x > mBorderBound.left + TOUCH_FIELD && x < mBorderBound.right - TOUCH_FIELD
&& y > mBorderBound.top + TOUCH_FIELD && y < mBorderBound.bottom - TOUCH_FIELD)
return POS_CENTER; if (x > mBorderBound.left + BORDER_CORNER_LENGTH && x < mBorderBound.right - BORDER_CORNER_LENGTH) {
if (y > mBorderBound.top - TOUCH_FIELD && y < mBorderBound.top + TOUCH_FIELD)
return POS_TOP;
if (y > mBorderBound.bottom - TOUCH_FIELD && y < mBorderBound.bottom + TOUCH_FIELD)
return POS_BOTTOM;
} if (y > mBorderBound.top + BORDER_CORNER_LENGTH && y < mBorderBound.bottom - BORDER_CORNER_LENGTH) {
if (x > mBorderBound.left - TOUCH_FIELD && x < mBorderBound.left + TOUCH_FIELD)
return POS_LEFT;
if (x > mBorderBound.right - TOUCH_FIELD && x < mBorderBound.right + TOUCH_FIELD)
return POS_RIGHT;
} // 前面的逻辑已经排除掉了几种情况 所以后面的 ┏ ┓ ┗ ┛ 边角就按照所占区域的方形来判断就可以了
if (x > mBorderBound.left - TOUCH_FIELD && x < mBorderBound.left + BORDER_CORNER_LENGTH) {
if (y > mBorderBound.top - TOUCH_FIELD && y < mBorderBound.top + BORDER_CORNER_LENGTH)
return POS_TOP_LEFT;
if (y > mBorderBound.bottom - BORDER_CORNER_LENGTH && y < mBorderBound.bottom + TOUCH_FIELD)
return POS_BOTTOM_LEFT;
} if (x > mBorderBound.right - BORDER_CORNER_LENGTH && x < mBorderBound.right + TOUCH_FIELD) {
if (y > mBorderBound.top - TOUCH_FIELD && y < mBorderBound.top + BORDER_CORNER_LENGTH)
return POS_TOP_RIGHT;
if (y > mBorderBound.bottom - BORDER_CORNER_LENGTH && y < mBorderBound.bottom + TOUCH_FIELD)
return POS_BOTTOM_RIGHT;
} return -1;
} private void setLastPosition(MotionEvent event) {
mLastPoint.x = event.getX();
mLastPoint.y = event.getY();
} private void getBorderEdgeLength() {
mBorderWidth = mBorderBound.width();
mBorderHeight = mBorderBound.height();
} private void getBorderEdgeWidth() {
mBorderWidth = mBorderBound.width();
} private void getBorderEdgeHeight() {
mBorderHeight = mBorderBound.height();
} private void resetLeft(float delta) {
mBorderBound.left += delta; getBorderEdgeWidth();
fixBorderLeft();
} private void resetTop(float delta) {
mBorderBound.top += delta;
getBorderEdgeHeight();
fixBorderTop();
} private void resetRight(float delta) {
mBorderBound.right += delta; getBorderEdgeWidth();
fixBorderRight(); } private void resetBottom(float delta) {
mBorderBound.bottom += delta; getBorderEdgeHeight();
fixBorderBottom();
} private void fixBorderLeft() {
// fix left
if (mBorderBound.left < mBmpBound.left)
mBorderBound.left = mBmpBound.left;
if (mBorderWidth < 2 * BORDER_CORNER_LENGTH)
mBorderBound.left = mBorderBound.right - 2 * BORDER_CORNER_LENGTH;
} private void fixBorderTop() {
// fix top
if (mBorderBound.top < mBmpBound.top)
mBorderBound.top = mBmpBound.top;
if (mBorderHeight < 2 * BORDER_CORNER_LENGTH)
mBorderBound.top = mBorderBound.bottom - 2 * BORDER_CORNER_LENGTH;
} private void fixBorderRight() {
// fix right
if (mBorderBound.right > mBmpBound.right)
mBorderBound.right = mBmpBound.right;
if (mBorderWidth < 2 * BORDER_CORNER_LENGTH)
mBorderBound.right = mBorderBound.left + 2 * BORDER_CORNER_LENGTH;
} private void fixBorderBottom() {
// fix bottom
if (mBorderBound.bottom > mBmpBound.bottom)
mBorderBound.bottom = mBmpBound.bottom;
if (mBorderHeight < 2 * BORDER_CORNER_LENGTH)
mBorderBound.bottom = mBorderBound.top + 2 * BORDER_CORNER_LENGTH;
}
}

补两张截图先:

界面神丑,无所谓啦,功能是有了  代码其实很简单了,一看就懂,但是有一些知识点,比如说下面这两段:

 sv.setOnTouchListener(new View.OnTouchListener() {

             @Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
myCropView.getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
});
 case MotionEvent.ACTION_DOWN:
setLastPosition(event);
getParent().requestDisallowInterceptTouchEvent(true);

这个代码就是为了让  移动或变化裁剪窗口  和  scrollview不冲突

具体内容会在后面更新博客~~  文章入口   (其实想写好多东西。。就是没空。。慢慢来)

[Android] 图片裁剪总结——自定义裁剪工具的更多相关文章

  1. [Android] 图片裁剪总结——调用系统裁剪

    花了两天时间看了下android的图片裁剪功能的实现.其实刚开始做这个我挺虚的,以为整个功能都需要自己写出来,但查了些资料,发现android已经提供了裁剪功能,需要的话自己调用就成了.soga,这下 ...

  2. Android 图片裁剪库 uCrop

    引语 晚上好,我是猫咪,我的公众号「程序媛猫咪」会推荐 GitHub 上好玩的项目,挖掘开源的价值,欢迎关注我. 现在 Android 开发,离不开图片,必然也需要图片裁剪功能,这个实现可以调用系统的 ...

  3. Android 图片裁剪踩坑

      今天做图库图片的裁剪遇到了不少坑,今天记录一下,以下坑位供各位看官参考: 如果有不对之处,欢迎各位看官留言评论! 图片裁剪踩坑锦囊: 问题一:相册裁剪权限问题 解:这个简单,对于Android6. ...

  4. Android图片裁剪之自由裁剪

    我的博客http://blog.csdn.net/dawn_moon 客户的需求都是非常怪的.我有时候在给客户做项目的时候就想骂客户是sb.可是请你相信我,等你有需求,自己变成客户的时候,给你做项目的 ...

  5. Android图片裁剪解决方案 -- 从相册截图

    在看Storage Access Framework,里面有一个加载相册图片的程序片断,可能是系统版本的问题,无法返回结果,这里找到一个适用于旧版本的方法. 在Android开发中,可以轻松调用一个I ...

  6. android调用系统的自定义裁剪后得到的图片不清晰,使用MediaStore.EXTRA_OUTPUT获取缓存下的清晰图片

    在使用系统自带的剪切图片工具时,通常只能设置一些比较小的值,像 intent.putExtra("outputX", 320); intent.putExtra("out ...

  7. Android实现图片裁剪

    MainActivity.java package com.kale.imagetailor; import java.io.File; import java.io.FileNotFoundExce ...

  8. Android 图片的裁剪与相机调用

    有时候我们需要的图片并不适合我们想要的大小, 那么我们就可以用到系统自带的图片裁剪功能, 把规定范围的图像给剪出来. 贴上部分代码: //调用图库 Intent intent = new Intent ...

  9. Android大图片裁剪终极解决方案(上:原理分析)

    转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-)  http://my.oschina.net/ryanhoo/blog/86842 约几个月前,我正 ...

随机推荐

  1. HuLu机器学习问题与解答系列(1-8)

    声明:本系列文章转载自微信公众号HULU,本人只是搬运工,仅供学习,如有不妥,后续告知删除. 嗨,欢迎回来,希望你能保持定期回顾的好习惯噢!下面是Hulu机器学习问题与解答系列的前8篇内容,点击主题名 ...

  2. (转)Python内置函数进阶之“属性(property())”详解

    原文:https://blog.csdn.net/GeekLeee/article/details/78519767 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.c ...

  3. 全网最详细的PLSQL Developer + Oracle client的客户端 或者 PLSQL Developer + Oracle server服务端的下载与安装过程(图文详解)

    不多说,直接上干货! 环境说明: 本地没有安装Oracle服务端,oracle服务端64位,是远程连接,因此本地配置PLSQL Developer64位. Oracle database使用在本机部署 ...

  4. Linux之SElinux安全上下文件(1)

    SELinux:Secure Enhanced Linux,是美国国家安全局(NSA=The National Security Agency)和SCC(Secure Computing Courpo ...

  5. NIO的Buffer&Channel&Selector

    java的NIO和AIO Buffer position.limit.capacity 初始化 Buffer 填充 Buffer 提取 Buffer 中的值 mark() & reset() ...

  6. java开发细节问题,spring的单例模式,多线程同步问题

    1.对象的赋值,new一个对象,然后在传递给函数赋值,往往这对对象赋值就可以使用了 2.对于 spring开发的细节问题 Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例模式,这 ...

  7. Java 容器源码分析之Queue

    简介 Queue是一种很常见的数据结构类型,在java里面Queue是一个接口,它只是定义了一个基本的Queue应该有哪些功能规约.实际上有多个Queue的实现,有的是采用线性表实现,有的基于链表实现 ...

  8. 【IT笔试面试题整理】判断一个二叉树是否是平衡的?

    [试题描述]定义一个函数,输入一个链表,判断链表是否存在环路 平衡二叉树,又称AVL树.它或者是一棵空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的高度之差之差的 ...

  9. SpringMVC之使用 @RequestMapping 映射请求

    @RequestMapping注解 SpringMVC使用该注解让控制器知道可以处理哪些请求路径的,除了可以修饰方法,还可以修饰在类上. – 类定义处:提供初步的请求映射信息.相对于 WEB 应用的根 ...

  10. .1-浅析express源码之入口文件

    鸽了鸽了,webpack源码大垃圾,看了那么久,感觉自己越来越渣……还是换个口味,node了解一下? 尝试从express框架源码入手,学习一下node的http模块相关的知识. 入口文件 先从框架的 ...