最近接到一个来自产品的需求如下:用手在视频画框内画矩形框,矩形框内有物体移动将进行报警,最多三个区域
刚接到需求脑海瞬间行成了一个解决方案,这得益于我之前对github开源项目的“见多识广”!有事没事多看看一些优秀的开源项目还是很有用的。(每次只能选一个区域上传到服务器,根据次数控制是否支持再次选取)
首先呢感谢开源项目:https://github.com/edmodo/cropper
我需要如何修改呢?暂且分为以下几个步骤:
获取服务器端原图
根据服务器的宽高比例设定ImageView的宽高
修改开源库矩形框样式级是否隐藏选取框
提供获取矩形四个点的比例值,用于回传到服务器
首先明确一点,服务器的图片按照16:9的约定(16:9的比例我这里是写死的,还可以新增自定义属性来控制),图片的宽高一定大于手机的控件宽高,所以我们需要获取屏幕宽度,按照与服务器约定比例16:9动态设置view宽度(onLayout函数内调用,以防屏幕旋转问题)
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
WindowManager wm = (WindowManager) getContext()
.getSystemService(Context.WINDOW_SERVICE);
int width = wm.getDefaultDisplay().getWidth();
int height = width/16*9;
setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height));
super.onLayout(changed, left, top, right, bottom);
mBitmapRect = getBitmapRect();
initCropWindow(mBitmapRect);
}
注意: layoutParmas,這里针对的是我自己项目内父控件编码,如有需要自行修改别完全copy(可以改为通用getLayoutParams..)
如何能保证服务器获取的原图能完全显示到控件里面呢?这里需要使用到ImageView的缩放类型centerInside,如果你还不完全了解scaleType,可以参考下面内容(了解的略过)
内容摘自:
http://blog.csdn.net/hhbgk/article/details/8101676
CENTER /center 按图片的原来size居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分显示
CENTER_CROP / centerCrop 按比例扩大图片的size居中显示,使得图片长(宽)等于或大于View的长(宽)
CENTER_INSIDE / centerInside 将图片的内容完整居中显示,通过按比例缩小或原来的size使得图片长/宽等于或小于View的长/宽
FIT_CENTER / fitCenter 把图片按比例扩大/缩小到View的宽度,居中显示
FIT_END / fitEnd 把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置
FIT_START / fitStart 把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置
FIT_XY / fitXY 把图片不按比例扩大/缩小到View的大小显示
MATRIX / matrix 用矩阵来绘制,动态缩小放大图片来显示。
修改代码如下
public PrecinctImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
setScaleType(ScaleType.CENTER_INSIDE);
}
由于需求有限制选取区域三次,所以新增属性isOpenPrecinct,去掉原有所有自定义属性(都用不到干掉吧,强迫症患者没办法),自定义属性解析后在onDraw 函数做一个开关作用
"PrecinctImageView">
"isOpenPrecinct" format="boolean"/>
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(isOpenPrecinct){
drawDarkenedSurroundingArea(canvas);
drawBorder(canvas);
drawCorners(canvas);
}
}
去掉原有的draw网格线方法,修改四个角的绘制,改为drawCircle
private void drawCorners(@NonNull Canvas canvas) {
final float left = Edge.LEFT.getCoordinate();
final float top = Edge.TOP.getCoordinate();
final float right = Edge.RIGHT.getCoordinate();
final float bottom = Edge.BOTTOM.getCoordinate();
final float lateralOffset = (mCornerThickness - mBorderThickness) / 2f;
final float startOffset = mCornerThickness - (mBorderThickness / 2f);
canvas.drawCircle(left, top, radioSize, mCornerPaint);
canvas.drawCircle(right, top, radioSize, mCornerPaint);
canvas.drawCircle(left, bottom, radioSize, mCornerPaint);
canvas.drawCircle(right, bottom, radioSize, mCornerPaint);
}
修改边框圆点样式,通过修改value 下默认值实现
<resources>
<color name="white_translucent">#AAFFFFFFcolor>
<color name="black_translucent">#B0000000color>
<color name="border">#FFB529color>
<color name="guideline">@color/white_translucentcolor>
<color name="corner">#FFB529color>
<color name="surrounding_area">#66000000color>
resources>
<resources>
<dimen name="border_thickness">1dpdimen>
<dimen name="corner_thickness">5dpdimen>
<dimen name="guideline_thickness">1pxdimen>
<dimen name="target_radius">24dpdimen>
<dimen name="snap_radius">3dpdimen>
<dimen name="corner_length">20dpdimen>
resources>
最后一步获取四个点坐标,根据控件的宽高转换为比例值,阅读源码发现Edge类可以为我们直接获取点坐标
public PointP getPrecinctPointP(){
PointP pointP = new PointP();
pointP.setLeftTopX(Edge.LEFT.getCoordinate()/getMeasuredWidth());
pointP.setLeftTopY(Edge.TOP.getCoordinate() / getMeasuredHeight());
pointP.setRightTopX(Edge.RIGHT.getCoordinate() / getMeasuredWidth());
pointP.setRightTopY(Edge.TOP.getCoordinate() / getMeasuredHeight());
pointP.setLeftBottomX(Edge.LEFT.getCoordinate() / getMeasuredWidth());
pointP.setLeftBottomY(Edge.BOTTOM.getCoordinate() / getMeasuredHeight());
pointP.setRightBottomX(Edge.RIGHT.getCoordinate() / getMeasuredWidth());
pointP.setRightBottomY(Edge.BOTTOM.getCoordinate()/getMeasuredHeight());
return pointP;
}
以上修改看上去没有任何问题,但是结果呢总是那么不如人愿!这个开源库getBitmapRect()函数
private RectF getBitmapRect() {
final Drawable drawable = getDrawable();
if (drawable == null) {
return new RectF();
}
//*************略************
}
这里获取的src对应的drawable资源,而在某种情况下图片如果比控件宽高小,设置src会导致图片显示不能完全覆盖控件,部分显示纯黑色,如果此时设置为Background,源码里getBitmapRect()获取到的范围值为0,所以这里应该修改代码如下
private RectF getBitmapRect() {
final Drawable drawable = getBackground();
if (drawable == null) {
return new RectF();
}
"@+id/precinctImageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/content_padding"
android:adjustViewBounds="true"
android:background="@drawable/butterfly"/>
最后附上效果图: