Як додати плаваючу мітку на Spinner


87

Після використання бібліотеки підтримки дизайну Android TextInputLayoutдля розміщення плаваючої мітки над EditTextкомпонентом, мені було цікаво, чи є спосіб додати плаваючу мітку до Spinnerкомпонента (не обов’язково за допомогою бібліотеки дизайну).

Під цим я маю на увазі щось на зразок TextViewрозміщеного над Spinner(очевидно, жодної анімації на зразок TextInputLayout), але я хочу, щоб розмір тексту, шрифт і колір відповідали розміру TextInputLayoutплаваючої мітки .

Наприклад, це може виглядати приблизно так (див. Мітки над Spinners):

введіть тут опис зображення

Як я вже згадував раніше, моєю основною метою є розмітка надпису над Spinner, так само, як і в TextInputLayout- таким чином, розмір тексту, шрифт, колір та відстань між міткою та компонентом будуть однаковими.

На сторінці Google Design про текстові поля з плаваючою етикеткою є діаграма, що показує розміри етикетки щодо компонента, але не вказано кольору та розміру тексту етикетки:

введіть тут опис зображення

Отже, підсумовуючи, я прошу:
- Якщо існує спеціальний компонент для досягнення того, про що я прошу, або спеціальний вигляд, який я можу використовувати, що це буде, і як я можу його використовувати.
- Якщо ні, то який розмір, колір тексту та шрифт плаваючої етикетки, щоб я міг розмістити TextViewнад моїм Spinnerіз розмірами макета, показаними на зображенні вище.


РЕДАГУВАТИ:

З порад Google Design для текстових полів , для плаваючих міток є таке:

Шрифт підказки та введення: Roboto Regular 16sp
Шрифт етикетки: Roboto Regular 12sp
Висота плитки: 72dp Оббивка
тексту вгорі та внизу: 16dp Оббивка
текстового поля: 8dp

а також зображень, показаних вище.

Отже, шрифт плаваючої етикетки: Roboto Regular 12sp . Тому ви можете використовувати a TextViewдля відображення Spinnerетикетки, оскільки я не знаю жодних спеціальних Views або спеціальних компонентів, які ви можете використовувати.

Однак після випробування це виглядає не так добре, як приклад, зображений на зображенні. Можливо, для цього краще підійде спеціальний вигляд , оскільки він може виглядати приємніше, але наведене вище рішення - це лише один із способів досягти чогось близького до того, що я спочатку хотів.

Відповіді:


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.Hintз Бібліотеки підтримки дизайну Google. Однак це, мабуть, буде виглядати трохи дивно, якщо у вас також є позначені EditTextвиди на тому самому екрані.

Нарешті, ви можете поставити TextViewнад вашим Spinner(або будь-яким іншим елементом) із застосованим стилем:

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

Результат

На наступному скріншоті показано простий приклад із двома звичайними TextInputLayoutподаннями, за якими слідують мітка та a Spinner. Я не застосовував додатковий 8dpінтервал для їх подальшого поділу, але це показує, що розмір, шрифт і колір відображаються.

Елементи всередині Spinnerмають різну прокладку, однак я волію зберігати вертикальне вирівнювання з усіма іншими мітками, щоб отримати більш рівномірний вигляд.

введіть тут опис зображення


1
Так, цілком можливо досягти цього без зовнішніх бібліотек. Насправді я використовував той самий підхід при створенні власного подання, яке насправді є складеним видом, що складається зі стилю TextView, Spinner та розділювача. Причиною того, що я створив спеціальний вигляд, було те, що простіше керувати як одним видом в ієрархії макета, замість того, щоб намагатися керувати двома або трьома поданнями.
Farbod Salamat-Zadeh

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

Це, безумовно, найкраще рішення. Це невеликий хакер і дозволяє використовувати стандарт TextInputLayout, таким чином гарантуючи, що ви будете мати точно правильний вигляд.
BoD

3
Просто невелике покращення: використовувати R.layout.support_simple_spinner_dropdown_itemзамістьandroid.R.layout.simple_spinner_item
BoD

