【问题标题】:Customizing spinners' spacing自定义微调器的间距
【发布时间】:2014-11-22 12:12:03
【问题描述】:

微调器提供两种状态。第一个默认状态 (state A) 显示当前选择的值。第二个(状态 B)在触摸微调器显示屏时显示一个下拉菜单。

默认情况下,向状态 A 和 B 中显示的项目添加左填充。我想在显示当前选定值时将其删除(状态 A),但在显示项目时保留它显示在下拉菜单中(状态 B)。

由于填充是使用在创建微调器时指定的布局中使用的 CheckedTextView 设置的,所以我的第一次尝试是向微调器构造函数传递一个自定义布局,其中包含一个空的 CheckedTextView填充。这样,左侧填充在状态 A 和状态 B 中都消失了。但是,我的目标是为状态 A 保留它。

我的第二次尝试是在我的主题定义中自定义 android:dropDownSpinnerStyle。由于更改 android:dropDownSpinnerStyle 的背景颜色只会更改状态 A 中项目的背景颜色,因此我的想法是用负值覆盖 marginLeft 或 paddingLeft。不幸的是,它没有效果。

鉴于似乎没有考虑负边距/填充,我尝试了相反的方法。首先,我使用了自定义项目布局(正如我第一次尝试所解释的那样),以便删除两个状态(A 和 B)上的左填充。其次,我为属性 android:dropDownListViewStyle 定义了一个自定义样式。不幸的是,对 last 属性使用正的 marginLeft 值没有任何效果。因此,我设置了 paddingLeft。它有效,并允许我仅获得状态 B 的左侧间距。但是,左侧空间也适用于背景触摸颜色(参见下图)。

我认为如果我想要完全填充下拉菜单宽度的触摸背景颜色,则只应更改状态 A 的样式。欢迎任何想法、建议或示例。

下面是我第三次尝试的主题定义:

<style name="Theme.App.Base" parent="Theme.App">
    ...
    <item name="android:dropDownListViewStyle">@style/Widget.Spinner.DropDown.ListView</item>
</style>

<style name="Widget.Spinner.DropDown.ListView" parent="Widget.AppCompat.ListView.DropDown">
    <item name="android:paddingLeft">16dp</item>
</style>

【问题讨论】:

标签: android android-layout drop-down-menu android-spinner android-appcompat


【解决方案1】:

状态 A 采用以下样式:

// Theme (Base) // Theme.AppCompat
@android:style/Widget.TextView.SpinnerItem

// Holo & Holo Light
@android:style/Widget.Holo.TextView.SpinnerItem

这里的属性是spinnerItemStyle

此外,提供的填充不是 paddingLeft,而是 paddingStart - 以支持 LTR 和 RTL 语言。同样,设置paddingEnd 而不是paddingRight。此信息适用于 API >=17。

如果您使用 AppCompat,您仍将覆盖 spinnerItemStyle 属性,但提供 paddingLeftpaddingRight

例子:

<style name="Theme.App.Base" parent="Theme.App">
...
    <item name="android:spinnerItemStyle">@style/TextViewSpinnerItem</item>
</style>

<style name="TextViewSpinnerItem" parent="@android:style/Widget.TextView.SpinnerItem">
    <item name="android:paddingLeft">40dp</item>
    <item name="android:paddingRight">40dp</item>
</style>

40dp 值用于测试设置此样式是否有效。这应该只填充State A(40dp),留下State B的默认填充8dp。确认后,您可以0dp,或根据您的要求。

这是我得到的结果:

更新:

参考示例项目-MainActivity:

spinner.setAdapter(ArrayAdapter.createFromResource(this,
            R.array.planets_array, android.R.layout.simple_spinner_item));

通过给适配器android.R.layout.simple_spinner_item,您告诉它状态A和状态B都使用布局。这是一个问题,因为这种布局的定义方式:

<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@android:id/text1"
    style="?android:attr/spinnerItemStyle"
    android:singleLine="true"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="marquee"
    android:textAlignment="inherit"/>

注意style 应用于此TextView。早些时候,我曾建议您覆盖此属性。它奏效了。但由于这两种状态都使用了这种布局,所以结果并不理想。

事实上,上面的陈述(虽然目前没有做任何事情)更有希望:

ArrayAdapter.createFromResource(this,
            R.array.planets_array, android.R.layout.simple_spinner_item)
            .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

通过使用setDropDownViewResource(int),您将允许引入不同的样式属性。在这种情况下,状态 A 将由 android.R.layout.simple_spinner_item 表示,状态 B 将使用 android.R.layout.simple_spinner_dropdown_item

我们来看看android.R.layout.simple_spinner_dropdown_item

<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    style="?android:attr/spinnerDropDownItemStyle"
    android:singleLine="true"
    android:layout_width="match_parent"
    android:layout_height="?android:attr/dropdownListPreferredItemHeight"
    android:ellipsize="marquee"/>

现在我们可以覆盖另一个属性 - spinnerDropDownItemStyle - 并给状态 B 一个完全不同的外观。但是,我们不会。在 Lollipop 上,spinnerDropDownItemStyle 指向样式Widget.Material.DropDownItem.Spinner,它将paddingX 设置为8dp。你说你对状态 B 的默认填充没问题。

所以,这就是你需要的:

// Create an ArrayAdapter
ArrayAdapter<CharSequence> mAdapter = ArrayAdapter.createFromResource(this,
            R.array.planets_array, android.R.layout.simple_spinner_item);

// State B
mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

并且,如果您还没有,请将其添加到 values/styles.xml:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:spinnerItemStyle">@style/TextViewSpinnerItem</item>
</style>

<style name="TextViewSpinnerItem" parent="@android:style/Widget.TextView.SpinnerItem">
    <item name="android:paddingLeft">0dp</item>
    <item name="android:paddingRight">0dp</item>
</style>

您还应该创建values-v21/styles.xml 并添加:

<style name="TextViewSpinnerItem" parent="@android:style/Widget.Material.TextView.SpinnerItem">
    <item name="android:paddingLeft">0dp</item>
    <item name="android:paddingRight">0dp</item>
</style>

【讨论】:

  • 感谢您的帮助。不幸的是,您的示例在应用于 Android Lollipop 时会更新状态 A 和 B。
  • @Laurent 我添加了我尝试过的代码的屏幕截图。该代码在 Genymotion Lollipop 预览模拟器中运行。我不确定为什么它对您不起作用。你的基本主题是什么?你能发布你styles.xml的所有相关部分吗?
  • 我创建了一个简单的项目来重现该问题。 styles.xml 可在github.com/lpellegr/android-spinner-styling-issue/blob/master/… 获得
  • @Laurent 感谢您上传示例项目。我试图解释上面的问题。我希望它可以帮助您解决问题。
  • 因为您正在对 spinnerItemStyle 继承的主题进行硬编码,所以我认为通常最好只提供自定义布局资源来替换 simple_spinner_item,除非您希望它在所有版本中看起来完全相同支持(在这种情况下,您可能已经定义了整个自定义主题)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-13
  • 2012-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多