<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] # 1. 前言 很多時候都需要圖片的縮放效果。在ImageView中就支持這個屬性,比如有下面這個圖像: ![](https://img.kancloud.cn/0b/e0/0be0387aadb4cc933d2327812a501b3e_536x402.png) 其詳細信息為: ![](https://img.kancloud.cn/b7/37/b73729fb40f5cc09b68462e5521a15eb_244x59.png) 但是,我們可以在ImageView中很容易將其載入到一個正方形的ImageView容器中,比如: ~~~ <ImageView android:layout_gravity="center_horizontal" android:layout_marginTop="4dp" android:src="@drawable/a" android:layout_width="200dp" android:layout_height="200dp" android:scaleType="fitCenter" android:background="@drawable/border" /> ~~~ 為了觀察方便,這里為ImageView設置了一個邊框border.xml: ~~~ <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <!--設置邊框顏色--> <stroke android:width="4dp" android:color="@color/teal_700"/> <!--設置填充顏色--> <solid android:color="@android:color/transparent"/> <padding android:left="4dp" android:top="4dp" android:right="4dp" android:bottom="4dp"/> </shape> ~~~ 效果: ![](https://img.kancloud.cn/ee/eb/eeeb4fb533ca5c2fc4cd9ec9e90c63dc_251x214.png) 可見其便捷性。所以這里大致將所遇到的圖片縮放方法做一個總結。 # 2. 方法案例 ## 2.1 使用Bitmap的createScaledBitmap ~~~ class ScaleBitmapDemo: View { constructor(context: Context?) : super(context) {init()} constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs){init()} constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( context, attrs, defStyleAttr ){init()} private lateinit var targetBitmap: Bitmap private lateinit var mPaint: Paint private lateinit var rect: Rect private var startX = 0 private var targetWidth = 0 private var targetHeight = 0 private var paddingSize = 0 private fun init(){ // 關閉硬件加速 setLayerType(LAYER_TYPE_SOFTWARE, null) // 載入圖像 val decodeResource = BitmapFactory.decodeResource(resources, R.drawable.a) // 因為這里沒有裁剪,所以計算一下寬度的縮放值即可 targetWidth = dp2px(200) val scale = targetWidth * 1f / decodeResource.width targetHeight = (decodeResource.height * 1f * scale).toInt() mPaint = Paint(Paint.ANTI_ALIAS_FLAG) mPaint.color = resources.getColor(R.color.teal_700, null) mPaint.style = Paint.Style.FILL // 左邊X坐標 startX = (resources.displayMetrics.widthPixels - targetWidth) / 2 rect = Rect(startX, 300, startX + targetWidth, 300 + targetHeight) paddingSize = dp2px(4) // 從當前存在的位圖,按一定的比例創建一個新的位圖。 targetBitmap = Bitmap.createScaledBitmap(decodeResource, targetWidth - paddingSize * 2, (targetHeight - scale * paddingSize * 5).toInt(), false) } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) canvas?.apply { drawRect(rect, mPaint) drawBitmap(targetBitmap, startX.toFloat() + paddingSize, 300f + paddingSize, mPaint) } } private fun dp2px(value: Int) : Int{ return (resources.displayMetrics.density * value).toInt() } } ~~~ 關鍵部分也就是: ~~~ // 從當前存在的位圖,按一定的比例創建一個新的位圖。 targetBitmap = Bitmap.createScaledBitmap ~~~ 結果: ![](https://img.kancloud.cn/8b/09/8b098ad8d8e75a99eea961b4a6a8eff4_247x190.png) 因為這里沒有裁剪,所以這里保持圖片長方形形狀進行縮放。 ## 2.2 縮放圖片(createScaledBitmap),裁剪畫布 大致思路:首先判斷下圖像的大小和容器的大小,然后進行縮放圖像,需要確保圖像的寬高大于容器的寬高。然后將這個圖像所在的畫布進行裁剪,從中心裁剪出容器大小的圖像即可。代碼如下: ~~~ class ShaderScaleBitmapDemo : View { constructor(context: Context?) : super(context) { init() } constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { init() } constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( context, attrs, defStyleAttr ) { init() } private lateinit var mPaint: Paint private lateinit var mBitmap: Bitmap private lateinit var mRect: Rect private var translateCanvasX = 0f private fun init() { // 關閉硬件加速 setLayerType(LAYER_TYPE_SOFTWARE, null) // 載入圖像 mBitmap = BitmapFactory.decodeResource(resources, R.drawable.a) mPaint = Paint(Paint.ANTI_ALIAS_FLAG) mPaint.color = resources.getColor(R.color.teal_700, null) mPaint.style = Paint.Style.FILL_AND_STROKE // 判斷圖像是否大于容器大小 val imagewidth = dp2px(200 - 4) // 1 表示圖像的寬或者高比容器小,需要放大 // 2 表示圖像大小合適,直接裁剪即可 // 3 表示圖像大小過大,需要縮小 var flag = 1 if (mBitmap.width > imagewidth && mBitmap.height > imagewidth) { if( mBitmap.height - imagewidth < 500 ) flag = 2 else flag = 3 } // 縮放圖像 when(flag){ 1, 3 -> { mBitmap = scaleBitmapImage(mBitmap, imagewidth) } } // 計算裁剪畫布的坐標 val clipRectLeft = (mBitmap.width - imagewidth) / 2 val clipRectTop = (mBitmap.width - imagewidth) / 2 val clipRectRight = left + imagewidth val clipRectBottom = top + imagewidth translateCanvasX = (resources.displayMetrics.widthPixels - imagewidth) * 1f/ 2 // 裁剪畫布的矩形 mRect = Rect(clipRectLeft, clipRectTop, clipRectRight, clipRectBottom) } private fun scaleBitmapImage(bitmap: Bitmap, w: Int): Bitmap { var scale = 1f scale = Math.min(scale, w * 1f / bitmap.width) scale = Math.min(scale, w * 1f / bitmap.height) return createBitmapByOriginAndScaleValue(bitmap, scale) } private fun createBitmapByOriginAndScaleValue(bitmap: Bitmap, scale:Float): Bitmap{ return Bitmap.createScaledBitmap( bitmap, (scale * bitmap.width + 0.5f).toInt(), (scale * bitmap.height + 0.5f).toInt(), false ) } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) canvas?.apply { val saveLayer = saveLayer(0f, 0f, translateCanvasX + mBitmap.width.toFloat(), mBitmap.height.toFloat(), mPaint ) translate(translateCanvasX, 0f) clipRect(mRect) drawBitmap(mBitmap, dp2px(2).toFloat(), dp2px(2).toFloat(), mPaint) restoreToCount(saveLayer) } } private fun dp2px(value: Int): Int { return (resources.displayMetrics.density * value).toInt() } } ~~~ 結果也就是下面的第二個圖像,第一個是上面直接使用ImageView的效果: ![](https://img.kancloud.cn/32/7d/327dc09426168d8a5e60c362ad545bf5_251x383.png) 看著有點像是縮放的大小差不多,但是因為在這個自定義View中沒有處理onMeasure方法,所以這里的容器的寬高是存在問題的,當然,這里不再處理。比如如果我們在使用的時候也指定border.xml: ~~~ <com.weizu.ShaderScaleBitmapDemo android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/border" /> ~~~ 結果: ![](https://img.kancloud.cn/59/c5/59c5a3662cbab35277f5d63f6a3798b8_422x621.png) 很明顯,達不到預期效果。但是這里如果僅僅是縮放和裁剪畫布已經達到的練習效果。之后會就如何自定義View來實現ImageView的效果進行實踐,所以這里不再介紹如何修復這里的bug。 ## 2.3 另一種裁剪方式(createBitmap) 在上面的案例中繼續使用另一種裁剪效果,這里使用: ``` createBitmap(Bitmap source, int x, int y, int width, int height) ``` 而不是裁剪畫布。也就是直接裁剪圖像,source是待裁剪的源圖像,x,y是裁剪位置的坐標,width和height是裁剪的高度。比如在《Android自定義控件開發入門與實戰》一文中使用: ``` Bitmap.createBitmap(src,src.getWidth()/3,src.getHeight()/3, src.getWidth()/3,src.getHeight()/3); ``` 源圖像,其中紅色為輔助線: ![](https://img.kancloud.cn/0d/b5/0db52703351a72d9ed390c7b1330a030_610x505.png) 最后得到的: ![](https://img.kancloud.cn/ba/ba/baba487d4995847d4a54bf079be24c45_294x226.png) 所以這里也可以不裁剪畫布,直接裁剪圖像即可。如下面的代碼: ~~~ private fun init() { // 關閉硬件加速 setLayerType(LAYER_TYPE_SOFTWARE, null) // 載入圖像 mBitmap = BitmapFactory.decodeResource(resources, R.drawable.a) mPaint = Paint(Paint.ANTI_ALIAS_FLAG) mPaint.color = resources.getColor(R.color.teal_700, null) mPaint.style = Paint.Style.FILL_AND_STROKE // 判斷圖像是否大于容器大小 val imagewidth = dp2px(200 - 4) // 1 表示圖像的寬或者高比容器小,需要放大 // 2 表示圖像大小合適,直接裁剪即可 // 3 表示圖像大小過大,需要縮小 var flag = 1 if (mBitmap.width > imagewidth && mBitmap.height > imagewidth) { if( mBitmap.height - imagewidth < 500 ) flag = 2 else flag = 3 } // 縮放圖像 when(flag){ 1, 3 -> { mBitmap = scaleBitmapImage(mBitmap, imagewidth) } } // 計算裁剪畫布的坐標 val clipRectLeft = (mBitmap.width - imagewidth) / 2 val clipRectTop = (mBitmap.width - imagewidth) / 2 val clipRectRight = left + imagewidth val clipRectBottom = top + imagewidth translateCanvasX = (resources.displayMetrics.widthPixels - imagewidth) * 1f/ 2 // 裁剪畫布的矩形 mRect = Rect(clipRectLeft, clipRectTop, clipRectRight, clipRectBottom) } private fun scaleBitmapImage(bitmap: Bitmap, w: Int): Bitmap { var scale = 1f scale = Math.min(scale, w * 1f / bitmap.width) scale = Math.min(scale, w * 1f / bitmap.height) return createBitmapByOriginAndScaleValue(bitmap, scale) } private fun createBitmapByOriginAndScaleValue(bitmap: Bitmap, scale:Float): Bitmap{ return Bitmap.createScaledBitmap( bitmap, (scale * bitmap.width + 0.5f).toInt(), (scale * bitmap.height + 0.5f).toInt(), false ) } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) canvas?.apply { val saveLayer = saveLayer(0f, 0f, translateCanvasX + mBitmap.width.toFloat(), mBitmap.height.toFloat(), mPaint ) clipRect(mRect) drawBitmap(mBitmap, dp2px(2).toFloat(), dp2px(2).toFloat(), mPaint) restoreToCount(saveLayer) } } ~~~ 然后在xml中指定大小和居中: ~~~ <com.weizu.ShaderScaleBitmapDemo android:layout_width="200dp" android:layout_height="200dp" android:layout_gravity="center_horizontal" /> ~~~ 效果: ![](https://img.kancloud.cn/7a/42/7a42cbbeef4fa73ae979c38d18b3c9b8_249x376.png) 主要方法也就是: ~~~ private fun createBitmapByOriginAndScaleValue(bitmap: Bitmap, scale:Float): Bitmap{ return Bitmap.createScaledBitmap( bitmap, // src (scale * bitmap.width + 0.5f).toInt(), // dstWidth (scale * bitmap.height + 0.5f).toInt(), // dstHeight false // filter ) } ~~~ 值得注意的是,在上面的Boolean類型變量filter,這里直接設置為了false。該參數的意義是即是否給圖像添加濾波效果。如果設 置為 true,則能夠減少圖像中由于噪聲引起的突兀的孤立像素點或像素塊。 ## 2.4 使用density來進行圖像縮放 Density 用于表示該Bitmap合適的屏幕dpi,可以分為inDensity和inTargetDensity兩個值,當著兩個值不等的時候,它會縮放圖像。比如:先獲取 Bitmap 的原始 Density,然后將 Density 放大兩倍,這樣在 顯示屏幕分辨率不變的情況下,顯示出來的圖片就應該縮小一半。對應代碼: ~~~ class Scale2BitmapDemo : View { constructor(context: Context?) : super(context) { init() } constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { init() } constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( context, attrs, defStyleAttr ) { init() } private lateinit var mPaint: Paint private lateinit var mBitmap: Bitmap private fun init() { // 關閉硬件加速 setLayerType(LAYER_TYPE_SOFTWARE, null) // 加載圖片 mBitmap = BitmapFactory.decodeResource(resources, R.drawable.lf) mPaint = Paint(Paint.ANTI_ALIAS_FLAG) mPaint.color = resources.getColor(R.color.teal_700, null) mPaint.style = Paint.Style.FILL_AND_STROKE // 縮小圖片,這里使用inDensity // 獲取 Bitmap 的原始 Density,然后將 Density 放大兩倍,這樣在 // 顯示屏幕分辨率不變的情況下,顯示出來的圖片就應該縮小一半。 mBitmap.density *= 2 } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) canvas?.apply { drawBitmap(mBitmap,0f, 0f, mPaint) } } } ~~~ 效果: ![](https://img.kancloud.cn/43/67/43671b8d45f68347b9d9b1f2af18bcc8_225x375.png) 上面為原圖,下面為縮放后的圖像。 需要注意的是:Bitmap 在內存中的尺寸是沒有變化的,這種設置 Bitmap Density 的方式只會影響顯示縮放,而不會改變 Bitmap 本身在內存中的大。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看