Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android的下拉框(二)——AutoCompleteTextView #150

Open
soapgu opened this issue Jul 5, 2022 · 0 comments
Open

Android的下拉框(二)——AutoCompleteTextView #150

soapgu opened this issue Jul 5, 2022 · 0 comments
Labels
problem problem or trouble 安卓 安卓

Comments

@soapgu
Copy link
Owner

soapgu commented Jul 5, 2022

  • 引文

为了还有第二版的的Android下拉框。
原来不是已经写过一篇了

主要Spinner有个致命缺陷
下拉框的高度无法自定义,一旦数据项一多,整个下拉框就飞到上面来了,非常的尴尬
其他缺陷
下拉框图标无法“自定义”,非常的恶心。虽然问题不致命,但是我找了好几天的StackOverflow都无功而返。

  • 横空出世的“AutoCompleteTextView”

是从StackOVerflow里面翻到material里面找出来的
图片

<com.google.android.material.textfield.TextInputLayout
    ...
    style="@style/Widget.MaterialComponents.TextInputLayout.*.ExposedDropdownMenu">

    <AutoCompleteTextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="none"
    />

</com.google.android.material.textfield.TextInputLayout>

从用例分析,使用AutoCompleteTextView就能“替代”Spinner。

所以有的时候就是这么的魔幻!
打败方便面的是外卖
打败数码相机的是智能手机

  • AutoCompleteTextView实现下拉框的功能

首先需要设置 android:inputType="none"
因为是继承了文本框EditText
所有需要禁用输入,只能靠下拉选择来输入

        AutoCompleteTextView autoCompleteTextView = this.findViewById(R.id.autoCompleteText);
        List<String> list = Arrays.asList( "Material", "Design", "Components", "Android" );
        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, list);
        autoCompleteTextView.setAdapter( adapter);

通过设置Adapter来设置下拉数据源,这个和Spinner是一致的。
所以学习Spinner本身不存在“浪费”的问题,还是比较简单的

  • 一揽子Style问题解决

好了,接下来就是最难的样式问题了。

  • 没有好用的IDE
  1. WEB前端有谷歌或者firefox的开发者工具,html dom的属性看的一清二楚,值的来源。还可以直接修改看效果

  2. WPF有Snoop神器,和WEB比也没有差很多
    而安卓只有Layout Inspector,只能看不能改。还不知道值的来源
    图片
    再难也要一个一个解决不是嘛

  3. 从Material选择一个合适的Style

Material的Style主要由一下Part
FilledBox:会有填充色,无框
OutlinedBox:有外框五填充色
Dense:紧凑布局
ExposedDropdownMenu:带下拉框选择器

最后选择, style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
FilledBox会有填充色不好看。

  1. 去掉不必要的边框
    这里需要在TextInputLayout里面把boxStrokeWidth和boxStrokeWidthFocused都设为0dp

  2. 自定义选择器图标
    需要设置app:endIconDrawable为自己的自定义图标
    app:endIconMode="dropdown_menu"这个配置是会自动弹下拉框的配置,如果不设不会弹。但是带“ExposedDropdownMenu”的style已经帮我们设过了
    app:endIconTint是填色,endIconDrawable只是填了一个形状,色彩还要自己画的

  3. 解决下拉框图标和内容间距过大的问题
    这是一个非常头疼的问题。
    图片
    需要在AutoCompleteTextView 里面设置android:drawablePadding="-xxdp"
    设置负值来把图标拉过来减少间距

StackOverflow上找的解决方案

  1. 解决文本部分空隙太大,造成显示不完整换行等一系列问题
    这个也是困扰很久的问题。省去研究过程直接上结果
    Style追踪1:
<style name="Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu">
    <item name="materialThemeOverlay">
      @style/ThemeOverlay.MaterialComponents.AutoCompleteTextView.OutlinedBox
    </item>
    <item name="endIconMode">dropdown_menu</item>
  </style>

