在Android中的ImageView中动态调整图像大小

时间:2018-01-25 19:49:56

标签: android

我需要知道如何在不同的屏幕尺寸上自动调整图像大小。

我的活动中有一个ImageView,我已将其layout_heightlayout_width指定为50dp。现在我希望图像的大小相对于各种设备的屏幕尺寸/分辨率来升级或缩小,但是它显示的图像大小相同,因此在平板电脑中看起来太小而且恰好在手机。 此外,如果我使用wrap_content代替宽度和高度,它在手机上看起来太大而且就在平板电脑上。

那么我该怎么做呢?

P.S。我一直在使用Android Emulator Nexus 4(用于手机; 768x1280 xhdpi)和Nexus 9(用于平板电脑; 2048x1563 xhdpi)。

2 个答案:

答案 0 :(得分:0)

您必须提供不同屏幕密度的图像才能支持所有设备。使用Android Asset StudioImage baker或任何其他设计工具生成它们。

然后,您需要将它们移动到资源目录。

res/drawable-mdpi/myimage.png
res/drawable-hdpi/myimage.png
res/drawable-xhdpi/myimage.png
res/drawable-xxhdpi/myimage.png

详细了解Supporting different screensDesigning for Multiple Screens

答案 1 :(得分:0)

我最近写了类似的东西,它可能不是最好的解决方案,因为它使用布局传递来制作动画,但它适用于我的用例。我需要缩放图像以适应容器,同时保持原始宽高比。这有一个ScaleType,但我还需要跟踪图像的缩放程度,以便我可以将其他点转换为相对于原始图像在缩放图像上正确显示。根据您的使用情况,这可能有点矫枉过正,但这就是我接触它的方式:

用至少2个视图定义你的XML,一个将作为你的ImageView可以填充的最大边界,另一个将是你的ImageView可扩展 - 我很懒,用一个看不见的视图做到这一点(注意我删除了一些视图,因为它们特定于我的项目):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginTop="16dp">

    <!-- This is the ImageView we're setting the bitmap on, that we'll be scaling -->
        <ImageView
            android:id="@+id/image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:scaleType="fitCenter"
            android:layout_centerHorizontal="true"/>


    <!-- Being lazy here and using an invisible view for measuring our max bounds, use RelativeLayouts layout params to bound this appropriately to your use case i.e. layout_above, layout_below, etc -->
    <View
        android:id="@+id/image_max_scale"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="invisible"/>

    <ProgressBar
        android:id="@+id/loading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"/>

</RelativeLayout>

在定义View定义3个rects之后(我需要这些是全局的,你可能不会 - 我也将在Kotlin中提供示例):

private val originalBounds = RectF()
private val maxContainerBounds = RectF()
private val finalBounds = RectF()

创建View后,加载Bitmap并将其设置在ImageView上。在ImageView上设置它之前,将OnPreDrawListener添加到View的ViewTreeObserver。这将允许您获取最大边界框的测量边界,以及ImageView最初设置时的大小(因为我们最初使用的是wrap_content):

            image.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
                override fun onPreDraw(): Boolean {
                    image.getLocalVisibleRect(originalBounds)
                    image_max_scale.getLocalVisibleRect(maxContainerBounds)

                    image.viewTreeObserver.removeOnPreDrawListener(this)
                    image.post {
                        animateImageContainerScale()
                    }
                    return true
                }
            })

            image.setImageBitmap(it)

所以,现在我们的边界有2个Rects,我们可以设置ImageView的动画以适应这些边界:

//Provides getWidth(), setWidth(), getHeight(), setHeight() for property animation
    class BoundListener(w: Int, h: Int) {
        var width: Int = w
        var height: Int = h
    }

private fun animateImageContainerScale() {
    finalBounds.set(originalBounds)

    val scaleMatrix = Matrix()
    scaleMatrix.setRectToRect(originalBounds, maxContainerBounds, Matrix.ScaleToFit.CENTER)
    scaleMatrix.mapRect(finalBounds, originalBounds)

    val valueReceiver = BoundListener(originalBounds.width().toInt(), originalBounds.height().toInt())
    val animator = ObjectAnimator.ofPropertyValuesHolder(valueReceiver,
        PropertyValuesHolder.ofInt("width", finalBounds.width().toInt()),
        PropertyValuesHolder.ofInt("height", finalBounds.height().toInt()))
    animator.addUpdateListener {
        image.layoutParams.width = valueReceiver.width
        image.layoutParams.height = valueReceiver.height
        image.requestLayout()
    }
    animator.setAutoCancel(true)
    animator.start()
}

这应该使ImageView动画化以适应最大范围,或者如果要跳过动画,只需将宽度和高度设置为适当的finalBounds值。