Cómo agregar una etiqueta flotante en Spinner

88

Después de usar la biblioteca de compatibilidad de diseño de Android TextInputLayoutpara colocar una etiqueta flotante sobre un EditTextcomponente, me preguntaba si hay una manera de agregar una etiqueta flotante al Spinnercomponente (no necesariamente usando la biblioteca de diseño).

Con esto, me refiero a algo como un TextViewcolocado encima de Spinner(obviamente no hay animaciones como TextInputLayout), pero quiero que el tamañoTextInputLayout del texto, la fuente y el color coincidan con los de la etiqueta flotante de .

Por ejemplo, se vería así (vea las etiquetas sobre las Spinners):

ingrese la descripción de la imagen aquí

Como mencioné antes, mi objetivo principal es tener una etiqueta encima del Spinner, al igual que en el TextInputLayout, por lo que el tamaño del texto, la fuente, el color y las distancias entre la etiqueta y el componente serían los mismos.

En la página de Google Design sobre campos de texto de etiquetas flotantes , hay un diagrama que muestra las dimensiones de la etiqueta en relación con el componente, pero no hay indicación del color o tamaño del texto de la etiqueta:

ingrese la descripción de la imagen aquí

Entonces, para resumir, estoy preguntando:
- Si hay un componente especial para lograr lo que estoy pidiendo o una vista personalizada que pueda usar, cuál sería y cómo puedo usarla.
- Si no es así, ¿cuál es el tamaño, el color y la fuente del texto de la etiqueta flotante, para que pueda colocar una TextViewencima de mi Spinnercon las dimensiones del diseño que se muestran en la imagen de arriba?


EDITAR:

De las pautas de diseño de Google para campos de texto , tiene lo siguiente para etiquetas flotantes:

Sugerencia y fuente de entrada: Roboto Regular 16sp
Fuente de etiqueta: Roboto Regular 12sp
Altura del mosaico: 72dp Relleno
superior e inferior del
texto : 16dp Relleno del divisor del campo de texto: 8dp

así como las imágenes que se muestran arriba.

Entonces, la fuente de la etiqueta flotante es: Roboto Regular 12sp . Por lo tanto, puede usar a TextViewpara mostrar la Spinneretiqueta, ya que no conozco ningún Viewcomponente especial o personalizado que pueda usar.

Sin embargo , después de probarlo, no se ve tan bien como el ejemplo que se muestra en la imagen. Una vista personalizada puede ser mejor para esto , ya que podría verse mejor, pero la solución anterior es solo una forma de lograr algo cercano a lo que quería originalmente.

Farbod Salamat-Zadeh
fuente

Respuestas:

44

Quiero que el tamañoTextInputLayout del texto, la fuente y el color coincidan con los de la etiqueta flotante .

Esto se puede lograr fácilmente sin bibliotecas externas. Después de intentar piratear TextInputLayoute incluso crear mi propia vista personalizada, me di cuenta de que usar un TextViewcódigo simple requiere mucho menos código y probablemente sea más eficiente.

El estilo de texto se puede copiar de la AppCompatbiblioteca.

El estilo

De las pautas de Material Design obtenemos la siguiente información:

  • la etiqueta debe tener un margen inferior de 8dp
  • la etiqueta debe estar alineada verticalmente con el texto de entrada

Esto es lo que las pautas no mencionan sobre el Material EditText:

  • tiene un relleno izquierdo de 4dp
  • su etiqueta en realidad no tiene ningún espacio por 16dpencima, esto se deja al diseñador de la interfaz: esto tiene sentido porque si lo coloca debajo de otra EditText, solo necesitará un 8dpespacio adicional

Además, la Biblioteca de soporte de diseño contiene este estilo para la etiqueta de un elemento enfocado:

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

Los elementos inactivos simplemente se usan TextAppearance.AppCompat.Caption.

Implementación

Agregue lo siguiente a su dimens.xmlarchivo:

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

Luego agregue esto a 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>

