Android仿微信的图片裁剪库 ------ 持续开发中(裁剪框与图片的联动)

终于分解的步骤基本已经完成了,接下来我们讲一下裁剪框和图片的联动以及动画的更新。

 

其实从前面几次的讲解,其实简单来说就是两个RectF的维护-----裁剪框和图片。那么除了移动以外我们主要做的就是找到动画开始和结束的状态,也就是两个RectF的。

 

接下来我们拓展一下我们的估值器,让它也计算裁剪框的RectF的变化

if (startValue.winFrame != null) {
                Log.d(TAG, "${endValue?.winFrame}")
                left = startValue.winFrame?.left!! + fraction * (endValue.winFrame?.left!! - startValue.winFrame?.left!!)
                top = startValue.winFrame?.top!! + fraction * (endValue.winFrame?.top!! - startValue.winFrame?.top!!)
                right = startValue.winFrame?.right!! + fraction * (endValue.winFrame?.right!! - startValue.winFrame?.right!!)
                bottom = startValue.winFrame?.bottom!! + fraction * (endValue.winFrame?.bottom!! - startValue.winFrame?.bottom!!)

                clipImageState?.winFrame = RectF(left, top, right, bottom)
            } else {
                clipImageState?.winFrame = null
            }

我们在手指按下时,记录一下锚点,即是否点击到了裁剪框。

override fun onDown(e: MotionEvent?): Boolean {
        Log.d(TAG, "onDown")
        mAnchor = clipImageWindowView.getAnchor(e?.x!!, e.y)
        if (mAnchor != null) {
            isChanged = true
        }
        isSteady = false
        return true
    }

而在ontouchEvent中我们监听手指松开的一系列情况,大致分为一下三种:

1.当前拖动裁剪框完毕

     那么我们的思路很明确,一是把裁剪框放大,而是图片的放大和移动

     具体关于RectF的计算逻辑很简单,首先是看裁剪框是应该上下顶到View的边界还是左右顶到View的边界。然后就可以确定缩放比例,之后记录裁剪框中心的位移,将该位移应用到放大后的图片,使得裁剪框内图片内容不发生变化。

2.手动缩放图片

    手动缩放图片我们需要处理一个特殊case,就是缩放之后图片小于了裁剪框,此时我们要把图片放大到至少与裁剪框对齐。

3.手动拖拽图片

    手动拖拽我们也需要处理特殊的case,就是图片越过边界之后恢复到与裁剪框对齐。

 

我的具体实现可能比较冗杂,建议大家自己捋一捋逻辑还是很有帮助的,之后我会上传到github上欢迎大家拍砖。

 /**
     * 监听手指抬起动作进行图片的复位
     */
    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent?): Boolean {

        var handled = mScaleGestureDetector?.onTouchEvent(event) ?: false
        handled = mGestureDetector?.onTouchEvent(event) ?: false || handled

        if (event?.actionMasked == MotionEvent.ACTION_UP ||
                event?.actionMasked == MotionEvent.ACTION_CANCEL) {
            /**
             * 临时变量用于存储图片frame的起始状态作为动画的开始状态
             */
            val startFrame = RectF()
            startFrame.set(zoomImageView.getFrame())
            if (mAnchor != null) {
                val tempList = clipImageWindowView.endState
                val winEndState = tempList[1] as RectF
                val tempScale = tempList[0] as Float
                val imageEndState = zoomImageView.getScaleEnd(tempScale, clipImageWindowView.mFrame.centerX(),
                        clipImageWindowView.mFrame.centerY())
                // 如果裁剪框大于了图片的最终位置,则需要对图片新的位置进行修正
                M.reset()
                if (winEndState.left < imageEndState.left) {
                    M.postTranslate(winEndState.left - imageEndState.left, 0f)
                }
                if (winEndState.top < imageEndState.top) {
                    M.postTranslate(0f, winEndState.top - imageEndState.top)
                }
                if (winEndState.right > imageEndState.right) {
                    M.postTranslate(winEndState.right - imageEndState.right, 0f)
                }
                if (winEndState.bottom > imageEndState.bottom) {
                    M.postTranslate(0f, winEndState.bottom - imageEndState.bottom)
                }
                M.mapRect(imageEndState)
                startAnimation(ClipImageState(startFrame, clipImageWindowView.mFrame),
                        ClipImageState(imageEndState, winEndState))
                return handled
            }

            if (needToReset) {
                if (startFrame.width() < clipImageWindowView.mFrame.width() ||
                        startFrame.height() < clipImageWindowView.mFrame.height()) {
                    val scale = max(clipImageWindowView.mFrame.width() / startFrame.width(),
                            clipImageWindowView.mFrame.height() / startFrame.height())
                    zoomImageView.onScale(scale, clipImageWindowView.mFrame.centerX(),
                            clipImageWindowView.mFrame.centerY())
                }
                needToReset = false
            }
            startAnimation(ClipImageState(startFrame), ClipImageState(zoomImageView.getResetTransEnd()))
        }
        return handled
    }

