Android:如何根据屏幕大小缩放布局

5
考虑以下布局(从这里拉出):

enter image description here

我希望您能够解释如何使此布局随屏幕大小缩放,对于正方形来说,自定义的onMeasure函数非常有效:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}

以下自定义Togglebuttons和Imagebuttons的宽度和高度应自动缩放以填充屏幕剩余空间(减去layout_margins),按钮内的文本和图像应自动缩放以填充按钮(减去padding)。外边距也应自动缩放。
我的第一个想法是使用相对布局来定位按钮,并使用layout_margin/padding属性创建边距。然而,相对布局和layout_margin/padding需要固定像素值,因此它们不可扩展。
然后我考虑使用嵌套线性布局和layout_weights来定位按钮,并使用占位符视图创建边距。虽然这些技术是可伸缩的,但它们无法与按钮一起使用,因为按钮具有许多属性(文本大小、图像大小、角半径等)需要固定像素值。这个限制意味着,例如,以下xml:
<ToggleButton 
    android:layout_weight="1"
    style="@style/myButton"
    [...] />
<View 
    android:layout_weight="1"/>
<ImageButton 
    android:layout_weight="1"
    style="@style/myButton"
    [...] />

这并不一定会使得两个按钮和它们之间的空间具有相同的宽度。这完全取决于按钮的文本大小、图像大小等等。

我已经查看了this question,但我觉得对于这样一个简单的问题应该有更简单的解决方案,不需要过多使用非XML。

3个回答

7
如果您使用“dp”构建视图,它在每个屏幕大小上基本上是相同的大小。
在大多数情况下,您会希望您的视图按比例自动调整以适应屏幕大小。
当然,在大多数情况下,您需要为平板电脑构建单独的布局。
但是,除此之外,我可以向您推荐执行以下步骤:

1. 将库添加到您的项目中。

2. 现在,在您的布局中,您可以编写如下视图:
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="I'm scalable!" 
    android:textSize="@dimen/_12sdp"/>

在这个例子中,您的TextView将适应每个屏幕尺寸进行缩放。

3. 预览所有屏幕尺寸以查看结果。


4
这在很大程度上取决于您想要创建的自定义ViewViewGroup类的数量。我能想到的最少自定义类的实现方式是这样的(与您描述的非常相似):
  • 用于最大正方形的定制FrameLayout,具有自定义的onMeasure()实现,以将高度匹配到可用宽度(您已经提到了这个)。
  • 使用权重的嵌套LinearLayout实例,以使所有网格按钮大小相同。
这种方法的主要缺点是效率低下。您需要大约36个LinearLayout实例来创建较小的9x9网格,这是36个纯布局开销的视图。
就文本大小而言,我能想到几种处理方法。一种是使用Paint.measureTextBounds()(您可以获取任何TextViewPaint对象来进行测量),以确定在测量后需要使每个按钮中的文本大小。不幸的是,这将是一个有些迭代的过程,因为Paint基于其当前设置来测量给定文本,所以您需要:
  1. 设置文本大小
  2. 测量边界
  3. 检查高度
  4. 重复直到尺寸刚好适合
好消息是,您只需要执行一次此操作,然后将其应用于所有网格按钮,但您需要等待测量网格按钮。
另一种选择是在像ImageView这样的东西内部显示图像而不是文本,它可以自动缩放内容以适应其大小。您可以使用我编写的TextDrawable之类的东西将文本内容设置为可缩放的图像,而无需损失质量。
现在回到布局。通过创建自定义的ViewGroup来测量和布局网格(名称GridLayout已经被使用了...并且它不完全满足此目的,因此我们称其为BlockLayout),您可以获得大量效率。创建自定义的BlockLayout将允许您测量每个块的大小,并在单个父级中以网格形式布置9个子视图,而不是4个LinearLayout实例。这基本上与您测量整个正方形的方式相同,只是平均分割而已。
然后,您可以仅使用10个布局开销的实例构建整个布局...如果您可以将整个内容编写为单个ViewGroup,则甚至可以使用更少的开销。
基本上,您编写的越多的代码来展开视图层次结构,您的应用程序就会运行得越好。

感谢您详细的回答!我想我会使用您的TextDrawable,因为它看起来是最方便调整文本大小的方式。但是,我该如何将其与按钮一起使用呢?通常,我会为按钮制作自定义样式,并添加一个元素<item name="android:background">@drawable/myButton</item>,其中myButton是每个状态的形状选择器。但是,根据您在博客文章中的使用情况,似乎您正在将TextDrawable用作ImageView的背景,而我不认为视图可以有两个背景。 - 1''
编辑:进一步阅读后,我注意到setImageDrawable()setBackgroundDrawable()之间存在差异。 我的理解是,我应该通过XML将按钮定位并设置其backgroundDrawable为选择器,然后在Java中通过findViewByID获取按钮,并将其imageDrawable设置为TextDrawable,这样做对吗? - 1''
是的,我建议使用 ImageViewImageButton 并将 TextDrawable 设置为内容而不是背景。这是因为您可以使用像 FIT_CENTER 这样的 ScaleType 使文本填充视图空间。对于 Button(其内容是纯文本),您无法将内容设置为 Drawable,只能设置背景。还要注意的是,这种方法的一个缺点是您无法在 XML 中定义自定义 Drawable 类型,因此将其添加到样式中并不是真正可能的。 - devunwired
它运行得非常好!顺便说一句,如果你恰好有关于在模拟器中使用网络摄像头的建议,那么这里有一个悬赏问题需要关注:https://dev59.com/fWYr5IYBdhLWcg3wBlzp - 1''

0
为了补充Devnuwired的回答,您可以编写一个类似于以下方法的方法,将他的TextDrawable文本添加到ImageButton中:
private void addText(String text, ImageButton button, int colour) {
    TextDrawable d = new TextDrawable(this);
    d.setText(text);
    d.setTextColor(colour);
    d.setTextAlign(Layout.Alignment.ALIGN_CENTER);
    button.setImageDrawable(d);
}

或者另外一种选择

private void addText(String text, int buttonID, int colour) {
    TextDrawable d = new TextDrawable(this);
    d.setText(text);
    d.setTextColor(colour);
    d.setTextAlign(Layout.Alignment.ALIGN_CENTER);
    ((ImageButton) findViewById(buttonID)).setImageDrawable(d);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接