【问题标题】:Android: how to scale a layout with screen sizeAndroid:如何使用屏幕尺寸缩放布局
【发布时间】:2012-12-29 03:31:49
【问题描述】:

考虑一下这个布局(取自here):

我想了解使此布局随屏幕大小缩放的原理。对于正方形,自定义 onMeasure 函数效果很好:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}

下面的自定义切换按钮和图像按钮的宽度和高度应该缩放以填充屏幕的其余部分,减去 layout_margins,并且其中的文本和图像应该缩放以填充按钮,减去填充。外边距也应该缩放。

我的第一个想法是使用相对布局来定位按钮,并使用 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。

【问题讨论】:

    标签: android android-layout android-xml


    【解决方案1】:

    如果您使用“dp”构建视图,基本上,它与 eack 屏幕尺寸的尺寸相同。
    在大多数情况下,您会希望您的视图会根据屏幕大小调整自身大小。
    当然,在大多数情况下,您需要为平板电脑构建单独的布局。
    但是,除此之外,我可以建议您执行以下步骤:

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

    2. 现在在您的布局中,您可以编写这样的视图:

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="I'm scalable!" 
        android:textSize="@dimen/_12sdp"/>
    

    在本例中,您的 TextView 将在每个屏幕尺寸上进行缩放。

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

    【讨论】:

      【解决方案2】:

      这在很大程度上取决于您要创建的自定义 ViewViewGroup 类的数量。我能想到的自定义类数量最少的实现将是这样的(与您所描述的非常相似):

      • 为最大的正方形定制了 FrameLayout,并使用定制的 onMeasure() 实现来匹配高度和可用宽度(您已经提到过这个)。
      • 嵌套LinearLayout 实例使用权重使所有网格按钮大小相同。

      这种方法的最大缺点是效率。您将需要大约 36 个 LinearLayout 实例来在较大的 9x9 网格内创建小的 9x9 网格……这是纯布局开销的 36 个视图。


      就文本大小而言,我可以想到几种方法来处理这个问题。一种方法是使用Paint.measureTextBounds()(您可以获取任何TextViewPaint 对象来进行测量)来确定在测量后需要在每个按钮中制作文本的大小。不幸的是,这将是一个迭代过程,因为Paint 根据当前设置测量给定文本,因此您需要:

      1. 设置文字大小
      2. 测量界限
      3. 检查高度
      4. 重复直到尺寸刚好合适

      好消息是您只需要这样做一次,然后将其应用于所有网格按钮,但您需要等到网格按钮被测量。

      这里的另一个选项是在ImageView 之类的内容中显示图像而不是文本,它可以将内容缩放到它的大小。您可以使用我编写的 TextDrawable 之类的东西将文本内容设置为可缩放而不会损失质量的图像。


      现在回到布局。您可以通过创建自定义ViewGroup 来测量和布置网格来获得大量的效率(名称GridLayout 已经被使用......它并不能完全满足这个目的,所以我们称之为@987654337 @)。创建一个自定义BlockLayout 将允许您测量每个块的大小,并在一个网格中布置9 个子视图,而不是4 个LinearLayout 实例。这与你测量整个正方形的方法基本相同,只是平分。

      然后,您只需 10 个布局开销实例就可以构建整个布局……如果您可以将整个内容编码到单个 ViewGroup 中,则更少。

      基本上,您可以编写越多的代码来扁平化视图层次结构,您的应用程序的整体运行就会越好。

      HTH

      【讨论】:

      • 感谢您的详尽回答!我想我会使用你的 TextDrawable,因为它看起来是迄今为止调整文本大小最方便的方法。但是,我怎样才能将它与按钮一起使用?通常我会使用元素&lt;item name="android:background"&gt;@drawable/myButton&lt;/item&gt; 为按钮制作自定义样式,其中myButton 是一个选择器,每个状态都有形状。但似乎您在 blog post 中使用 TextDrawable 作为 ImageView 的背景,而且我认为视图不能有两个背景。
      • 编辑:在进一步阅读中,我注意到setImageDrawable()setBackgroundDrawable() 之间存在差异。我是否正确假设我应该定位按钮并将其 backgroundDrawable 通过 XML 设置为选择器,然后在 Java 中通过 findViewByID 获取按钮并设置其 imageDrawable成为 TextDrawable?
      • 是的,我建议使用ImageViewImageButton 并将TextDrawable 设置为内容,而不是背景。这是因为您可以使用ScaleType 之类的FIT_CENTER 来获取填充视图空间的文本。使用Button(其内容是纯文本)您不能将内容设置为Drawable,只能设置为背景。另请注意,这样做的一个缺点是您无法在 XML 中定义自定义 Drawable 类型,因此实际上不可能将其添加到样式中。
      • 效果很好!顺便说一句,如果你碰巧有一些关于在模拟器上使用网络摄像头的建议,a question with a bounty 急需关注。
      【解决方案3】:

      为了补充 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);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-10-24
        • 1970-01-01
        • 1970-01-01
        • 2014-12-15
        • 2021-06-21
        • 2014-10-22
        • 1970-01-01
        相关资源
        最近更新 更多