如何在Spinner上添加浮动标签


87

在使用Android设计支持库TextInputLayoutEditText组件上方放置一个浮动标签之后,我想知道是否有一种方法可以向该Spinner组件添加一个浮动标签(不一定使用设计库)。

这样,我的意思是TextView在上方放置一个Spinner(显然没有像那样的动画TextInputLayout),但是我希望文本大小,字体和颜色与TextInputLayout浮动标签的大小匹配

例如,它看起来像这样(请参阅Spinners上方的标签):

在此处输入图片说明

正如我之前提到的,我的主要目的是SpinnerTextInputLayout-上方有一个标签,就像-一样,因此文本大小,字体,颜色以及标签与组件之间的距离是相同的。

有关浮动标签文本字段Google设计页面上,有一张图表显示了标签相对于组件的尺寸,但没有指示标签文本的颜色或大小:

在此处输入图片说明

因此,总而言之,我在问:
-如果有一个特殊的组件可以实现我所要问的内容或可以使用的自定义视图,它将是什么,以及如何使用它。
-如果不是,什么是浮动标签文字大小,颜色和字体,这样我就可以把一个TextView上面我Spinner用上面的图片中显示的布局尺寸。


编辑:

根据Google设计指南中的文本字段,它具有以下浮动标签:

提示和输入字体:Roboto Regular 16sp
标签字体:Roboto Regular 12sp
瓦片高度:72dp
文本顶部和底部填充:16dp
文本字段分隔符填充:8dp

以及上面显示的图像。

因此,浮动标签字体为:Roboto Regular 12sp。因此,您可以使用aTextView来显示Spinner标签,因为我不知道View可以使用的任何custom或特殊组件。

但是,在尝试之后,它看起来不如图像中所示的示例好。一个自定义视图可能是为了这个美好的,因为它可能看起来更好,但上面的解决方案是实现东西接近我本来想的只是一种方法。

Answers:


44

我希望文字大小,字体和颜色与TextInputLayout浮动标签相匹配

无需任何外部库即可轻松实现。在尝试修改TextInputLayout甚至创建自己的自定义视图之后,我意识到使用简单的TextView代码所需的代码要少得多,而且效率可能更高。

文字样式 可以AppCompat库中复制

风格

从材料设计准则中,我们可以获得以下信息:

  • 标签的下边距应为 8dp
  • 标签应与输入文字垂直对齐

以下是准则中未提及的内容EditText

  • 它的左侧填充为 4dp
  • 它的标签上面实际上没有任何间距16dp,这留给了界面设计者:这是有道理的,因为如果将它放在另一个标签下EditText,则只需要一个额外8dp的空间

此外,设计支持库包含以下样式以用于焦点元素的标签:

<style name="TextAppearance.Design.Hint" parent="TextAppearance.AppCompat.Caption">
    <item name="android:textColor">?attr/colorControlActivated</item>
</style>

非活动元素只需使用 TextAppearance.AppCompat.Caption

实作

将以下内容添加到您的dimens.xml文件中:

<dimen name="input_label_vertical_spacing">8dp</dimen>
<dimen name="input_label_horizontal_spacing">4dp</dimen>

然后添加到styles.xml

<style name="InputLabel" parent="TextAppearance.AppCompat.Caption">
    <item name="android:paddingBottom">@dimen/input_label_vertical_spacing</item>
    <item name="android:paddingLeft">@dimen/input_label_horizontal_spacing</item>
    <item name="android:paddingRight">@dimen/input_label_horizontal_spacing</item>
</style>

如果您希望标签始终具有突出显示的(重点)颜色,请TextAppearance.AppCompat.Caption使用TextAppearance.Design.HintGoogle Design支持库中的替换为。但是,如果您EditText在同一屏幕上也标记了视图,这看起来可能会有些奇怪。

最后,您可以在样式(或其他任何元素)的TextView上方放置一个Spinner

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/category"
    style="@style/InputLabel" />

结果

以下屏幕截图显示了一个简单示例,其中包含两个普通TextInputLayout视图,后跟一个标签和一个Spinner。我没有应用额外的8dp间距来进一步分隔它们,但这向您显示了尺寸,字体和颜色。

内的元素Spinner具有不同的填充,但是我更喜欢与所有其他标签保持垂直对齐,以获得更统一的外观。

在此处输入图片说明


1
是的,无需外部库就可以实现此目标。实际上,我在创建自定义视图时使用了相同的方法,该视图实际上是由样式化的TextView,Spinner和divider视图组成的复合视图。我创建自定义视图的原因是因为在布局层次结构中更易于管理为一个视图,而不是尝试管理两个或三个视图。
Farbod Salamat-Zadeh,2016年

