Android聊天界面中图片大小的合理缩小算法

应用场景

我们知道在聊天界面中,发送显示图片是不可缺少的一部分,这个时候就会面临对于图片显示控件的缩小处理。当然如果是简单的给ImageView设置一个固定的值的话,这篇文章就没有意义了。我们要做的就是对于ImageView的动态处理。至于缩小怎样的程度,就是这次要探究的点。
先看下效果:

(不用在意图片颜色,是录制软件不好,发到这里压缩后变颜色了,看图片长宽是不是符合你要求0.0)

核心要点
  • 获取网络图片或本地图片的宽高
  • 对于图片长宽的判断
  • 合理地取与屏幕宽高的比值作为ImageView的实际宽高

下面我们来一步一步分析

1. 获取网络图片或本地图片的宽高
实不相瞒,这一步搞了我很久很久的时间,可能是我太菜了,为了获取图片的长宽,我查资料尝试了很多种方法,最终终于找到有效的方法,这里你们也可以作为笔记备忘一下0.0,省得像我这个辣鸡费了这么时间。

获取网络图片的宽高

这里用到了Glide,自打前不久Glide更新之后,许多方法都遗弃了,我踩了不少的坑的,下面这个获取网络图片宽高的方法,还算是有用的,百度的其他许多方法都不适用的,我也没取看Glide源码,所以通过测试找到下面这个方法。

Glide.with(mContext.applicationContext).asBitmap().load(imgUrl).addListener(object : RequestListener<Bitmap> {
            override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
            //获取图片宽高
                val imgWidth = resource?.width
                val imgHeight = resource?.height
            }
             override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Bitmap>?, isFirstResource: Boolean): Boolean {
                return false
            }
}).submit()

就是上面这个注册监听的的方法。在onResourceReady中的参数resource就可以获取网络图片的宽高,同时别忘了最后面的submit(),不加的话是没有作用的!!!

获取本地图片的宽高

这里百度的代码可以用,但是要注意本地路径的类型,你可以先log出来看看,如果是content开头的话,要先用内容提供者获取到具体的路径。如果是file类型就直接可以用啦。
下面代码是对content类型的处理,如果是file可以省略contentresolver那部分。

 val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        var actualFilePath: String? = null
        var cursor: Cursor? = null
        try {
            val proj = arrayOf<String>(MediaStore.Images.Media.DATA)
            cursor = mContext.getContentResolver().query(Uri.parse(pathUrl), proj, null, null, null)
            val column_index: Int = cursor!!.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
            cursor.moveToFirst()
            actualFilePath = cursor.getString(column_index)
        } finally {
            if (cursor != null) {
                cursor.close()
            }
        }
        val bitmap = BitmapFactory.decodeFile(actualFilePath, options)
        //获取图片宽高
        val imgWidth = options.outWidth
        val imgHeight = options.outHeight

2.对于图片长宽的判断
做这一步的原因是因为我们要对于宽比高长宽比高短两种情况的图片做处理,这样才能做到更好的体验。
第一点,宽比高长的图片我们尽量让他保持这样的形态缩小,宽比高短的话高尽量短一些,这样整体来看就会比较舒服。
第二点,为了让图片缩小,我们还要多做一层判断,对于宽(高)小于屏幕宽(高)的图片,我们就让他保持原图大小;而对于大于屏幕宽(高)二分之一的图片,我们才进行合理缩小。

3.合理地取与屏幕宽高的比值作为ImageView的实际宽高
首先,为了让图片大小好看一点,我是按下面两个标准取这个比值的。
第一点,为了让原本图片于屏幕宽高建立关系,我用宽(高)取除于屏幕宽(高),然后去取小数部分。
第二点,对于宽比高长的图片,我让系数控制在0.5到 1.0内,而对于宽比高短的图片,则是控制在0到0.5之间。这么做的原因还是因为手机的屏幕高一般都是很长的0.0

好了,具体的思路就是这样了,本来就是简简单单做个课设而已,但是强迫症不允许我看见这个图片显示的乱七八糟,于是从昨晚到早上花了不少时间,做个笔记记录一下。

完整代码如下