还有一个问题,我们在拖动裁剪框的时候,裁剪框可能大于图片的边界,这时候我们需要实时放大一下图片,以适应裁剪框的变化,这里逻辑还有待优化,这显然是个很愚蠢的实现方案,鉴于本渣渣水平有限,优化我会在完成整个库之后统一进行,这里就是给一个思路,即实时更改图片的RectF

override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {
        if (mAnchor != null) {
            clipImageWindowView.onScroll(mAnchor, -distanceX, -distanceY)
            /**
             * 修正图片frame
             */
            if (zoomImageView.getFrame().left > clipImageWindowView.mFrame.left) {
                scaleOffset = zoomImageView.getFrame().width() / (zoomImageView.getFrame().width() - distanceX)
                zoomImageView.onScale(scaleOffset, clipImageWindowView.mFrame.centerX(),
                        clipImageWindowView.mFrame.centerY())
            }
            if (zoomImageView.getFrame().top > clipImageWindowView.mFrame.top) {
                scaleOffset = zoomImageView.getFrame().height() / (zoomImageView.getFrame().height() - distanceY)
                zoomImageView.onScale(scaleOffset, clipImageWindowView.mFrame.centerX(),
                        clipImageWindowView.mFrame.centerY())
            }
            if (zoomImageView.getFrame().right < clipImageWindowView.mFrame.right) {
                scaleOffset = zoomImageView.getFrame().width() / (zoomImageView.getFrame().width() + distanceX)
                zoomImageView.onScale(scaleOffset, clipImageWindowView.mFrame.centerX(),
                        clipImageWindowView.mFrame.centerY())
            }
            if (zoomImageView.getFrame().bottom < clipImageWindowView.mFrame.bottom) {
                scaleOffset = zoomImageView.getFrame().height() / (zoomImageView.getFrame().height() + distanceY)
                zoomImageView.onScale(scaleOffset, clipImageWindowView.mFrame.centerX(),
                        clipImageWindowView.mFrame.centerY())
            }
        } else {
            zoomImageView.onScroll(distanceX, distanceY)
        }
        invalidate()
        return true
    }

至此,整个图片裁剪的主要代码分析已经结束了,大家尽量领会精神,虽然我学的是软件工程,但是我的代码封装和优化还是用的很烂,之后我会在github上传一份代码相对优美,结构相对完整的demo,欢迎大家围观。

 

感兴趣的小伙伴或者希望一起学习Android 相关知识的欢迎加我微信一起玩耍呀!

PS  我就是个小白,第一次尝试写小小的模块,还希望各位大佬多多指教,不喜勿喷(逃

微信号:qbwk43

最后大家可以看看初步效果

http://www.iqiyi.com/w_19s6z4tq69.html

项目github地址:https://github.com/lqy20160609/ImageClip

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值