【问题标题】:Scaling Image doesn't work properly on phone缩放图像在手机上无法正常工作
【发布时间】:2020-05-26 17:10:52
【问题描述】:

我正在尝试画一张背面有图案的扑克牌。我有 1 个尺寸的可绘制对象并以编程方式缩放这些可绘制对象。

它在我的平板电脑(Pixel C,运行 Android 8.1)上完美运行,但卡背面的设计在我的手机(Pixel 3a,运行 Android 10)上无法正常缩放。在 Pixel 3a 上,图像比预期的要大得多,并且不在卡的背面居中。此外,卡片本身似乎可以正常缩放,而不是放在上面的设计。

编辑:这似乎是操作系统级别的问题。我有一个使用 API 29(Android 10,与我的物理手机相同)的模拟 Pixel 3a,它看起来与下面我的物理手机的屏幕截图相同。但是,当我使用 API 27(Android 8.1)创建 Pixel 3a 模拟器时,它看起来就像在运行相同操作系统的平板电脑上一样。任何想法为什么?似乎这是操作系统级别的错误,但我不确定哪个函数包含该问题,或者如何准确重现它。

编辑 2:看起来 API 27 是最后一个显示我希望看到的内容。我尝试了使用 API 28、29 和 R 的模拟器,所有模拟器显示的图像都比我预期的要大得多。

这是我正在运行的代码:

    private fun createImageInImageCenter(context: Context, backgroundBitmap: Bitmap, bitmapToDrawInTheCenter : Bitmap) : Drawable {

        // Figure out width / height
        val resultBitmap = Bitmap.createBitmap(
            backgroundBitmap.width,
            backgroundBitmap.height,
            backgroundBitmap.config
        )

        val scaledCenter = scaleImage(bitmapToDrawInTheCenter, backgroundBitmap.height /2,
            backgroundBitmap.width / 2)

        val canvas = Canvas(resultBitmap)
        // Draw background
        canvas.drawBitmap(backgroundBitmap, Matrix(), Paint())
        // Draw design centered on top
        canvas.drawBitmap(
            scaledCenter,
            ((backgroundBitmap.width - scaledCenter.width) / 2).toFloat(), // left
            ((backgroundBitmap.height - scaledCenter.height) / 2).toFloat(), // top
            Paint()
        )

        return BitmapDrawable(context.resources, resultBitmap)
    }

    private fun scaleImage (image: Bitmap, maxHeight: Int, maxWidth: Int = -1) : Bitmap {
        var ratio = 1f

        if(maxWidth > 0 && image.width > maxWidth)
            ratio = maxWidth.toFloat() / image.width

        if(maxHeight > 0 && (image.height * ratio).roundToInt() > maxHeight)
            ratio = maxHeight.toFloat() / image.height

        val sizeX = (image.width * ratio).roundToInt()
        val sizeY = (image.height * ratio).roundToInt()

        return Bitmap.createScaledBitmap(image, sizeX, sizeY, false)
    }

    fun drawCard() {

        // Resize the card itself
        val cardHeight = context.resources.getDimension(R.dimen.card_max_height)
        val back = scaleImage(context.getDrawable(R.drawable.card_black)!!, cardHeight.toInt())

        // Resize the design on the card
        val image = scaleImage(context.getDrawable(R.drawable.triforce)!!, back.height / 2, back.width / 2)

        pic = createImageInImageCenter(context, back, image)
    }

这是它在平板电脑上的样子:

vs 手机上的样子:

注意:我不知道为什么图片这么大,或者如何在这里缩放它们。