Дуже розумний хак. Але це все одно хак.
Севастьян Саванюк

4
Якщо ви використовуєте mTextView.setText(...), ви не отримаєте всіх значень від адаптера у випадаючому adapter.getFilter().filter(null);
списку

також якщо ви встановите текст, ви не можете програмово закрити випадаючий список
Mike6679

34

Я маю суть, розроблену власноруч, щоб вирішити ту саму проблему, що і у вас.

Перевір:

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

Зараз мені не потрібні блешні. Ви все ще будете мати ефект плаваючої етикетки з анімацією.


1
Що саме ви маєте на увазі під словом "Мені не потрібні спінери" , і де у вашому суть ви говорите "Використовується, щоб зробити ваш EditText кращим варіантом, ніж Spinners" ? Чи є інтерфейс просто редагуванням тексту?
Farbod Salamat-Zadeh

Я використовую EditText з TextInput Layout як альтернативу для спінінгів. Коли користувач натискає цей користувацький EditText, я відкриваю діалогове вікно з опціями для вибору. Звичайно, це може бути і краще, і я приймаю будь-які вдосконалення, як-от показати варіанти з іншими видами поглядів, як спінер.
Родріго Енрікес,

1
Я оновлю цю суть проекту github із зразками, тоді я сподіваюся отримати допомогу щодо вдосконалення цього рішення.
Родріго Енрікес,

5
Додайте setInputType(InputType.TYPE_NULL);до onDraw(canvas)методу, щоб вимкнути будь-який вхід у текст редагування. В іншому випадку, наприклад, довгі клацання відкриють контекстне меню і дозволять користувачеві вставляти текст.
Козеріг

1
ну це було приголомшливо, але якщо ви коли-небудь вирішили оновити його до бібліотеки github, обов’язково надайте можливість вибору між EditTextабо AppCompatEditText, будь ласка!
Мухаммед Надері

11

Я створив складний Viewкомпонент, який відображає мітку над Spinner. Текст для мітки можна встановити за допомогою XML або на Java.

Компонент має ключові особливості Spinner( не всіх ), а також схожий на TextInputLayoutкомпонент.

Я назвав його a LabelledSpinner, і він доступний як частина моєї бібліотеки UsefulViews Android на GitHub під ліцензією Apache 2.0 .

Щоб використовувати його, додайте бібліотечну залежність у свій build.gradleфайл:

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

Приклади його використання доступні у сховищі GitHub (як зразок програми, так і посібник із використання).


@LavekushAgrawal Повідомте мене, що саме не працює, або відкрийте питання про репо
Farbod Salamat-Zadeh

1
Насправді це працює, але лейбл не плаває, як edittext
Lavekush Agrawal

@LavekushAgrawal Над цим розміщена маленька наклейка Spinner, подібна до того, як над EditTextкомпонентами є загорнуті маленькі мітки TextInputLayout. Як ви собі уявили?
Farbod Salamat-Zadeh

@ FarbodSalamat-Zadeh Це класна бібліотека для використання, але вона не працює на льодяниках.
Хорхе

2
не працює над gradle 3.5, тільки gradle 2.0 дуже стара бібліотека
Артур Мело


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>

Створіть власний Spinner за допомогою 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"робить цей вигляд недоступним для тих, хто використовує клавіатуру або голос для взаємодії з додатком?
саргас

Я ніколи не використовував клавіатуру або голос для взаємодії з блешнею, але причина, по якій я встановив, 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/


це не
спінер

1
це
спінер

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

        }
    });

якщо у вас є питання, запитайте мене


Ви можете допомогти мені застрягти? у мене є багаторазовий редагувальний текст, тому при створенні фокусу макета переходить до першого edittext, і поки я безпосередньо натискаю вертушку, тому над кодом edittext не отримую фокус. але мені потрібно зосередитись на клацанні спінера, як я можу?
sunita

@sunita, будь ласка, скажіть мені порядок перегляду, тому що коли я намагався, я зміг зосередитись на
спіннері


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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.