3
您可能想要添加<item name="android:textColor">?android:textColorHint</item>样式,以便在自定义标签中获得与未聚焦状态下TextInputLayout中使用的相同的文本颜色。
se.solovyev

“但是,如果您还在同一屏幕上标记了EditText视图,这看起来可能会有些奇怪。” ... 您可以只具体指定样式,SpinnerLabel而不要命名样式,InputLabel以便仅将其用于微调框。
罗宾汉

35

我通过使用AutoCompleteTextView,禁用键盘并显示触摸选项来实现此目的。

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, getResources().getStringArray(R.array.locations));

AutoCompleteTextView mTextView = (AutoCompleteTextView) findViewById(R.id.location);

mTextView.setAdapter(adapter);
mTextView.setKeyListener(null);
mTextView.setOnTouchListener(new View.OnTouchListener(){
    @Override
    public boolean onTouch(View v, MotionEvent event){
        ((AutoCompleteTextView) v).showDropDown();
        return false;
    }
});

到目前为止,这是最好的解决方案。这是一个小技巧,可以使用standard TextInputLayout,从而确保您拥有正确的外观。
BoD

3
只是一个小改进:使用R.layout.support_simple_spinner_dropdown_item代替android.R.layout.simple_spinner_item
BoD

非常聪明的技巧。但这仍然是一个hack。
Sevastyan Savanyuk '17

4
如果您使用mTextView.setText(...),则不会从下拉菜单中接收到适配器的所有值。调用adapter.getFilter().filter(null);再次显示所有建议
mmrmartin

同样,如果您设置了文本,则无法以编程方式关闭下拉菜单
Mike6679 '18

34

我有一个要点可以解决您遇到的同样问题。

一探究竟:

https://gist.github.com/rodrigohenriques/77398a81b5d01ac71c3b

现在,我不需要微调器。您将仍然具有带有动画的浮动标签效果。


1
“我不需要微调器”的确切含义是什么?在您的要旨中,您说的“用来使EditText比微调器更好的选择”是什么意思?UI仅仅是EditText吗?
Farbod Salamat-Zadeh,2015年

我将EditText与TextInput Layout一起用作微调器。当用户单击此自定义EditText时,我将打开一个对话框,其中包含可供选择的选项。当然,这可能会更好,我接受任何改进,例如使用微调框等其他视图来显示选项。
Rodrigo Henriques

1
我将把这个要点升级为带有示例的github项目,然后希望得到帮助以改进此解决方案。
Rodrigo Henriques 2015年

5
添加setInputType(InputType.TYPE_NULL);到该onDraw(canvas)方法以禁用对edittext的任何输入。否则,例如长时间单击将弹出上下文菜单,并使用户能够粘贴文本。
摩羯座

1
太棒了,但是如果您决定将其升级到github库,请确保提供一个在EditText或中选择的选项AppCompatEditText,请!
穆罕默德·纳德里

11

我创建了一个复合View组件,该组件在的上方显示标签Spinner。标签的文本可以使用XML或Java设置。

该组件的主要功能Spinner并非全部)具有与TextInputLayout组件相似的外观。

我已将其命名为a LabelledSpinner,并且根据Apache 2.0许可,它可以作为GitHub上我的UtilityViews Android库的一部分提供。

要使用它,请在build.gradle文件中添加库依赖项:

compile 'com.satsuware.lib:usefulviews:+'

可以在GitHub存储库中获得其用法示例(示例应用程序和用法指南)。


@LavekushAgrawal让我知道什么根本不起作用或在回购协议上引发问题
Farbod Salamat-Zadeh,2016年

1
实际上它在工作,但是标签不是像edittext一样浮动
Lavekush Agrawal

@LavekushAgrawal在上方有一个小标签Spinner,类似于EditText包裹在中的组件上方的小标签TextInputLayout。您如何想象的?
Farbod Salamat-Zadeh's

@ FarbodSalamat-Zadeh这是一个很酷的库,但是在Lollipop上不起作用。
豪尔赫

2
在gradle 3.5上不起作用,仅在gradle 2.0上非常老的库
Arthur Melo


5

我有一个替代解决方案,它使用TextInputLayout的行为和自定义DialogFragment(AlertDialog)来模拟微调器对话框弹出窗口。

layout.xml:

<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <EditText
        android:id="@+id/your_et"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/your_label"
        android:maxLines="1"
        android:inputType="textNoSuggestions"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        android:focusable="false"
        style="@style/Base.Widget.AppCompat.Spinner.Underlined"/>
