Spinner'a kayan etiket nasıl eklenir


88

TextInputLayoutBir EditTextbileşenin üzerine kayan bir etiket yerleştirmek için Android Tasarım Destek Kitaplığı'nı kullandıktan sonra , Spinnerbileşene kayan bir etiket eklemenin bir yolu olup olmadığını merak ediyordum (mutlaka Tasarım Kitaplığı'nı kullanmak zorunda değil).

Bununla, TextViewa'nın üstüne yerleştirilmiş gibi bir şeyi kastediyorum Spinner(tabii ki benzeri animasyon yok TextInputLayout), ancak metin boyutunun, yazı tipinin ve renginin TextInputLayoutkayan etiketininkiyle eşleşmesini istiyorum .

Örneğin, şuna benzer görünecektir (' Spinnerlerin üzerindeki etiketlere bakın ):

görüntü açıklamasını buraya girin

Daha önce de bahsettiğim gibi, asıl amacım Spinner, aynen olduğu gibi üzerinde bir etiket bulundurmak TextInputLayout- yani metin boyutu, yazı tipi, renk ve etiket ile bileşen arasındaki mesafeler aynı olacaktır.

Açık etiket metin alanları yüzen konusunda Google Tasarımı sayfasında , bileşene etiket göreli boyutlarını gösteren bir şekil bulunmaktadır, ancak etiket metni rengi veya boyutu hiçbir belirti yoktur:

görüntü açıklamasını buraya girin

Özetlemek gerekirse, şunu soruyorum:
- İstediğimi elde etmek için özel bir bileşen veya kullanabileceğim özel bir görünüm varsa, bu ne olurdu ve onu nasıl kullanabilirim.
- Değilse, kayan etiket metni boyutu, rengi ve yazı tipi nedir, böylece yukarıdaki resimde gösterilen mizanpaj boyutlarıyla bir TextViewüstüme yerleştirebilirim Spinner.


DÜZENLE:

Gönderen metin alanları için Google Tasarım kurallar , bu yüzen etiketler için aşağıdaki vardır:

İpucu ve giriş yazı tipi: Roboto Normal 16sp
Etiket yazı tipi: Roboto Normal 12sp
Döşeme yüksekliği: 72dp
Metin üst ve alt dolgusu: 16dp
Metin alanı bölücü dolgusu: 8dp

yukarıda gösterilen resimlerin yanı sıra.

Yani kayan etiket yazı tipi şu şekildedir : Roboto Regular 12sp . Bu nedenle, kullanabileceğiniz herhangi bir özel bileşen veya özel bileşen bilmediğim TextViewiçin Spinneretiketi görüntülemek için a Viewkullanabilirsiniz.

Ancak , denedikten sonra, görselde gösterilen örnek kadar iyi görünmüyor. Daha güzel görünebileceğinden özel bir görünüm bunun için daha iyi olabilir, ancak yukarıdaki çözüm, başlangıçta istediğim şeye yakın bir şeyi başarmanın yalnızca bir yoludur.

Yanıtlar:


44

Metin boyutunun, yazı tipinin ve renginin TextInputLayoutkayan etiketininkiyle eşleşmesini istiyorum .

Bu, herhangi bir harici kitaplık olmadan kolayca gerçekleştirilebilir. Bunu kırmaya TextInputLayoutve hatta kendi özel görünümümü oluşturmaya çalıştıktan sonra , basit bir kullanımın TextViewçok daha az kod gerektirdiğini ve muhtemelen daha verimli olduğunu fark ettim .

Metin stili kopyalanabilir gelen AppCompatkütüphanede.

Stil

Materyal Tasarım yönergelerinden aşağıdaki bilgileri alıyoruz:

  • etiketin alt kenar boşluğu olmalıdır 8dp
  • etiket, giriş metni ile dikey olarak hizalanmalıdır

Kılavuzların Materyal hakkında bahsetmediği şeyler EditText:

  • sol dolgusu var 4dp
  • etiketinin üzerinde aslında herhangi bir boşluk yoktur 16dp, bu arayüz tasarımcısına bırakılmıştır: bu mantıklıdır çünkü onu bir başkasının altına yerleştirirseniz EditText, yalnızca ek 8dpbir alana ihtiyacınız olacaktır .

Dahası, Tasarım Destek Kitaplığı odaklanmış bir öğenin etiketi için şu stili içerir:

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

Etkin olmayan öğeler basitçe kullanır TextAppearance.AppCompat.Caption.

Uygulama

Aşağıdakileri dimens.xmldosyanıza ekleyin :

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

Ardından şunu ekleyin 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>

Eğer etiket her zaman vurgulanan (aksan) renge sahip değiştirmek istiyorsanız TextAppearance.AppCompat.Captionile TextAppearance.Design.HintGoogle Tasarım Destek Kütüphanesi'nden. Bununla birlikte, EditTextaynı ekranda görünümleri de etiketlediyseniz, bu muhtemelen biraz garip görünecektir .

Son olarak, stil uygulanmış olarak TextViewkendinizin Spinner(veya başka herhangi bir öğenin) üstüne bir koyabilirsiniz :

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

Sonuç

Aşağıdaki ekran görüntüsü, iki normal TextInputLayoutgörünümün ardından bir etiket ve bir Spinner. 8dpBunları daha fazla ayırmak için ek boşluk uygulamadım , ancak bu size boyut, yazı tipi ve rengin yansıtıldığını gösteriyor.

İçindeki öğelerin Spinnerfarklı bir dolgusu var, ancak daha düzgün bir görünüm elde etmek için diğer tüm etiketlerle dikey hizalamayı tercih ediyorum.

görüntü açıklamasını buraya girin


1
Evet, bunu harici kütüphaneler olmadan gerçekleştirmek tamamen mümkündür. Aslında, özel görünümümü oluştururken aynı yaklaşımı kullandım, bu aslında biçimlendirilmiş TextView, Spinner ve bölücü Görünümden oluşan bir bileşik görünüm. Özel görünümü yapmamın nedeni, iki veya üç görünümü yönetmeye çalışmak yerine, düzen hiyerarşisinde tek bir görünüm olarak yönetmenin daha kolay olmasıdır.
Farbod Salamat-Zadeh

3
<item name="android:textColor">?android:textColorHint</item>Odaklanmamış durumda TextInputLayout'ta kullanılanla aynı metin rengini özel etikette elde etmek için muhtemelen stilinizi eklemek istersiniz .
se.solovyev

"Ancak, aynı ekranda Metni Düzenle görünümlerini de etiketlediyseniz, bu muhtemelen biraz garip görünecektir." ... Spesifik olabilir ve SpinnerLabelbunun yerine stili adlandırabilirsiniz, InputLabelböylece onları yalnızca iplikçiler için kullanırsınız.
Robin Hood

35

Bunu, bir AutoCompleteTextView kullanarak, klavyeyi devre dışı bırakarak ve dokunma seçeneklerini göstererek başardım.

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

Bu, açık ara en iyi çözümdür. Bu küçük bir kesmedir ve standardı kullanmanıza izin verir TextInputLayout, böylece tam olarak doğru görünüme sahip olmanızı sağlar.
BoD

3
Sadece küçük bir artış: kullanım R.layout.support_simple_spinner_dropdown_itemyerineandroid.R.layout.simple_spinner_item
Yönetim Kurulu

Çok akıllıca bir hack. Ama yine de bir hack.
Sevastyan Savanyuk

4
Eğer kullanırsanız mTextView.setText(...), sen aranıyor ... damla menüde adaptörden tüm değerleri almaz adapter.getFilter().filter(null);tekrar tüm önerileri gösterileri
maresmar

ayrıca metni ayarlarsanız, açılır menüyü programlı olarak
kapatamazsınız

34

Sahip olduğunuz problemin aynısını çözmek için kendi başıma oluşturduğum bir öz var.

Bunu kontrol et:

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

Şimdi eğiricilere ihtiyacım yok. Dahil edilen animasyonlarla birlikte kayan etiket efektine sahip olacaksınız.


1
"İplikçilere ihtiyacım yok" ile tam olarak neyi kastediyorsunuz ve özünüzün neresinde "EditText'inizi Spinners'dan daha iyi bir seçenek yapmak için kullanılır" diyorsunuz? Kullanıcı Arayüzü basitçe bir Düzenleme Metni mi?
Farbod Salamat-Zadeh

İplikçiler için bir alternatif olarak TextInput Layout ile EditText kullanıyorum. Kullanıcı bu özel EditText'e tıkladığında, seçim için seçenekler içeren bir iletişim kutusu açarım. Tabii ki daha iyi olabilirdi ve tıpkı spinner gibi seçenekleri başka türden görünümlerle göstermek gibi her türlü gelişmeyi kabul ediyorum.
Rodrigo Henriques

1
Bu özü örneklerle bir github projesine yükselteceğim, ardından bu çözümü geliştirmek için yardım almayı umuyorum.
Rodrigo Henriques

5
Ekle setInputType(InputType.TYPE_NULL);için onDraw(canvas)EDITTEXT içine herhangi bir giriş devre dışı bırakmak için yöntemiyle. Aksi takdirde, örneğin uzun tıklamalar bir bağlam menüsü getirecek ve kullanıcının metni yapıştırmasına olanak sağlayacaktır.
Oğlak

1
bu harikaydı, ancak onu bir github kitaplığına yükseltmeye karar verdiyseniz, EditTextveya arasında seçim yapmak için bir seçenek verdiğinizden emin olun AppCompatEditText, lütfen!
Muhammad Naderi

11

ViewÜzerinde bir etiket görüntüleyen bir bileşik bileşen oluşturdum Spinner. Etiket metni, XML veya Java kullanılarak ayarlanabilir.

Bileşen, bileşene benzer görünmesinin yanı sıra a'nın temel özelliklerine sahiptir Spinner( hepsi değil ) TextInputLayout.

Ona a adını LabelledSpinnerverdim ve Apache 2.0 Lisansı altında GitHub'da UsefulViews Android kitaplığımın bir parçası olarak mevcuttur .

Kullanmak için build.gradledosyanıza kitaplık bağımlılığını ekleyin :

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

Kullanım örnekleri GitHub deposunda (hem örnek bir uygulama hem de bir kullanım kılavuzu) mevcuttur.


@LavekushAgrawal Depoda tam olarak neyin işe yaramadığını veya bir sorunu açmama izin verin
Farbod Salamat-Zadeh

1
Aslında çalışma, ancak etiket EDITTEXT gibi yüzer değil
Lavekush Agrawal

@LavekushAgrawal Bileşenlerin Spinnerüzerinde küçük etiketlerin nasıl EditTextsarılı olduğuna benzer şekilde üzerine yerleştirilmiş küçük bir etiket var TextInputLayout. Nasıl olacağını hayal ettin?
Farbod Salamat-Zadeh

@ FarbodSalamat-Zadeh Bu kullanmak için harika bir kitaplıktır, ancak Lollipop'ta çalışmaz.
Jorge

2
gradle 3.5 üzerinde çalışmıyor, sadece gradle 2.0 çok eski kütüphane
Arthur Melo

6

Bunu başarabilirsiniz: görüntü açıklamasını buraya girin

Bunun gibi yeni Malzeme kitaplığı stilleriyle:

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

daha fazla bilgi için: https://material.io/develop/android/components/menu/


dönen değil
kullanıcı924

2
sadece farklı bir tasarıma sahip bir
iplikçi


5

Bir döndürücü iletişim kutusu açılır penceresini taklit etmek için TextInputLayout ve özel bir DialogFragment (AlertDialog) davranışını kullanan alternatif bir çözümüm var.

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) aracılığıyla Özel Döndürücü Oluşturun

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