【问题讨论】:

    标签: android kotlin bitmap scale


    【解决方案1】:

    R.dimen.card_max_height 使用的单位是什么?

    是 dp 还是 px? 这很重要,因为如果您使用 px,它可以在具有不同分辨率的不同屏幕上为您提供非常不同的结果。 如果你用过dp,最好用这样的东西

    int px = Math.round(TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP, 14,r.getDisplayMetrics()));
    

    (对不起java版本)

    如果不考虑不同的屏幕尺寸和分辨率,您不能只将其转换为 int。

    还有……我注意到你用过

    context.getDrawable(R.drawable.triforce)!!
    

    我认为在 Kotlin 中不推荐这样做。它击败了 Kotlin 据说已经摆脱了 nullpointerexception,你 应该检查它是否不返回null然后执行操作

    【讨论】:

    • 还要检查单位的 back.height 和 width,如果一切都好并且与最大卡片高度配合得很好
    • R.dimen.card_max_height 在 dp 中。我尝试将其转换为像素(使用与您提供的代码类似的代码),但没有任何区别。
    • 至于null的东西,目前这只是概念验证代码,还没有最终确定。这最终将成为一个变量,我将在最终产品上检查 null。现在硬编码的图像只是一个占位符。
    • 你的回答并没有让我一路找到解决方案,但它确实有帮助,所以我给了你一个赞成票。感谢您将我推向正确的方向!
    【解决方案2】:

    我找到了一种让它工作的方法,部分感谢@mmmcho 的回答,也感谢我在其他地方找到的具有两种转换功能的另一个答案。

        fun convertDpToPixel(context: Context, dp: Float): Float {
            return dp * (context.resources
                .displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
        }
    
        fun convertPixelsToDp(context: Context, px: Float): Float {
            return px / (context.resources
                .displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
        }
    
        private fun createImageInImageCenter(context: Context, background: Drawable, bitmapToDrawInTheCenter : Drawable) : Drawable {
    
            val backgroundBitmap = background.toBitmap()
            // Figure out width / height
            val resultBitmap = Bitmap.createBitmap(
                backgroundBitmap.width,
                backgroundBitmap.height,
                backgroundBitmap.config
            )
    
            val canvas = Canvas(resultBitmap)
    
            // Draw background
            canvas.drawBitmap(backgroundBitmap, Matrix(), Paint())
    
            val scaledCenter = scaleImage(context, bitmapToDrawInTheCenter, resultBitmap.height / 2,
                resultBitmap.width / 2)
    
            // Do conversion from DP to Pixel for API 28+
            if(Build.VERSION.SDK_INT >= 28) {
                // Draw design on top
                canvas.drawBitmap(
                    scaledCenter,
                    (backgroundBitmap.width.toFloat() /2) - convertDpToPixel(context, scaledCenter.width.toFloat() / 2),
                    (backgroundBitmap.height.toFloat() /2) - convertDpToPixel(context, scaledCenter.height.toFloat() / 2),
                    Paint()
            )
            }
            else {
                // Draw design on top
                canvas.drawBitmap(
                    scaledCenter,
                    ((backgroundBitmap.width - scaledCenter.width) / 2).toFloat(), // left
                    ((backgroundBitmap.height - scaledCenter.height) / 2).toFloat(), // top
                    Paint()
                )
            }
    
            return BitmapDrawable(context.resources, resultBitmap)
        }
    
        private fun scaleImage (context : Context, image: Bitmap, maxHeight: Int, maxWidth: Int = -1) : Bitmap {
            var ratio = 1f
    
            // Do conversion from pixels to DP for API 28+
            if(Build.VERSION.SDK_INT >= 28)
            {
                val width = convertPixelsToDp(context, image.width.toFloat())
                val height = convertPixelsToDp(context, image.height.toFloat())
                val newMaxWidth = convertPixelsToDp(context, maxWidth.toFloat())
                val newMaxHeight = convertPixelsToDp(context, maxHeight.toFloat())
    
                if(newMaxWidth > 0 && width > newMaxWidth)
                    ratio = newMaxWidth / image.width
    
                if(newMaxHeight > 0 && (height * ratio).roundToInt() > newMaxHeight)
                    ratio = newMaxHeight / image.height
            }
            else {
                if (maxWidth > 0 && image.width > maxWidth)
                    ratio = maxWidth.toFloat() / image.width
    
                if (maxHeight > 0 && (image.height * ratio).roundToInt() > maxHeight)
                    ratio = maxHeight.toFloat() / image.height
            }
    
            val sizeX = (image.width * ratio).roundToInt()
            val sizeY = (image.height * ratio).roundToInt()
    
            return Bitmap.createScaledBitmap(image, sizeX, sizeY, false)
        }
    
        fun drawCard() {
            val back = context.getDrawable(R.drawable.card_black)!!
    
            // Image to draw on the back
            val image = context.getDrawable(R.drawable.triforce)!!
    
            pic = createImageInImageCenter(context, back, image)
        }
    

    花了很多时间来弄清楚需要转换什么,以及需要转换哪种方式,但我想通了:-)

    【讨论】:

      猜你喜欢
      • 2013-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-12
      • 1970-01-01
      相关资源
      最近更新 更多