</android.support.design.widget.TextInputLayout>

通过DialogFragment创建自定义微调器(AlertDialog)

SpinnerFragment.java:

public class SpinnerFragment extends DialogFragment {

private static final String TITLEID = "titleId";
private static final String LISTID = "listId";
private static final String EDITTEXTID = "editTextId";

public static SpinnerFragment newInstance(int titleId, int listId, int editTextId) {
    Bundle bundle = new Bundle();
    bundle.putInt(TITLEID, titleId);
    bundle.putInt(LISTID, listId);
    bundle.putInt(EDITTEXTID, editTextId);
    SpinnerFragment spinnerFragment = new SpinnerFragment();
    spinnerFragment.setArguments(bundle);

    return spinnerFragment;
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    final int titleId = getArguments().getInt(TITLEID);
    final int listId = getArguments().getInt(LISTID);
    final int editTextId = getArguments().getInt(EDITTEXTID);
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

    try {
        final String[] items = getResources().getStringArray(listId);

        builder.setTitle(titleId)
                .setItems(listId, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int pos) {
                        EditText et = (EditText) getActivity().findViewById(editTextId);
                        String selectedText = items[pos];
                        if (!TextUtils.isEmpty(selectedText)) {
                            et.setText(selectedText);
                        } else {
                            et.getText().clear();
                        }
                    }
                });

    } catch (NullPointerException e) {
        Log.e(getClass().toString(), "Failed to select option in " + getActivity().toString() + " as there are no references for passed in resource Ids in Bundle", e);
        Toast.makeText(getActivity(), getString(R.string.error_failed_to_select), Toast.LENGTH_LONG).show();
    }

    return builder.create();
}

}

Activity.java:

private void addCustomSpinner() {
    EditText yourEt = (EditText) findViewById(R.id.your_et);
    yourEt.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            showCustomSpinnerDialog(view);
        }
    });
}

private void showCustomSpinnerDialog(View v) {
    int titleId = R.string.your_label;
    int listId = R.array.spinner_selections;
    int editTextId = R.id.your_et;
    SpinnerFragment spinnerFragment = SpinnerFragment.newInstance(titleId, listId, editTextId);
    spinnerFragment.show(getFragmentManager(), "customSpinner");
}

结果

单击微调器样式为TextInputLayout的微调器时,它将触发一个警报对话框,其中包含您的选择列表。选择一个选项后,将使用您的选择填充EditText,标签将按照您的需要浮动。


android:focusable="false"使用键盘或语音与应用程序交互的用户是否无法访问此视图?
sargas

我从未使用键盘或语音与微调器互动,但是设置的原因android:focusable="false"是,用户无法键入不在选择范围内的输入。不幸的是,我没有实体的Android手机来测试行为以告知您。
肯尼·李

4

您可以实现: 在此处输入图片说明

使用以下新的材料库样式:

<com.google.android.material.textfield.TextInputLayout
        android:id="@+id/fullNameLay"
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

    <androidx.appcompat.widget.AppCompatAutoCompleteTextView
            android:id="@+id/fullNameEt"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
</com.google.android.material.textfield.TextInputLayout>

有关更多信息:https : //material.io/develop/android/components/menu/


它不是微调器
user924

1
它是一个微调器,仅具有不同的设计
Amin Keshavarzian

3

这是我的把戏

好东西是一切都会按您的意愿运作,

但是不好的是,它正在增加布局层次结构,并且您必须处理代码中的功能,而且这是一个丑陋的解决方案:

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.design.widget.TextInputLayout
            android:id="@+id/til"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/edt"
                android:layout_width="match_parent"
                android:layout_height="@dimen/edt_height"
                android:hint="@string/create_gcc_visa_txt_step" />

        </android.support.design.widget.TextInputLayout>

        <Spinner
            android:id="@+id/spn"
            style="@style/MyAppTheme.Base.Spinner"
            android:layout_height="@dimen/edt_height"
            android:layout_alignBottom="@id/til" />

    </RelativeLayout>

并覆盖微调器的适配器,以使所选值透明

public class MySpinnerAdapter extends SimpleAdapter {
    Context mContext;

    public MySpinnerAdapter(Context context, List<String> data, int resource, String[] from, int[] to) {
        super(context, data, resource, from, to);
        mContext = context;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        convertView = super.getView(position, convertView, parent);

        TextView tv = (TextView) convertView.findViewById(android.R.id.text1);
            tv.setTextColor(ContextCompat.getColor(mContext, R.color.transparent));
        return convertView;
    }
}

