Come aggiungere un'etichetta mobile su Spinner


88

Dopo aver utilizzato Android Design Support Library TextInputLayoutper posizionare un'etichetta mobile sopra un EditTextcomponente, mi chiedevo se esiste un modo per aggiungere un'etichetta mobile al Spinnercomponente (non necessariamente utilizzando la Libreria del progetto).

Con questo intendo qualcosa come un TextViewposto sopra Spinner(ovviamente nessuna animazione come il TextInputLayout), ma voglio che la dimensioneTextInputLayout del testo, il carattere e il colore corrispondano a quelli dell'etichetta mobile di .

Ad esempio, sarebbe simile a questo (vedere le etichette sopra le Spinners):

inserisci qui la descrizione dell'immagine

Come ho detto prima, il mio scopo principale è avere un'etichetta sopra Spinner, proprio come in TextInputLayout- quindi la dimensione del testo, il carattere, il colore e le distanze tra l'etichetta e il componente sarebbero gli stessi.

Nella pagina di Google Design relativa ai campi di testo dell'etichetta mobile , è presente un diagramma che mostra le dimensioni dell'etichetta rispetto al componente, ma non vi è alcuna indicazione del colore o della dimensione del testo dell'etichetta:

inserisci qui la descrizione dell'immagine

Quindi, per riassumere, chiedo:
- Se esiste un componente speciale per ottenere ciò che chiedo o una visualizzazione personalizzata che posso utilizzare, quale sarebbe e come posso utilizzarla.
- In caso contrario, qual è la dimensione, il colore e il carattere del testo dell'etichetta mobile, in modo da poter posizionare un TextViewsopra il mio Spinnercon le dimensioni del layout mostrate nell'immagine sopra.


MODIFICARE:

Dalle linee guida di Google Design per i campi di testo , include quanto segue per le etichette mobili:

Suggerimento e carattere di input: Roboto Regular 16sp Carattere
etichetta: Roboto Regular 12sp
Altezza riquadro: 72dp
Imbottitura superiore e inferiore del
testo : 16dp Imbottitura del divisore del campo di testo : 8dp

così come le immagini mostrate sopra.

Quindi il carattere dell'etichetta mobile è: Roboto Regular 12sp . È quindi possibile utilizzare a TextViewper visualizzare l' Spinneretichetta poiché non sono a conoscenza di Viewcomponenti personalizzati o speciali che si potrebbero utilizzare.

Tuttavia , dopo averlo provato, non sembra buono come l'esempio mostrato nell'immagine. Una visualizzazione personalizzata potrebbe essere migliore per questo , in quanto potrebbe sembrare più bella, ma la soluzione sopra è solo un modo per ottenere qualcosa di simile a quello che volevo inizialmente.

Risposte:


44

Voglio che la dimensioneTextInputLayout del testo, il carattere e il colore corrispondano a quelli dell'etichetta mobile di .

Ciò può essere ottenuto facilmente senza alcuna libreria esterna. Dopo aver tentato di hackerare TextInputLayoute persino creare la mia visualizzazione personalizzata, mi sono reso conto che l'utilizzo di un semplice TextViewrichiede molto meno codice ed è probabilmente più efficiente.

Lo stile del testo può essere copiato dalla AppCompatlibreria.

Lo stile

Dalle linee guida di Material Design otteniamo le seguenti informazioni:

  • l'etichetta dovrebbe avere un margine inferiore di 8dp
  • l'etichetta dovrebbe essere allineata verticalmente con il testo di input

Ecco cosa le linee guida non menzionano riguardo al Materiale EditText:

  • ha un'imbottitura sinistra di 4dp
  • la sua etichetta in realtà non ha alcuna spaziatura 16dpsopra di essa, questa è lasciata al progettista dell'interfaccia: questo ha senso perché se la metti sotto un'altra EditText, avrai solo bisogno di uno 8dpspazio aggiuntivo

Inoltre, la Design Support Library contiene questo stile per l'etichetta di un elemento focalizzato:

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

Gli elementi inattivi usano semplicemente TextAppearance.AppCompat.Caption.

Implementazione

