我需要知道如何在不同的屏幕尺寸上自动调整图像大小。
我的活动中有一个ImageView,我已将其layout_height
和layout_width
指定为50dp。现在我希望图像的大小相对于各种设备的屏幕尺寸/分辨率来升级或缩小,但是它显示的图像大小相同,因此在平板电脑中看起来太小而且恰好在手机。
此外,如果我使用wrap_content
代替宽度和高度,它在手机上看起来太大而且就在平板电脑上。
那么我该怎么做呢?
P.S。我一直在使用Android Emulator Nexus 4(用于手机; 768x1280 xhdpi)和Nexus 9(用于平板电脑; 2048x1563 xhdpi)。
答案 0 :(得分:0)
您必须提供不同屏幕密度的图像才能支持所有设备。使用Android Asset Studio或Image baker或任何其他设计工具生成它们。
然后,您需要将它们移动到资源目录。
res/drawable-mdpi/myimage.png
res/drawable-hdpi/myimage.png
res/drawable-xhdpi/myimage.png
res/drawable-xxhdpi/myimage.png
详细了解Supporting different screens和Designing 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值。