归档一个类似ImageView效果的TextureView

有个测试视频可以直接下载:

https://www.w3schools.com/html/mov_bbb.mp4

下面是项目代码,原样抄出来:


/**
 * A TextureView that adapts its scale type based on the screen's aspect ratio.
 * - On tall screens (> 16:9), it behaves like ImageView's "centerCrop".
 * - On wide screens (<= 16:9), it behaves like ImageView's "fitCenter".
 */
class ScalableTextureView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : TextureView(context, attrs, defStyleAttr) {

    companion object {
        private const val TAG = "ScalableTextureView"
    }

    sealed class Mode {
        abstract fun getViewportRect(
            videoWidth: Int,
            videoHeight: Int,
            viewWidth: Int,
            viewHeight: Int
        ): RectF

        data object CenterCrop : Mode() {
            override fun getViewportRect(
                videoWidth: Int,
                videoHeight: Int,
                viewWidth: Int,
                viewHeight: Int
            ): RectF {
                val hRatio = viewHeight.toFloat() / videoHeight.toFloat()
                val wRatio = viewWidth.toFloat() / videoWidth.toFloat()
                val finalRatio = max(hRatio, wRatio)

                val finalViewWidth = videoWidth.toFloat() * finalRatio
                val finalViewHeight = videoHeight.toFloat() * finalRatio

                val centerX = viewWidth / 2F
                val centerY = viewHeight / 2F

                val dstRect = RectF(
                    centerX - finalViewWidth / 2F,
                    centerY - finalViewHeight / 2F,
                    centerX + finalViewWidth / 2F,
                    centerY + finalViewHeight / 2F
                )
                return dstRect
            }
        }

        data object FitCenter : Mode() {
            override fun getViewportRect(
                videoWidth: Int,
                videoHeight: Int,
                viewWidth: Int,
                viewHeight: Int
            ): RectF {
                val hRatio = viewHeight.toFloat() / videoHeight.toFloat()
                val wRatio = viewWidth.toFloat() / videoWidth.toFloat()
                val finalRatio = min(hRatio, wRatio)

                val finalViewWidth = videoWidth.toFloat() * finalRatio
                val finalViewHeight = videoHeight.toFloat() * finalRatio

                val centerX = viewWidth / 2F
                val centerY = viewHeight / 2F

                val dstRect = RectF(
                    centerX - finalViewWidth / 2F,
                    centerY - finalViewHeight / 2F,
                    centerX + finalViewWidth / 2F,
                    centerY + finalViewHeight / 2F
                )
                return dstRect
            }
        }
    }

    private var mVideoWidth = 0
    private var mVideoHeight = 0

    @Volatile
    var mode: Mode = Mode.CenterCrop

    init {
        this.mode = if (screenHeight.toFloat() / screenWidth.toFloat() > 16F / 9F) Mode.CenterCrop else Mode.FitCenter
    }

    fun setVideoSize(videoWidth: Int, videoHeight: Int) {
        if (mVideoWidth != videoWidth || mVideoHeight != videoHeight) {
            this.mVideoWidth = videoWidth
            this.mVideoHeight = videoHeight
            updateTransform()
        }
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        updateTransform()
    }

    private fun updateTransform() {
        if (mVideoWidth == 0 || mVideoHeight == 0) {
            setTransform(null)
            return
        }

        if (width == 0 || height == 0) {
            return
        }

        val dstRect = mode.getViewportRect(mVideoWidth, mVideoHeight, width, height)
        val srcRect = RectF(0f, 0f, width.toFloat(), height.toFloat())

        Log.i(TAG, "transform $srcRect -> $dstRect")

        val matrix = Matrix()
        matrix.setRectToRect(srcRect, dstRect, Matrix.ScaleToFit.FILL)
        setTransform(matrix)
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值