Si desea que la etiqueta tenga siempre el color resaltado (acento), reemplácelo TextAppearance.AppCompat.Captioncon TextAppearance.Design.Hintde la Biblioteca de compatibilidad de diseño de Google. Sin embargo, esto probablemente se verá un poco extraño si también tiene EditTextvistas etiquetadas en la misma pantalla.

Finalmente, puede poner un TextViewencima de su Spinner(o cualquier otro elemento) con el estilo aplicado:

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

Resultado

La siguiente captura de pantalla muestra un ejemplo simple con dos TextInputLayoutvistas normales seguidas de una etiqueta y un Spinner. No apliqué el 8dpespaciado adicional para separarlos más, pero esto le muestra que el tamaño, la fuente y el color se reflejan.

Los elementos del interior Spinnertienen un relleno diferente, sin embargo, prefiero mantener la alineación vertical con todas las demás etiquetas para obtener un aspecto más uniforme.

ingrese la descripción de la imagen aquí

Andrea Lazzarotto
fuente
1
Sí, es perfectamente posible lograr esto sin bibliotecas externas. De hecho, utilicé el mismo enfoque al crear mi vista personalizada, que en realidad es una vista compuesta que consta de TextView, Spinner y Divider View con estilo. La razón por la que creé la vista personalizada fue porque es más fácil de administrar como una vista en la jerarquía de diseño, en lugar de intentar administrar dos o tres vistas.
Farbod Salamat-Zadeh
3
Probablemente desee agregar <item name="android:textColor">?android:textColorHint</item>su estilo para obtener el mismo color de texto en la etiqueta personalizada que se usa en TextInputLayout en estado desenfocado.
se.solovyev
"Sin embargo, esto probablemente se verá un poco extraño si también ha etiquetado las vistas EditText en la misma pantalla". ... Puede ser específico y nombrar el estilo en SpinnerLabellugar de InputLabelusarlo solo para hilanderos.
Robin Hood
35

Logré esto usando un AutoCompleteTextView, deshabilitando el teclado y mostrando las opciones al tacto.

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;
    }
});
Sidney Veiga
fuente
Ésta es, con mucho, la mejor solución. Este es un pequeño truco y permite usar el estándar TextInputLayout, asegurando así que tendrá la apariencia correcta exacta.
BoD
3
Solo una pequeña mejora: usar en R.layout.support_simple_spinner_dropdown_itemlugar deandroid.R.layout.simple_spinner_item
BoD
Hack muy inteligente. Pero sigue siendo un truco.
Sevastyan Savanyuk
4
Si lo usa mTextView.setText(...), no recibirá todos los valores del adaptador en el menú desplegable ... La llamada adapter.getFilter().filter(null);muestra nuevamente todas las sugerencias
mmrmartin
Además, si establece texto, no puede cerrar el menú desplegable mediante programación
Mike6679
34

Tengo una esencia hecha por mí mismo para resolver el mismo problema que tienes.

Echale un vistazo:

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

Ahora no necesito hilanderos. Seguirá teniendo efecto de etiqueta flotante con animaciones incluidas.

Rodrigo Henriques
fuente
1
¿Qué quiere decir exactamente con "No necesito hilanderos" , y en qué punto de su esencia dice "Usado para hacer que su EditText sea una mejor opción que Spinners" ? ¿Es la interfaz de usuario simplemente un EditText?
Farbod Salamat-Zadeh
Yo uso EditText con TextInput Layout como alternativa para los hilanderos. Cuando el usuario hace clic en este EditText personalizado, abro un diálogo con opciones para seleccionar. Por supuesto que podría ser mejor y acepto cualquier mejora como mostrar las opciones con otro tipo de vistas como spinner.
Rodrigo Henriques
1
Actualizaré esta esencia en un proyecto de github con muestras y luego espero obtener ayuda para mejorar esta solución.
Rodrigo Henriques
5
Agregue setInputType(InputType.TYPE_NULL);al onDraw(canvas)método para deshabilitar cualquier entrada en el texto de edición. De lo contrario, por ejemplo, los clics largos mostrarán un menú contextual y permitirán al usuario pegar texto.
Capricornio
1
bueno, esto fue increíble, pero si alguna vez decidiste actualizarlo a una biblioteca github, asegúrate de dar una opción para elegir entre EditTexto AppCompatEditText, ¡por favor!
Muhammad Naderi
11