Aggiungi quanto segue al tuo dimens.xmlfile:

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

Quindi aggiungi questo 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>

Se desideri che l'etichetta abbia sempre il colore evidenziato (accento), sostituisci TextAppearance.AppCompat.Captioncon TextAppearance.Design.Hintdalla libreria di supporto per i progetti di Google. Tuttavia, questo probabilmente sembrerà un po 'strano se hai anche EditTextviste etichettate sullo stesso schermo.

Infine, puoi mettere un TextViewsopra il tuo Spinner(o qualsiasi altro elemento) con lo stile applicato:

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

Risultato

Lo screenshot seguente mostra un semplice esempio con due TextInputLayoutvisualizzazioni normali seguite da un'etichetta e un file Spinner. Non ho applicato la 8dpspaziatura aggiuntiva per separarli ulteriormente, ma questo mostra che la dimensione, il carattere e il colore vengono riflessi.

Gli elementi all'interno Spinnerhanno una diversa imbottitura, tuttavia preferisco mantenere l'allineamento verticale con tutte le altre etichette per ottenere un aspetto più uniforme.

inserisci qui la descrizione dell'immagine


1
Sì, è perfettamente possibile ottenere questo risultato senza librerie esterne. In effetti, ho utilizzato lo stesso approccio durante la creazione della mia visualizzazione personalizzata, che in realtà è una visualizzazione composta composta da TextView, Spinner e divisore in stile. Il motivo per cui ho creato la visualizzazione personalizzata era perché è più facile da gestire come una visualizzazione nella gerarchia del layout, invece di provare a gestire due o tre visualizzazioni.
Farbod Salamat-Zadeh

3
Probabilmente vuoi aggiungere il <item name="android:textColor">?android:textColorHint</item>tuo stile per ottenere lo stesso colore del testo nell'etichetta personalizzata utilizzato in TextInputLayout nello stato non focalizzato.
se.solovyev

"Tuttavia, questo probabilmente sembrerà un po 'strano se hai anche etichettato le viste EditText sullo stesso schermo." ... Puoi solo essere specifico e nominare lo stile SpinnerLabelinvece di in InputLabelmodo da usarli solo per i filatori.
Robin Hood

35

Ho ottenuto ciò utilizzando un AutoCompleteTextView, disabilitando la tastiera e mostrando le opzioni al tocco.

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

Questa è di gran lunga la soluzione migliore. Questo è un piccolo trucco e consente di utilizzare lo standard TextInputLayout, assicurandoti così l'aspetto esatto e corretto.
CdA

3
Solo un piccolo miglioramento: utilizzare al R.layout.support_simple_spinner_dropdown_itemposto diandroid.R.layout.simple_spinner_item
CdA

Trucco molto intelligente. Ma è ancora un trucco però.
Sevastyan Savanyuk

4
Se usi mTextView.setText(...), non riceverai tutti i valori dall'adattatore nel adapter.getFilter().filter(null);
menu

inoltre, se imposti il ​​testo, non puoi chiudere il menu a discesa a livello di programmazione
Mike6679

34

Ho un succo fatto da me per risolvere lo stesso problema che hai tu.

Controlla:

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

Ora non ho bisogno di filatori. Avrai ancora l'effetto etichetta mobile con animazioni incluse.


1
Cosa intendi esattamente con "Non ho bisogno di filatori" e dove nella tua sintesi dici "Usato per rendere il tuo EditText un'opzione migliore di Spinner" ? L'interfaccia utente è semplicemente un EditText?
Farbod Salamat-Zadeh

Uso EditText con TextInput Layout come alternativa per i filatori. Quando l'utente fa clic in questo EditText personalizzato, apro una finestra di dialogo con le opzioni da selezionare. Ovviamente potrebbe essere migliore e accetto qualsiasi miglioramento come mostrare le opzioni con altri tipi di visualizzazioni proprio come lo spinner.
Rodrigo Henriques

1
Aggiornerò questo gist in un progetto github con esempi, quindi spero di ottenere aiuto per migliorare questa soluzione.
Rodrigo Henriques