<style name="ThemeOverlay.MaterialComponents.AutoCompleteTextView.OutlinedBox">
    <item name="autoCompleteTextViewStyle">
      @style/Widget.MaterialComponents.AutoCompleteTextView.OutlinedBox
    </item>
  </style>

首先我们的内容项也就是AutoCompleteTextView会被设上指定Style
Style追踪2:

<style name="Widget.MaterialComponents.AutoCompleteTextView.OutlinedBox" parent="Base.Widget.MaterialComponents.AutoCompleteTextView"/>
    <style name="Widget.MaterialComponents.AutoCompleteTextView.OutlinedBox.Dense">
    <item name="android:paddingTop">13dp</item>
    <item name="android:paddingBottom">13dp</item>
  </style>

<style name="Base.Widget.MaterialComponents.AutoCompleteTextView" parent="Widget.AppCompat.AutoCompleteTextView">
    <item name="enforceMaterialTheme">true</item>
    <item name="enforceTextAppearance">true</item>
    <item name="android:background">@null</item>
    <item name="android:paddingStart" ns1:ignore="NewApi">16dp</item>
    <item name="android:paddingEnd" ns1:ignore="NewApi">16dp</item>
    <item name="android:paddingLeft">16dp</item>
    <item name="android:paddingRight">16dp</item>
    <!-- Edit text's default text size is 16sp which currently equals to 22dp total line height, so
     we need a total of 34dp to get the 56dp height of the default layout. -->
    <item name="android:paddingTop">17dp</item>
    <item name="android:paddingBottom">17dp</item>
    <item name="android:textAppearance">?attr/textAppearanceSubtitle1</item>
    <item name="android:dropDownVerticalOffset">@dimen/mtrl_exposed_dropdown_menu_popup_vertical_offset</item>
    <item name="android:popupElevation" ns1:ignore="NewApi">@dimen/mtrl_exposed_dropdown_menu_popup_elevation</item>

看到没有
如果加了Dense,紧凑布局的话,android:paddingTop和android:paddingBottom 都是13dp
如果是默认布局,那么android:paddingTop和android:paddingBottom 都是17dp

这就是为啥看上去明明空间是够的,这个文字就是显示不完整。

解决方法也是非常简单粗暴,我们可以直接在AutoCompleteTextView里面把android:paddingTop和android:paddingBottom全部覆写掉。这个和WPF以及Web原理是一样的本地变量的优先级是最高的

  1. 解决下拉框高度设置问题
    这也是我Spinner不能解决的核心问题所在
    在AutoCompleteTextView可以设置
    android:dropDownHeight:可以固定下拉框高度,如果条目过多会有滚动栏
    android:dropDownVerticalOffset:解决垂直距离调整
    android:dropDownHorizontalOffset:解决水平距离调整
  • 完整UI代码

这里AutoCompleteTextView直接换成MaterialAutoCompleteTextView,都一样的就是一个派生类

<com.google.android.material.textfield.TextInputLayout
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
        android:layout_width="105dp"
        android:layout_height="35dp"
        app:endIconDrawable="@drawable/chevron_down"
        app:endIconTint="@color/black"
        app:boxStrokeWidth="0dp"
        app:boxStrokeWidthFocused="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" >
        <com.google.android.material.textfield.MaterialAutoCompleteTextView
            android:id="@+id/autoCompleteText"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:inputType="none"
            android:paddingTop="0dp"
            android:paddingBottom="0dp"
            android:paddingStart="0dp"
            android:paddingEnd="0dp"
            android:dropDownVerticalOffset="0dp"
            android:dropDownHeight="200dp"
            android:drawablePadding="-20dp"
            android:text="中文字符"
            />
    </com.google.android.material.textfield.TextInputLayout>
@soapgu soapgu added 安卓 安卓 problem problem or trouble labels Jul 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
problem problem or trouble 安卓 安卓
Projects
None yet
Development

No branches or pull requests

1 participant