在微调器中选择后,只需获取选定的文本并将其设置为EditText,它将与动画具有相同的效果

yourSpinnerView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<String> adapterView, View view, int i, long l) {
            //get your selected text from adapter or from where you want 
            String selectedText = adapterView.getItemAtPosition(i));

            if (i != 0) { 
                edt.setText(selectedText);
            } else { 
                // if in case your spinner have first empty text, 
                // then when spinner selected, just empty EditText.
                edt.setText("");
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    });

如果您有任何问题问我


你能帮助我被卡住吗?我有多个编辑文本,所以布局焦点的oncreate会转到第一个edittext,而直接按Spinner时,则以上edittext代码无法获得焦点。但是我需要集中精力单击Spinner,我该怎么办?
sunita

@sunita您能告诉我视图的顺序吗,因为当我尝试时,我能够专注于微调器
Damir Mailybayev 17-4-20


0

SpinnerCustom.java

package com.pozitron.tfkb.customviews;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.Nullable;
import android.text.SpannableString;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;

import com.pozitron.commons.customviews.TextViewFont;
import com.pozitron.tfkb.R;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * Created by so12607 on 31/01/2018.
 */

public class SpinnerCustom extends LinearLayout {

    @BindView(R.id.layoutSpinnerCustomLabel)
    TextViewFont layoutSpinnerCustomLabel;

    @BindView(R.id.layoutSpinnerCustomSpinner)
    TextViewFont layoutSpinnerCustomSpinner;

    @BindView(R.id.layoutSpinner)
    LinearLayout layoutSpinner;

    private View v;

    public SpinnerCustom(Context context) {
        this(context, null);
    }

    public SpinnerCustom(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);

    }

    public SpinnerCustom(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        v = LayoutInflater.from(context).inflate(R.layout.layout_spinner_custom, this, true);
        ButterKnife.bind(this);

        if (!isInEditMode()) {

            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SpinnerCustom, 0, 0);
            final String label = array.getString(R.styleable.SpinnerCustom_label);
            final boolean enable = array.getBoolean(R.styleable.SpinnerCustom_enabled, true);
            layoutSpinnerCustomLabel.setText(label);

            layoutSpinnerCustomLabel.setEnabled(enable);
            layoutSpinnerCustomSpinner.setEnabled(enable);
            layoutSpinner.setEnabled(enable);
            layoutSpinner.setClickable(enable);
            v.setEnabled(enable);
            v.setClickable(enable);
            array.recycle();
        }
    }

    public void setText(String text) {
        layoutSpinnerCustomSpinner.setText(text);
    }

    public void setText(SpannableString text) {
        layoutSpinnerCustomSpinner.setText(text);
    }

    public void setText(CharSequence text) {
        layoutSpinnerCustomSpinner.setText(text);
    }

    public void setLabel(String text) {
        layoutSpinnerCustomLabel.setText(text);
    }

    public void setError(SpannableString text) {
        layoutSpinnerCustomSpinner.setError(text);
    }

    public void setEnabled(boolean enable) {
        layoutSpinnerCustomLabel.setEnabled(enable);
        layoutSpinnerCustomSpinner.setEnabled(enable);
        layoutSpinner.setEnabled(!enable);
        layoutSpinner.setClickable(!enable);
    }
}

layout_spinner_custom.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layoutSpinner"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <com.pozitron.commons.customviews.TextViewFont
        android:id="@+id/layoutSpinnerCustomLabel"
        style="@style/TextLabel"
        tools:text="label" />

    <com.pozitron.commons.customviews.TextViewFont
        android:id="@+id/layoutSpinnerCustomSpinner"
        style="@style/SpinnerText"
        android:clickable="false" />

</LinearLayout>

style.xml

<style name="TextLabel" parent="android:Widget.TextView">
    <item name="font">@integer/font_GTEestiDisplay_Regular</item>
    <item name="android:layout_width">match_parent</item>
    <item name="android:textSize">14sp</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:gravity">bottom</item>
    <item name="android:textColor">@color/greyLabel</item>
</style>

<style name="SpinnerText" parent="EditText">
    <item name="font">@integer/font_GTEestiDisplay_Medium</item>
    <item name="android:gravity">bottom</item>
    <item name="android:textSize">17sp</item>
    <item name="android:minHeight">35dp</item>
    <item name="android:focusable">false</item>
    <item name="android:background">@drawable/spinner_selector</item>
    <item name="android:text">@string/select</item>
    <item name="android:textColor">@color/selector_spinner_text</item>
</style>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.