He creado un Viewcomponente compuesto que muestra una etiqueta sobre el Spinner. El texto de la etiqueta se puede configurar mediante XML o en Java.

El componente tiene las características clave de a Spinner( no todas ), además de tener un aspecto similar al TextInputLayoutcomponente.

Lo he nombrado a LabelledSpinner, y está disponible como parte de mi biblioteca de Android UsefulViews en GitHub bajo la licencia Apache 2.0 .

Para usarlo, agregue la dependencia de la biblioteca en su build.gradlearchivo:

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

Los ejemplos de su uso están disponibles en el repositorio de GitHub (una aplicación de muestra y una guía de uso).

Farbod Salamat-Zadeh
fuente
@LavekushAgrawal Déjame saber qué es exactamente lo que no funciona o abre un problema en el repositorio
Farbod Salamat-Zadeh
1
En realidad está funcionando, pero la etiqueta no es flotante como edittext
Lavekush Agrawal
@LavekushAgrawal Hay una pequeña etiqueta colocada sobre el Spinner, que es similar a cómo hay pequeñas etiquetas sobre los EditTextcomponentes, envueltos TextInputLayout. ¿Cómo te lo imaginaste?
Farbod Salamat-Zadeh
@ FarbodSalamat-Zadeh Esta es una biblioteca genial para usar, pero no funciona en Lollipop.
Jorge
2
no funciona en gradle 3.5, solo una biblioteca muy antigua de gradle 2.0
Arthur Melo
5

Tengo una solución alternativa que usa el comportamiento de TextInputLayout y un DialogFragment personalizado (AlertDialog) para emular una ventana emergente de diálogo giratorio.

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>

Crear Spinner personalizado a través de 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");
}

Resultado

Cuando haces clic en el TextInputLayout con estilo de ruleta, se activará un cuadro de diálogo de alerta que contiene tu lista de selecciones. Una vez que se elige una selección, EditText se completará con su selección y la etiqueta flotará como lo desee.

Kenny Li
fuente
¿No android:focusable="false"hace que esta vista sea inaccesible para quienes usan el teclado o la voz para interactuar con la aplicación?
sargas
Nunca he usado el teclado o la voz para interactuar con una ruleta, pero la razón por la que configuré android:focusable="false"es para que el usuario no pueda ingresar una entrada que no esté entre la selección. Desafortunadamente, no tengo un teléfono Android físico para probar los comportamientos y avisarles.
Kenny Li
5

Puedes lograr esto: ingrese la descripción de la imagen aquí

Con nuevos estilos de biblioteca de materiales como este:

<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>

para más información: https://material.io/develop/android/components/menu/

Amin Keshavarzian
fuente
no es spinner
user924
2
es una ruleta, solo que con un diseño diferente
Amin Keshavarzian
3

Aquí está mi truco

lo bueno es que todo saldrá como tu quieres,

pero lo malo es que está aumentando la jerarquía de diseño, y tienes que manejar la funcionalidad en el código, y es una solución fea:

    <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>

y anular el adaptador para spinner, para hacer transparentes los valores seleccionados

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;
    }
}

y después de seleccionar en la ruleta, simplemente obtenga el texto seleccionado y configúrelo en EditText y tendrá el mismo efecto con la animación

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) {

        }
    });

si tienes alguna duda pregúntame

Damir Mailybayev
fuente
¿puedes ayudarme, me estoy atascando? Tengo varios textos de edición, así que una vez creado el enfoque de diseño va al primer texto de edición y mientras estoy presionando directamente la ruleta, el código anterior de texto de edición no se enfoca. pero necesito enfocarme en el clic de la ruleta, ¿cómo puedo?
sunita
@sunita, ¿puedes decirme el orden de la vista, porque cuando lo intento pude concentrarme en la ruleta?
Damir Mailybayev
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>
Samet ÖZTOPRAK
fuente