而显示区域的四个角位置,获取就相对简单。其中左与上固定为0,剩下的就是右边与底部点了。
//由于裁剪区域与显示区域长宽应该是一致的,所以这里默认右边与底部为最终裁剪大小
int showRight = actuallyWidth;
int showBottom = actuallyHeight;
int cropRight = cropLeft+actuallyWidth;
int cropBottom = cropTop+actuallyHeight;
//裁剪超出图片边界超出边界
if(cropRight>bitmap.getWidth()){
cropRight = bitmap.getWidth();
//由于左固定为0,那么这里相应也要调整右边位置,让宽度与裁剪区域一致
showRight = bitmap.getWidth()-cropLeft;
}
if(cropBottom>bitmap.getHeight()){
cropBottom = bitmap.getHeight();
//由于上位置固定为0,那么这里相应也要调整底部位置,让高度与裁剪区域一致
showBottom = bitmap.getHeight()-cropTop;
}
至此,裁剪所需要的参数全部计算完毕,这样就可以正确裁剪出预览框中的内容。
边界限制#####
为了提升用户体验,或者是实现需求,可能我们需要限制缩放&移动的边界,让裁剪预览框的区域可以完全在图片里面,换个意思就是说,裁剪最后的图片一定是图片上的某个区域,而不会出现只裁剪到一部分图片,另一部分是空白的。
边界的限制只是针对移动与缩放。下面我们分别看看怎么对两者做边界限制
移动边界限制
同样由于涉及到了缩放,移动的边界限制需要特别处理。具体的思路是获取当前移动的距离与当前图片在屏幕上实际的四个位置点(左右上下),例如我们需要判断是否会超过左边界,那么我们会判断横坐标移动的距离+图片当前左边位置是否大于限制框的左边横坐标,是的话,那么则视为出界,应当重新计算移动距离。其他三个位置亦是如此,我们还是看下下面的代码片。
public void drag(float motionX, float motionY) {
//移动距离
float moveX = motionX -mLastX;
float moveY = motionY - mLastY;
//mRestrictRect为限制框,这个框实质就是预览框在屏幕上的坐标位置
if(mRestrictRect!=null){
//经过缩放与移动后,图片在屏幕上实际的位置
RectF rectF = getCurrentRectF();
//下面为四边边界的判断与重计算
if(moveX>0){
if(rectF.left+moveX>mRestrictRect.left){
moveX = mRestrictRect.left-rectF.left;
}
}else {
if(rectF.right+moveX<mRestrictRect.right){
moveX = mRestrictRect.right- rectF.right;
}
}
if(moveY>0){
if(rectF.top+moveY>mRestrictRect.top){
moveY = mRestrictRect.top-rectF.top;
}
}else {
if(rectF.bottom+moveY<mRestrictRect.bottom){
moveY = mRestrictRect.bottom- rectF.bottom;
}
}
}
mView.getImageMatrix().postTranslate(moveX,moveY);
mView.invalidate();
}
缩放边界限制
缩放边界的限制会相对复杂。因为当缩放出界时,需要根据多种情况重新计算缩放所需要的参数。
缩放边界限制的流程是:
1、按照缩放值,获取图片将会在屏幕出现的位置
2、判断四个位置是否会超出边界,并记录四个位置边界判断结果。如果缩放后的某个位置会超出限制框的边界位置,那么则限定该坐标为缩放中心点,保证该点位置不移动。例如左边将会出界,那么则以限制框的左边位置作为最终缩放中心点横坐标。
3、如果左右或者上下出界,则不用进行缩放,因为无法缩放了。如果不是这种情况,则进入4
4、根据Martrix缩放的计算公式推导出,什么缩放倍数下,会达到限制框的边界值。这里将会取到四个边界缩放值与当前的缩放值进行比对,取其中最大的缩放值作为最后的缩放值(因为缩小情况才会导致越界)
我们看看具体的代码片
public boolean onScale(ScaleGestureDetector detector) {
//初始化缩放值
float px = detector.getFocusX();
float py = detector.getFocusY();
float scaleFactor= detector.getScaleFactor();
if(mRestrictRect!=null){
Matrix matrixAfter = new Matrix(mView.getImageMatrix());
matrixAfter.postScale(detector.getScaleFactor()
,detector.getScaleFactor(),detector.ge tFocusX(),detector.getFocusY());
final BitmapDrawable drawable = (BitmapDrawable) mView.getDrawable();
final Bitmap bitmap = drawable.getBitmap();
RectF rectF = new RectF(0,0,bitmap.getWidth(),bitmap.getHeight());
//上面的大段代码都是为了这里,这里将会获取按照当前缩放值缩放后的图片实际的坐标位置
matrixAfter.mapRect(rectF);
boolean isLeftLimit = false ,isRightLimit = false ,
isTopLimit = false ,isBottomLimit =false;
//判断缩放后的位置是否会超过边界
if(rectF.left>mRestrictRect.left){
//超过边界则将点最为最后的缩放中心点,让该边界的点固定下来,不被改变
px = mRestrictRect.left;
isLeftLimit = true;
}
if(rectF.right<mRestrictRect.right){
px = mRestrictRect.right;
isRightLimit = true;
}
if(rectF.top>mRestrictRect.top){
py = mRestrictRect.top;
isTopLimit = true;
}
if(rectF.bottom<mRestrictRect.bottom){
py = mRestrictRect.bottom;
isBottomLimit = true;
}
//左右两边或者上下两边都无法缩放,就不缩放了
if((isRightLimit&&isLeftLimit)||(isTopLimit&&isBottomLimit)){
return true;
}
//重新计算允许的最小缩放倍数,根据四条边界的缩放倍数与当前的缩放倍数,
//获取最大缩放倍数,因为主要是缩小才会导致超越边界
//计算公式是: 结果坐标(ResultX) = 缩放前坐标(Before X)*缩放倍数(scale)
//+中心点坐标(center X)*(1-缩放倍数(scale))
float maxScaleLeft = (mRestrictRect.left-px)/(getCurrentRectF().left-px);
if(scaleFactor<maxScaleLeft){
scaleFactor = maxScaleLeft;
}
float maxScaleRight = (mRestrictRect.right-px)/(getCurrentRectF().right-px);
if(scaleFactor<maxScaleRight){
scaleFactor = maxScaleRight;
}
float maxScaleTop = (mRestrictRect.top-py)/(getCurrentRectF().top-py);
if(scaleFactor<maxScaleTop){
scaleFactor = maxScaleTop;
}
float maxSacleBottom = (mRestrictRect.bottom-py)/(getCurrentRectF().bottom-py);
if(scaleFactor<maxSacleBottom){
scaleFactor = maxSacleBottom;
}
}
//保存当前的缩放值
mScale=mScale*scaleFactor;
//执行缩放
mView.getImageMatrix().postScale(scaleFactor,scaleFactor,
px,py);
mView.invalidate();
return true;
}
GitHub地址#####
最后附录上EnjoyCrop源码EnjoyCrop,希望这篇文档对你有帮助,谢谢!