Android自定义View之图片滑动比较控件

2023-07-23  本文已影响0人  寻水的鱼Chock

实现效果类似于: http://thenewcode.com/819/A-Before-And-After-Image-Comparison-Slide-Control-in-HTML5

实际显示效果:


可滑动图片比较控件.png

源码:

class ComparisonImageView : View {
    private val mImageViewA by lazy {
        ImageView(context).apply {
            setImageResource(R.drawable.t1)
            scaleType = ImageView.ScaleType.CENTER_CROP
        }
    }
    private val mImageViewB by lazy {
        ImageView(context).apply {
            setImageResource(R.drawable.t2)
            scaleType = ImageView.ScaleType.CENTER_CROP
        }
    }

    private val mDrawableBar by lazy { resources.getDrawable(R.drawable.ic_hd) }
    private val mDrawableLine by lazy { resources.getDrawable(R.drawable.shape_vertical_line_gradient) }
    private val lineHalfWidth by lazy { 1.dpToPx() }
    private val dp12 by lazy { 12f.dpToPx() }
    private val dp34 by lazy { 34f.dpToPx() }
    private val dp64 by lazy { 64f.dpToPx() }
    private val dp74 by lazy { 114f.dpToPx() }

    var drawMode = 0

    var srcText: String = "美图前"
    var tarText: String = "美图后"
    var textBottomDp = dp12


    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    )

    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyleAttr: Int,
        defStyleRes: Int
    ) : super(context, attrs, defStyleAttr, defStyleRes)

    private val mTextPain by lazy {
        TextPaint().apply {
            color = Color.parseColor("#FFFFFF")
            textSize = 14f.spToPx()
            strokeWidth = 0.9F
            style = Paint.Style.FILL_AND_STROKE
            isAntiAlias = true
            setShadowLayer(3f, 0f, 1f.dpToPx(), Color.parseColor("#80000000"))
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (drawMode == 1) {
            mImageViewB.draw(canvas)
            return
        }
        mImageViewB.draw(canvas)
        canvas.save()
        canvas.clipRect(getLineValue(), 0, width, height)
        mImageViewA.draw(canvas)
        canvas.restore()
        //中线 start
        canvas.save()
        canvas.clipRect(getLineValue() - lineHalfWidth, 0, getLineValue() + lineHalfWidth, height)
        mDrawableLine.setBounds(0, 0, width, height)
        mDrawableLine.draw(canvas)
        canvas.restore()
        //中线 end
        //绘制文字-左边
        if (srcText.isNotBlank() && linePer != 0f) {
            canvas.drawText(srcText, getLineValue() + dp12, height - textBottomDp, mTextPain)
        }
        //绘制文字-右边
        if (tarText.isNotBlank() && linePer != 1f) {
            canvas.drawText(
                tarText,
                getLineValue() - mTextPain.measureText(srcText) - dp12,
                height - textBottomDp,
                mTextPain
            )
        }
        canvas.save()
        canvas.translate(getLineValue() - dp64 / 2, height - dp64 - dp34)
        mDrawableBar.setBounds(0, 0, dp64.toInt(), dp64.toInt())
        mDrawableBar.draw(canvas)
        canvas.restore()
    }

    /**
     * 0 默认  左右滑动对比
     * 1 全部显示处理后
     */
    fun setCompareMode(mode: Int) {
        if (drawMode == mode) return
        drawMode = mode
        postInvalidate()
    }


    var linePer = 0.5f

    private fun getLineValue(): Int {
        return (width * linePer).toInt()
    }

    /**
     * 播放对比效果
     * @param start 起始值
     * @param end 结束值
     * @param duration 动画时间
     */
    fun autoPlayDrawImage(start: Float, end: Float, duration: Long = 1000) {
        postDelayed({
            val va = ValueAnimator.ofFloat(start, end)
            va.interpolator = LinearInterpolator()
            va.addUpdateListener {
                linePer = it.animatedValue as Float
                postInvalidate()
            }
            va.duration = duration
            va.start()
        }, 150)

    }

    var startX = 0f

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        event ?: return false
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                startX = event.rawX
                val lx = getLineValue()
                return (startX > (lx - dp74)) && (startX < (lx + dp74))
            }
            MotionEvent.ACTION_MOVE -> {
                val movx = event.rawX
                val dir = movx - startX
                val lx = getLineValue()
                linePer = (lx + dir) / width
                if (linePer < 0) {
                    linePer = 0f
                } else if (linePer >= 1) {
                    linePer = 1f
                }
                startX = movx
                invalidate()
                return true
            }
            MotionEvent.ACTION_UP -> {

            }
        }
        return true
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        mImageViewA.measure(widthMeasureSpec, heightMeasureSpec)
        mImageViewB.measure(widthMeasureSpec, heightMeasureSpec)
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
        mImageViewA.layout(left, top, right, bottom)
        mImageViewB.layout(left, top, right, bottom)
    }

    internal inline fun String.debugLog() {
        if (BuildConfig.DEBUG) {
            Log.d(ComparisonImageView::class.java.simpleName, this)
        }
    }
}



如果本文对你有帮助就点个赞支持下吧~~~

上一篇 下一篇

猜你喜欢

热点阅读