Android自定义View图片裁剪,支持自由裁剪、按自定义比例裁剪、圆形裁剪、旋转、镜面翻转,从0到1自定义View
很多初学者、中级开发其实都不会自定义View,但是没关系,学习是自己的,悄咪咪的学,慢慢进步。本篇介绍的是很多项目都会用到的自定义图片裁剪控件(结尾有Demo链接,可直接运行,调用非常方便),不说废话,直接开始。
-
新建类,继承View
-
测量好控件的宽高并设置给控件自身
记住这个onMeasure方法,一般自定义View都会走的一步骤
- 定好图片的缩放规则,图片在自定义View中实际画的宽度和高度(以及圆形裁剪时的直径或半径)
我在这里写了一个reSizePhoto
方法,这个方法的作用是每次进行图片设置或者裁剪设置重新进行BitMap的宽高计算,以及直径的计算、裁剪区域四个角的矩形区域计算(也就是矩阵Rect),代码如下:
fun reSizePhoto(degree : Float){
if(img != null){
if(orientation == 0){
if(oldImg!!.width >= oldImg!!.height){
multipleWidth = NumberUtils.devide(w.toString(),oldImg!!.width.toString())
}else{
multipleWidth = NumberUtils.devide(h.toString(),oldImg!!.height.toString())
}
imgWidth = NumberUtils.multiply(oldImg!!.width.toString(),multipleWidth.toString())
imgHeight = NumberUtils.multiply(oldImg!!.height.toString(),multipleWidth.toString())
}else{
multipleWidth = NumberUtils.devide(w.toString(),oldImg!!.height.toString())
imgHeight = NumberUtils.multiply(oldImg!!.width.toString(),multipleWidth.toString())
imgWidth = w
}
diameter = imgWidth!!
if(diameter!! > w!!){
diameter = w
}
if(cropType == 0){
rectL = 0
if(orientation == 0){
rectT = 0
rectR = w!!!!.toInt()
rectB = h!!.toInt()
}else{
rectT = (h!!/2 - imgHeight!!/2).toInt()
rectR = w!!!!.toInt()
rectB = (h!!/2 + imgHeight!!/2).toInt()
}
}else if(cropType == 2){
var cropW = NumberUtils.multiply(cropRatioW.toString(),w!!.toString())
var cropH = NumberUtils.multiply(cropRatioH.toString(),cropW!!.toString())
rectL = ((w!! - cropW)/2).toInt()
rectT = ((h!! - cropH)/2).toInt()
rectR = (rectL!! + cropW).toInt()
rectB = cropH.toInt() + rectT!!
customL = rectL
customT = rectT
customR = rectR
customB = rectB
}else{
if(imgWidth!! > imgHeight!!){
diameter = imgHeight
rectL = ((w!! - diameter!!)/2).toInt()
rectT = ((h!!-diameter!!)/2).toInt()
rectB = ((h!!-diameter!!)/2).toInt() + diameter!!.toInt()
rectR = (rectL!! + diameter!!).toInt()
}else{
rectL = 0
rectT = ((h!!-diameter!!)/2).toInt()
rectB = (rectT!! + diameter!!).toInt()
rectR = w!!!!.toInt()
}
}
var matrix = Matrix()
matrix.setRotate(degree)
this.img = Bitmap.createBitmap(img!!,0,0,img!!.width,img!!.height,matrix,true)
this.img = Bitmap.createScaledBitmap(this.img!!,imgWidth!!.toInt(),imgHeight!!.toInt(),true)
alphaImg = img
if(orientation == 0){
Log.i("==========","==========图片 纵向 宽:${img!!.width} 高:${img!!.height} imgWidth:$imgWidth imgHeight:$imgHeight")
}else{
Log.i("==========","==========图片 横向 宽:${img!!.width} 高:${img!!.height} imgWidth:$imgWidth imgHeight:$imgHeight")
}
leftBorder = (w!! - imgWidth!!)/2
rightBorder = ((w!! - imgWidth!!)/2 + imgWidth!!)
if(imgWidth!! > w!!){
leftBorder = 0f
rightBorder = w!!
}
topBorder = (h!! - imgHeight!!)/2
bottomBorder = (h!! - imgHeight!!)/2 + imgHeight!!
if(imgHeight!! >= h!!){
topBorder = 0f
bottomBorder = h!!
}
if(rectL!! <= leftBorder!!){
rectL = leftBorder!!.toInt()
}
if(rectR!! >= rightBorder!!){
rectR = rightBorder!!.toInt()
}
if(rectT!! <= topBorder!!){
rectT = topBorder!!.toInt()
}
if(rectB!! >= bottomBorder!!){
rectB = bottomBorder!!.toInt()
}
hypotenuse = distancePoint(rectL!!.toFloat(),rectT!!.toFloat(),rectR!!.toFloat(),rectB!!.toFloat())
}
}
hypotenuse 这里要说明这个指的是两个点之间的一个直线距离,这个变量是用于按比例裁剪,因为按按比例裁剪它的裁剪区域宽高比是始终保持不变的,也就是中心的斜线不变,通过勾股定理即可得出中间斜线的长度,这样就可以得出实际原来最大的宽高比和目前的宽高比对裁剪区域的宽高进行等比缩放。
distancePoint方法是通过勾股定理计算出两个点之间的直线距离,代码如下:
(看不懂的朋友,请自行百度Math的方法,这里是开方和平方运算)
fun distancePoint(startX : Float,startY : Float,endX : Float,endY : Float) : Float{
return Math.sqrt(Math.pow((startX - endX).toDouble(),2.0) + Math.pow((startY - endY).toDouble(),2.0)).toFloat()
}
- 宽高直径、缩放比例这些都准备就绪,那就开始画图,这里实际上是画两个大小相同BitMap,一个是暗色的,一个是高亮的,开始onDraw()
这里要注意,我们只需要画一个暗色的Bitmap(也就是半透明的,直接设置Paint的透明度即可),但是高亮的原图(没有半透明的)我们也要准备好,我们画完暗色的图,再根据裁剪区域的Rect去在Canvas上绘制裁剪出来的区域,给人的视觉就是中间高亮,其它区域都是暗色的效果。
上onDraw代码:
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
paint?.alpha = 100
if(alphaImg != null){
canvas.drawBitmap(alphaImg!!,(w!!-alphaImg!!.width!!)/2,(h!!-alphaImg!!.height!!)/2,paint)
}
paint?.alpha = 255
if(img != null){
if(cropType == 0 || cropType == 2){
cropBitmap = cropRectangle(img!!,rectL!!.toFloat(),rectT!!.toFloat(),rectR!!.toFloat(),rectB!!.toFloat(),paint!!)
canvas.drawBitmap(cropBitmap!!,0f,0f,paint)
}else{
cropBitmap = cropCircle(img!!,diameter!!/2,paint!!,rectL!!.toFloat(),rectT!!.toFloat())
canvas.drawBitmap(cropBitmap!!,0f,0f,paint)
}
}
if(rectL != null){
if((rectR!! - rectL!!) > (rectB!! - rectT!!)){
borderWidth = (rectB!! - rectT!!)/3
}else{
borderWidth = (rectR!! - rectL!!)/3
}
if(borderWidth > 90){
borderWidth = 90
}
var path = Path()
//左上角
path.moveTo(rectL!!.toFloat(),(rectT!!+borderWidth).toFloat())
path.lineTo(rectL!!.toFloat(),rectT!!.toFloat())
path.lineTo((rectL!!+borderWidth).toFloat(),rectT!!.toFloat())
path.lineTo(rectL!!.toFloat(),rectT!!.toFloat())
path.close()
canvas.drawPath(path,linePaint!!)
//左下角
path.moveTo(rectL!!.toFloat(),(rectB!!-borderWidth).toFloat())
path.lineTo(rectL!!.toFloat(),rectB!!.toFloat())
path.lineTo((rectL!!+borderWidth).toFloat(),rectB!!.toFloat())
path.lineTo(rectL!!.toFloat(),rectB!!.toFloat())
path.close()
canvas.drawPath(path,linePaint!!)
//右上角
path.moveTo(rectR!!.toFloat(),(rectT!!+borderWidth).toFloat())
path.lineTo(rectR!!.toFloat(),rectT!!.toFloat())
path.lineTo((rectR!!-borderWidth).toFloat(),rectT!!.toFloat())
path.lineTo(rectR!!.toFloat(),rectT!!.toFloat())
path.close()
canvas.drawPath(path,linePaint!!)
//右下角
path.moveTo(rectR!!.toFloat(),(rectB!!-borderWidth).toFloat())
path.lineTo(rectR!!.toFloat(),rectB!!.toFloat())
path.lineTo((rectR!!-borderWidth).toFloat(),rectB!!.toFloat())
path.lineTo(rectR!!.toFloat(),rectB!!.toFloat())
path.close()
canvas.drawPath(path,linePaint!!)
//上横线
canvas.drawLine((rectL!!+(rectR!!-rectL!!)/2).toFloat(),rectT!!.toFloat(),((rectL!!+(rectR!!-rectL!!)/2)).toFloat()-borderWidth/2,rectT!!.toFloat(),linePaint!!)
canvas.drawLine((rectL!!+(rectR!!-rectL!!)/2).toFloat(),rectT!!.toFloat(),((rectL!!+(rectR!!-rectL!!)/2)).toFloat()+borderWidth/2,rectT!!.toFloat(),linePaint!!)
//下横线
canvas.drawLine((rectL!!+(rectR!!-rectL!!)/2).toFloat(),rectB!!.toFloat(),(rectL!!+(rectR!!-rectL!!)/2).toFloat()-borderWidth/2,rectB!!.toFloat(),linePaint!!)
canvas.drawLine((rectL!!+(rectR!!-rectL!!)/2).toFloat(),rectB!!.toFloat(),(rectL!!+(rectR!!-rectL!!)/2).toFloat()+borderWidth/2,rectB!!.toFloat(),linePaint!!)
//左竖线
canvas.drawLine((rectL!!).toFloat(),(rectT!!+(rectB!!-rectT!!)/2).toFloat(),(rectL!!).toFloat(),(rectT!!+(rectB!!-rectT!!)/2).toFloat() + borderWidth/2,linePaint!!)
canvas.drawLine((rectL!!).toFloat(),(rectT!!+(rectB!!-rectT!!)/2).toFloat(),(rectL!!).toFloat(),(rectT!!+(rectB!!-rectT!!)/2).toFloat() - borderWidth/2,linePaint!!)
//右竖线
canvas.drawLine((rectR!!).toFloat(),(rectT!!+(rectB!!-rectT!!)/2).toFloat(),(rectR!!).toFloat(),(rectT!!+(rectB!!-rectT!!)/2).toFloat() + borderWidth/2,linePaint!!)
canvas.drawLine((rectR!!).toFloat(),(rectT!!+(rectB!!-rectT!!)/2).toFloat(),(rectR!!).toFloat(),(rectT!!+(rectB!!-rectT!!)/2).toFloat() - borderWidth/2,linePaint!!)
}
}
其实很简单onDraw,画一个底图(暗色半透明的Bitmap),通过cropCircle(圆形裁剪)或cropRectangle(矩形裁剪)裁剪出中间的高亮区域,然后画四个角和中间的横线竖线,记住最后画线,因为线是在图片上方的。这里贴上裁剪区域(高亮区域)的代码:
fun cropCircle(sourceBitmap: Bitmap,radius : Float,paint: Paint,x : Float,y : Float) : Bitmap{
Log.i("============","===========cropCircle radius:$radius x:$x y:$y")
// 创建一个和View一样大小的Bitmap,作为画布
var outputBitmap = Bitmap.createBitmap(w!!.toInt(), h!!.toInt(), Bitmap.Config.ARGB_8888)
var outputCanvas = Canvas(outputBitmap)
// 绘制圆形裁剪区域
var cropRect = Rect(((w!!-imgWidth!!)/2).toInt(),((h!!-imgHeight!!)/2).toInt(),((w!!-imgWidth!!)/2).toInt()+imgWidth!!.toInt(),((h!!-imgHeight!!)/2).toInt()+imgHeight!!.toInt())
outputCanvas.drawCircle(x+radius, y+radius, radius, paint)
// 将sourceBitmap绘制在outputCanvas上,并应用裁剪
paint.setXfermode(PorterDuffXfermode(PorterDuff.Mode.SRC_IN))
outputCanvas.drawBitmap(sourceBitmap, null, cropRect, paint)
// 绘制裁剪后的图像
paint.setXfermode(null)
return outputBitmap
}
fun cropRectangle(sourceBitmap: Bitmap,l : Float,t : Float,r : Float,b : Float,paint: Paint) : Bitmap{
// 创建一个和View一样大小的Bitmap,作为画布
var outputBitmap = Bitmap.createBitmap(w!!.toInt(), h!!.toInt(), Bitmap.Config.ARGB_8888)
var outputCanvas = Canvas(outputBitmap)
// 绘制圆形裁剪区域
var cropRect = Rect(((w!!-imgWidth!!)/2).toInt(),((h!!-imgHeight!!)/2).toInt(),((w!!-imgWidth!!)/2).toInt()+imgWidth!!.toInt(),((h!!-imgHeight!!)/2).toInt()+imgHeight!!.toInt())
outputCanvas.drawRect(l, t, r,b, paint)
// 将sourceBitmap绘制在outputCanvas上,并应用裁剪
paint.setXfermode(PorterDuffXfermode(PorterDuff.Mode.SRC_IN))
outputCanvas.drawBitmap(sourceBitmap, null, cropRect, paint)
// 绘制裁剪后的图像
paint.setXfermode(null)
return outputBitmap
}
这里进行代码的说明,这里实际上就是新建一个Canvas对原位图进行一个重新绘制,并且在绘制好的位图上去做一个裁剪,并将裁剪区域的位图返回出来,这里有一个知识点:
PorterDuffXfermode 这个自己自行百度,本篇不多做介绍,可以去学习Paint的绘制模式
- 基础绘制已完成,处理用户触摸事件
因为此控件需要尽可能地把用户的所有触摸事件进行处理,所以直接重写dispatchTouchEvent
dispatchTouchEvent 不懂的同学可以去学习事件传递机制。本篇也不多做介绍,慢慢来,不要着急。
先上代码:
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
if(event.action == MotionEvent.ACTION_DOWN){
downX = event.x
downY = event.y
var leftHorizontalStance = event.x - rectL!!
if(leftHorizontalStance < 0){
leftHorizontalStance *= -1
}
var rightHorizontalStance = event.x - rectR!!
if(rightHorizontalStance < 0){
rightHorizontalStance *= -1
}
var verticalTopStance = event.y - rectT!!
if(verticalTopStance < 0){
verticalTopStance *= -1
}
var verticalBottomStance = event.y - rectB!!
if(verticalBottomStance < 0){
verticalBottomStance *= -1
}
if(leftHorizontalStance <= touchOffset && verticalTopStance <= touchOffset){ //左上角
touchStatus = 0
touchX = event.x
touchY = event.y
isCanDrag = true
}else if(leftHorizontalStance <= touchOffset && verticalBottomStance <= touchOffset){ //左下角
touchStatus = 3
touchX = event.x
touchY = event.y
isCanDrag = true
}else if(rightHorizontalStance <= touchOffset && verticalTopStance <= touchOffset){ //右上角
touchStatus = 1
touchX = event.x
touchY = event.y
isCanDrag = true
}else if(rightHorizontalStance <= touchOffset && verticalBottomStance <= touchOffset){ //右下角
touchStatus = 2
touchX = event.x
touchY = event.y
isCanDrag = true
}else{
isCanDrag = false
}
}else if(event.action == MotionEvent.ACTION_MOVE){
if(isCanDrag){
touchX = event.x
touchY = event.y
Log.i("=========","=========touchLocation touchX:$touchX touchY:$touchY w:$w imgWidth:$imgWidth h:$h imgHeight:$imgHeight")
if(imgWidth!! > w!!){
leftBorder = 0f
rightBorder = w!!
}
if(imgHeight!! >= h!!){
topBorder = 0f
bottomBorder = h!!
}
Log.i("=========","=========touchLocation leftBorder:$leftBorder rightBorder:$rightBorder topBorder:$topBorder bottomBorder:$bottomBorder ")
if(event.x <= leftBorder!!){
touchX = leftBorder!!
}else if(event.x >= rightBorder!!){
touchX = rightBorder!!
}
if(event.y <= topBorder!!){
touchY = topBorder!!
}else if(event.y >= bottomBorder!!){
touchY = bottomBorder!!
}
when(touchStatus){
0 -> {
rectL = touchX.toInt()
rectT = touchY.toInt()
if(cropType == 1){
if(w!! > h!!){
diameter = (rectB!! - rectT!!).toFloat()
}else{
diameter = (rectR!! - rectL!!).toFloat()
}
rectR = (rectL!! + diameter!! ).toInt()
rectB = (rectT!! + diameter!! ).toInt()
}
}
1 -> {
rectR = touchX.toInt()
rectT = touchY.toInt()
if(cropType == 1){
if(w!! > h!!){
diameter = (rectB!! - rectT!!).toFloat()
}else{
diameter = (rectR!! - rectL!!).toFloat()
}
rectL = (rectR!! - diameter!! ).toInt()
rectB = (rectT!! + diameter!! ).toInt()
}
}
2 -> {
rectR = touchX.toInt()
rectB = touchY.toInt()
if(cropType == 1){
if(w!! > h!!){
diameter = (rectB!! - rectT!!).toFloat()
}else{
diameter = (rectR!! - rectL!!).toFloat()
}
rectL = (rectR!! - diameter!! ).toInt()
rectT = (rectB!! - diameter!! ).toInt()
}
}
3 -> {
rectL = touchX.toInt()
rectB = touchY.toInt()
if(cropType == 1){
if(w!! > h!!){
diameter = (rectB!! - rectT!!).toFloat()
}else{
diameter = (rectR!! - rectL!!).toFloat()
}
rectR = (rectL!! + diameter!! ).toInt()
rectT = (rectB!! - diameter!! ).toInt()
}
}
}
customRatioCheck(touchX,touchY)
circleCheckBorder()
Log.i("==========","==========直径:$diameter")
postInvalidate()
}
Log.i("========","========touchStatus:$touchStatus")
}else if(event.action == MotionEvent.ACTION_UP || event.action == MotionEvent.ACTION_CANCEL){
isCanDrag = false
}
return true
}
这里进行一个讲解,用户操作裁剪区域,实际上改变的就是一个矩阵,就是一开始我们定义的Rect和直径(如果是圆形裁剪),这里我们要对当前裁剪模式进行判断,然后再进行处理:
if(是什么模式裁剪?矩形?比例?圆形?){
…根据当前模式进行矩阵变换
… 绘制
}
**这里还要注意我们要做两个个校验:
1. 校验1
第一个是用户操作裁剪区域不能超过屏幕区域,超过我们则默认为最大屏幕区域,不再变化。
1. 校验2
如果是按比例裁剪,我们要校验除了当前用户触摸的点以外的其它三个点是否满足我们当前的比例(也就是长宽),不满足我们则直接通过计算去让其在满足区域的点位置上
这里我也把校验的代码贴上:
fun circleCheckBorder(){
if(cropType != 1){
return
}
if(rectL!! <= leftBorder!!){
rectL = leftBorder!!.toInt()
rectR = (leftBorder!! + diameter!!).toInt()
}
if(rectT!! <= topBorder!!){
rectT = topBorder!!.toInt()
rectB = (topBorder!! + diameter!!).toInt()
}
if(rectR!! >= rightBorder!!){
rectR = rightBorder!!.toInt()
rectL = (rightBorder!! - diameter!!).toInt()
}
if(rectB!! >= bottomBorder!!){
rectB = bottomBorder!!.toInt()
rectT = (bottomBorder!! - diameter!!).toInt()
}
}
fun customRatioCheck(x : Float,y: Float){
if(cropType != 2){
return
}
var xStance = x - downX
var yStance = y - downY
if(xStance < 0){
xStance *= -1
}
if(yStance < 0){
yStance *= -1
}
when(touchStatus){
0 -> { //左上角
var stance = distancePoint(rectR!!.toFloat(),rectB!!.toFloat(),x,y)
var hypotenuseRatio : Float ?= null
if(stance > hypotenuse!!){
hypotenuseRatio = stance%hypotenuse!!
}else{
hypotenuseRatio = hypotenuse!!%stance
}
if(hypotenuseRatio!! != 0f && hypotenuseRatio >= 0.2f){
var scaleRatio = NumberUtils.devide(stance.toString(),hypotenuse.toString())
var newW = NumberUtils.multiply((customR!! - customL!!).toString(),scaleRatio.toString())
var newH = NumberUtils.multiply((customB!! - customT!!).toString(),scaleRatio.toString())
rectL = (rectR!! - newW).toInt()
rectT = (rectB!! - newH).toInt()
}
if(rectL!! < leftBorder!!){
rectL = leftBorder!!.toInt()
rectT = rectB!! - NumberUtils.multiply((rectR!! - rectL!!).toString(),cropRatioH.toString()).toInt()
}else if(rectT!! < topBorder!!){
rectT = topBorder!!.toInt()
rectL = rectR!! - NumberUtils.devide((rectB!! - rectT!!).toString(),cropRatioH.toString()).toInt()
}
}
1 -> { //右上角
var stance = distancePoint(rectL!!.toFloat(),rectB!!.toFloat(),x,y)
var hypotenuseRatio : Float ?= null
if(stance > hypotenuse!!){
hypotenuseRatio = stance%hypotenuse!!
}else{
hypotenuseRatio = hypotenuse!!%stance
}
if(hypotenuseRatio!! != 0f && hypotenuseRatio >= 0.2f){
var scaleRatio = NumberUtils.devide(stance.toString(),hypotenuse.toString())
var newW = NumberUtils.multiply((customR!! - customL!!).toString(),scaleRatio.toString())
var newH = NumberUtils.multiply((customB!! - customT!!).toString(),scaleRatio.toString())
rectR = (rectL!! + newW).toInt()
rectT = (rectB!! - newH).toInt()
}
if(rectR!! > rightBorder!!){
rectR = rightBorder!!.toInt()
rectT = rectB!! - NumberUtils.multiply((rectR!! - rectL!!).toString(),cropRatioH.toString()).toInt()
}else if(rectT!! < topBorder!!){
rectT = topBorder!!.toInt()
rectR = rectL!! + NumberUtils.devide((rectB!! - rectT!!).toString(),cropRatioH.toString()).toInt()
}
}
2 -> { //右下角
var stance = distancePoint(rectL!!.toFloat(),rectT!!.toFloat(),x,y)
var hypotenuseRatio : Float ?= null
if(stance > hypotenuse!!){
hypotenuseRatio = stance%hypotenuse!!
}else{
hypotenuseRatio = hypotenuse!!%stance
}
if(hypotenuseRatio!! != 0f && hypotenuseRatio >= 0.2f){
var scaleRatio = NumberUtils.devide(stance.toString(),hypotenuse.toString())
var newW = NumberUtils.multiply((customR!! - customL!!).toString(),scaleRatio.toString())
var newH = NumberUtils.multiply((customB!! - customT!!).toString(),scaleRatio.toString())
rectR = (rectL!! + newW).toInt()
rectB = (rectT!! + newH).toInt()
}
if(rectR!! > rightBorder!!){
rectR = rightBorder!!.toInt()
rectB = rectT!! + NumberUtils.multiply((rectR!! - rectL!!).toString(),cropRatioH.toString()).toInt()
}else if(rectB!! > bottomBorder!!){
rectB = bottomBorder!!.toInt()
rectR = rectL!! + NumberUtils.devide((rectB!! - rectT!!).toString(),cropRatioH.toString()).toInt()
}
}
3 -> { //左下角
var stance = distancePoint(rectR!!.toFloat(),rectT!!.toFloat(),x,y)
var hypotenuseRatio : Float ?= null
if(stance > hypotenuse!!){
hypotenuseRatio = stance%hypotenuse!!
}else{
hypotenuseRatio = hypotenuse!!%stance
}
if(hypotenuseRatio!! != 0f && hypotenuseRatio >= 0.2f){
var scaleRatio = NumberUtils.devide(stance.toString(),hypotenuse.toString())
var newW = NumberUtils.multiply((customR!! - customL!!).toString(),scaleRatio.toString())
var newH = NumberUtils.multiply((customB!! - customT!!).toString(),scaleRatio.toString())
rectL = (rectR!! - newW).toInt()
rectB = (rectT!! + newH).toInt()
}
if(rectL!! < leftBorder!!){
rectL = leftBorder!!.toInt()
rectB = rectT!! + NumberUtils.multiply((rectR!! - rectL!!).toString(),cropRatioH.toString()).toInt()
}else if(rectB!! > bottomBorder!!){
rectB = bottomBorder!!.toInt()
rectL = rectR!! - NumberUtils.devide((rectB!! - rectT!!).toString(),cropRatioH.toString()).toInt()
}
}
}
}
好了,本篇完,需要Demo代码的自取:
源码
本人所有文章不多废话,不漏代码,一般文章都会配资源Demo一份,分享最实际,最常用,真实能用的东西。