5
Aggiungi setInputType(InputType.TYPE_NULL);al onDraw(canvas)metodo per disabilitare qualsiasi input nell'edittext. Altrimenti, ad esempio, lunghi clic farà apparire un menu contestuale e consentirà all'utente di incollare il testo.
Capricorno

1
beh, è ​​stato fantastico, ma se hai mai deciso di aggiornarlo in una libreria github, assicurati di dare un'opzione tra cui scegliere EditTexto AppCompatEditText, per favore!
Muhammad Naderi

11

Ho creato un Viewcomponente composto che mostra un'etichetta sopra il file Spinner. Il testo per l'etichetta può essere impostato utilizzando XML o in Java.

Il componente ha le caratteristiche chiave di un Spinner( non tutte ) oltre ad essere simile al TextInputLayoutcomponente.

L'ho chiamato LabelledSpinnered è disponibile come parte della mia libreria Android UtileViews su GitHub con la licenza Apache 2.0 .

Per usarlo, aggiungi la dipendenza della libreria nel tuo build.gradlefile:

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

Esempi del suo utilizzo sono disponibili nel repository GitHub (sia un'app di esempio che una guida all'uso).


@LavekushAgrawal Fammi sapere cosa non funziona esattamente o apri un problema nel repo
Farbod Salamat-Zadeh

1
In realtà funziona, ma l'etichetta non è fluttuante come edittext
Lavekush Agrawal,

@LavekushAgrawal C'è una piccola etichetta posizionata sopra Spinner, che è simile a come ci sono piccole etichette sopra i EditTextcomponenti, avvolte TextInputLayout. Come hai immaginato che fosse?
Farbod Salamat-Zadeh,

@ FarbodSalamat-Zadeh Questa è una bella libreria da usare, ma non funziona su Lollipop.
Jorge

2
non funziona su gradle 3.5, solo gradle 2.0 libreria molto vecchia
Arthur Melo


5

Ho una soluzione alternativa che utilizza il comportamento di TextInputLayout e un DialogFragment personalizzato (AlertDialog) per emulare un popup di dialogo di selezione.

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>

Crea una casella di selezione personalizzata tramite 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");
}

Risultato

Quando fai clic sulla casella di selezione in stile TextInputLayout, verrà attivata una finestra di dialogo di avviso contenente l'elenco delle selezioni. Una volta scelta una selezione, EditText verrà popolato con la tua selezione e l'etichetta fluttuerà come desideri.


Non android:focusable="false"rende questa visualizzazione inaccessibile a chi utilizza la tastiera o la voce per interagire con l'app?
sargas

Non ho mai usato la tastiera o la voce per interagire con uno spinner, ma il motivo per cui ho impostato android:focusable="false"è che l'utente non può digitare un input che non è tra la selezione. Sfortunatamente, non ho un telefono Android fisico per testare i comportamenti per farti sapere.
Kenny Li

5

Puoi ottenere questo: inserisci qui la descrizione dell'immagine

Con nuovi stili di libreria di materiali come questo:

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

per maggiori informazioni: https://material.io/develop/android/components/menu/


non è spinner
user924

2
è uno spinner, solo con un design diverso
Amin Keshavarzian

3

Ecco il mio trucco,

la cosa buona è che tutto funzionerà come vuoi,

ma il male è che sta aumentando la gerarchia del layout e devi gestire la funzionalità nel codice, ed è una brutta soluzione:

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

e sostituisci l'adattatore per lo spinner, per rendere trasparenti i valori selezionati

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

e dopo aver selezionato nello spinner, ottieni il testo selezionato e impostalo su EditText e avrà lo stesso effetto con l'animazione

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

        }
    });

se hai qualche domanda chiedimi


puoi aiutarmi a rimanere bloccato? Ho più testo di modifica, quindi la creazione del layout va al primo edittext e mentre sto premendo direttamente il filatore in modo che il codice di edittext sopra non venga messo a fuoco. ma devo concentrarmi sul clic del filatore come posso?
sunita

@sunita puoi dirmi l'ordine della vista, perché quando ci provo sono riuscito a concentrarmi sullo spinner
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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.