最后在ImageView的外层套一个CardView就可以设置弧度了,这样好看些。0.0

    public static boolean isNetWork(String uri){
        if (uri.toLowerCase().startsWith("http")||uri.toLowerCase().startsWith("rtsp")||uri.toLowerCase().startsWith("mms")){
            return true;
        }
        return false;
    }
    if (FileSizeUtil.isNetWork(mDatas[position].filePath)) {
            zoomOutThePictureFromNet(viewHolder.img, mDatas[position].filePath)
        } else {
            zoomOutThePictureFromLocal(viewHolder.img, mDatas[position].filePath)
        }

    /**
     * 网络图片控件根据屏幕等比例缩小
     */
    fun zoomOutThePictureFromNet(img: ImageView, imgUrl: String) {
        //获取屏幕宽高
        val wm = mContext
                .getSystemService(Context.WINDOW_SERVICE) as WindowManager
        val screenWidth = wm.defaultDisplay.width
        val screenHeight = wm.defaultDisplay.height
        Glide.with(mContext.applicationContext).asBitmap().load(imgUrl).addListener(object : RequestListener<Bitmap> {
            override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
                //获取图片宽高
                val imgWidth = resource?.width
                val imgHeight = resource?.height
                var actualWidth: Int = 0
                var actualHeight: Int = 0
                var z: Float //获取比例值

                //先判断图片长宽哪个长
                if (imgHeight!! > imgWidth!!) {//如果图片长比较长的话
                    //如果图片的长超过屏幕的话
                    if (imgHeight > screenHeight / 2) {
                        val x: Float = (imgHeight / screenHeight).toFloat()
                        val y: Int = imgHeight / screenHeight
                        z = if (x > 1) {
                            x - y
                        } else {
                            x
                        }
                        if (z > 0.5) z = 1 - z  //将z控制在0.5内
                        actualHeight = (z * screenHeight).toInt()
                        actualWidth = (actualHeight.toFloat() / imgHeight.toFloat() * imgWidth.toFloat()).toInt()
                    } else {
                        //长度太长不好看,所以取一半
                        actualHeight = imgHeight / 2
                        actualWidth = imgWidth / 2
                    }
                } else {//如果图片宽比较长
                    //如果图片的宽超过屏幕的话
                    if (imgWidth!! > screenWidth / 2) {
                        val x: Float = (imgWidth.toFloat() / screenWidth.toFloat())
                        val y: Int = imgWidth / screenWidth
                        z = if (x > 1) {
                            x - y
                        } else {
                            x
                        }
                        if (z < 0.5) z = 1 - z  //将z控制在0.5到 1.0
                        actualWidth = (z * screenWidth / 2).toInt()
                        actualHeight = (actualWidth.toFloat() / imgWidth.toFloat() * imgHeight.toFloat()).toInt()
                    } else {
                        actualHeight = imgHeight
                        actualWidth = imgWidth
                    }

                }
                img.post {
                    val param = img.layoutParams
                    param.height = actualHeight
                    param.width = actualWidth
                    img.layoutParams = param
                }

                img.setImageBitmap(resource)
                return true
            }

            override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Bitmap>?, isFirstResource: Boolean): Boolean {
                return false
            }

        }).submit()

    }


    /**
     * 本地图片控件根据屏幕等比例缩小
     */
    fun zoomOutThePictureFromLocal(img: ImageView, pathUrl: String) {
        //获取屏幕宽高
        val wm = mContext
                .getSystemService(Context.WINDOW_SERVICE) as WindowManager
        val screenWidth = wm.defaultDisplay.width
        val screenHeight = wm.defaultDisplay.height

        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        var actualFilePath: String? = null
        var cursor: Cursor? = null
        try {
            val proj = arrayOf<String>(MediaStore.Images.Media.DATA)
            cursor = mContext.getContentResolver().query(Uri.parse(pathUrl), proj, null, null, null)
            val column_index: Int = cursor!!.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
            cursor.moveToFirst()
            actualFilePath = cursor.getString(column_index)
        } finally {
            if (cursor != null) {
                cursor.close()
            }
        }
        val bitmap = BitmapFactory.decodeFile(actualFilePath, options)
        val b = BitmapFactory.decodeFile(actualFilePath)
        //获取图片宽高
        val imgWidth = options.outWidth
        val imgHeight = options.outHeight
        var actualWidth: Int = 0
        var actualHeight: Int = 0
        var z: Float //获取比例值

        //先判断图片长宽哪个长
        if (imgHeight!! > imgWidth!!) {//如果图片长比较长的话
            //如果图片的长超过屏幕的话
            if (imgHeight > screenHeight / 2) {
                val x: Float = (imgHeight.toFloat() / screenHeight.toFloat())
                val y: Int = imgHeight / screenHeight
                z = if (x > 1) {
                    x - y
                } else {
                    x
                }
                if (z > 0.5) z = 1 - z  //将z控制在0.5内
                actualHeight = (z * screenHeight).toInt()
                actualWidth = (actualHeight.toFloat() / imgHeight.toFloat() * imgWidth.toFloat()).toInt()
            } else {
                //长度太长不好看,所以取一半
                actualHeight = imgHeight / 2
                actualWidth = imgWidth / 2
            }
        } else {//如果图片宽比较长
            //如果图片的宽超过屏幕的话
            if (imgWidth!! > screenWidth / 2) {
                val x: Float = (imgWidth.toFloat() / screenWidth.toFloat())
                val y: Int = imgWidth / screenWidth
                z = if (x > 1) {
                    x - y
                } else {
                    x
                }
                if (z < 0.5) z = 1 - z  //将z控制在0.5到 1.0
                actualWidth = (z * screenWidth / 2).toInt()
                actualHeight = (actualWidth.toFloat() / imgWidth.toFloat() * imgHeight.toFloat()).toInt()

            } else {
                actualHeight = imgHeight
                actualWidth = imgWidth
            }
        }
        img.post {
            val param = img.layoutParams
            param.height = actualHeight
            param.width = actualWidth
            img.layoutParams = param
        }

        img.setImageBitmap(b)
    }
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值