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)
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章