Sonuç

TextInputLayout stilindeki değer değiştiriciye tıkladığınızda, seçim listenizi içeren bir uyarı iletişim kutusunu tetikler. Bir seçim seçildiğinde, Metni Düzenle seçiminizle doldurulacak ve etiket istediğiniz gibi yüzecektir.


Does not android:focusable="false"uygulaması ile etkileştiği için klavyeyi veya sesli kullananlar erişilemez bu görüşü yapmak?
sargas

Bir değer değiştirici ile etkileşim için hiç klavye veya ses kullanmadım, ancak ayarlamamın nedeni android:focusable="false", kullanıcının seçim arasında olmayan bir girişi yazamamasıdır. Ne yazık ki, size bildirmek için davranışları test edecek fiziksel bir Android telefonum yok.
Kenny Li

3

İşte benim numaram

iyi şeyler, her şeyin istediğiniz gibi çalışmasıdır.

ancak kötü olan, düzen hiyerarşisini artırması ve koddaki işlevselliği ele almanız gerektiğidir ve bu çirkin bir çözümdür:

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

ve seçilen değerleri saydam yapmak için döndürücü için adaptörü geçersiz kılın

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

ve döndürücüde seçtikten sonra, sadece seçilen metni alın ve EditText olarak ayarlayın; animasyonla aynı etkiye sahip olacaktır

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

        }
    });

Herhangi bir sorunuz varsa bana sorun


sıkışmam için bana yardım eder misin? Birden fazla düzenleme metnim var, bu yüzden oncreate odak noktası ilk edittext'e gidiyor ve doğrudan döndürücüye basarken, edittext kodunun yukarıdaki koduna odaklanmam gerekiyor. ama döndürücü tıklamasına odaklanmam gerekiyor nasıl yapabilirim?
sunita

@sunita lütfen görüş sıramı söyler misiniz, çünkü denediğimde
spinner'a


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>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.