Spinner에 플로팅 라벨을 추가하는 방법


87

Android 디자인 지원 라이브러리를 사용하여 구성 요소 TextInputLayout위에 부동 레이블을 배치 한 후 EditText구성 요소에 부동 레이블을 추가하는 방법이 있는지 궁금합니다 Spinner(반드시 디자인 라이브러리를 사용하지 않음).

이것은 TextView위에 배치 된 것과 같은 것을 의미 하지만 Spinner(분명히와 같은 애니메이션이 없음 TextInputLayout) 텍스트 크기, 글꼴 및 색상이 TextInputLayout의 부동 레이블 과 일치하기를 원합니다 .

예를 들어, 다음과 같이 보입니다 ( Spinners 위의 레이블 참조 ).

여기에 이미지 설명 입력

내가 전에 언급 한 바와 같이, 내 주요 목표는 위의 레이블을하는 것입니다 Spinner단지 같이 TextInputLayout- 동일 할 것입니다 텍스트 크기, 글꼴, 색상 및 라벨과 구성 요소 사이의 거리 때문에.

온 레이블 텍스트 필드를 떠에 대한 구글 설계 페이지 구성 요소에 레이블의 상대 크기를 나타내는 도면이 있지만 레이블 텍스트의 색상이나 크기의 표시가 없습니다 :

여기에 이미지 설명 입력

요약하자면 다음과 같이 질문합니다
.-내가 요청한 내용을 달성하기위한 특수 구성 요소가 있거나 사용할 수있는 사용자 정의보기가 있다면 무엇이며 어떻게 사용할 수 있습니까?
-그렇지 않은 경우 플로팅 라벨 텍스트 크기, 색상 및 글꼴은 무엇입니까? 위 이미지에 표시된 레이아웃 치수 로 TextView위에 배치 할 수 있습니다 Spinner.


편집하다:

로부터 텍스트 필드에 대한 구글 디자인 가이드 라인 , 그것은 부동 라벨에 대해 다음이 있습니다 :

힌트 및 입력 글꼴 : Roboto Regular 16sp
라벨 글꼴 : Roboto Regular 12sp
타일 ​​높이 : 72dp
텍스트 상단 및 하단 패딩 : 16dp
텍스트 필드 구분선 패딩 : 8dp

위에 표시된 이미지뿐만 아니라.

따라서 부동 레이블 글꼴은 Roboto Regular 12sp 입니다. 따라서 사용할 수 있는 사용자 정의 또는 특수 구성 요소를 알지 못 하므로 a TextView를 사용 하여 Spinner레이블 을 표시 View할 수 있습니다.

그러나 시도한 후에는 이미지에 표시된 예만큼 좋아 보이지 않습니다. 사용자 지정보기는 더 나은이에있을 수 는 더 좋은 볼 수 있기 때문에,하지만, 위의 솔루션은 내가 원래 원했던 뭔가 가까이를 달성 한 방법입니다.

답변:


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구글 설계 지원 라이브러리에서. 그러나 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 및 구분선보기로 구성된 복합보기 인 사용자 지정보기를 만들 때 동일한 접근 방식을 사용했습니다. 사용자 지정보기를 만든 이유는 2 ~ 3 개의보기를 관리하는 대신 레이아웃 계층 구조에서 하나의보기로 관리하는 것이 더 쉽기 때문입니다.
— Farbod Salamat-Zadeh

3
<item name="android:textColor">?android:textColorHint</item>포커스되지 않은 상태에서 TextInputLayout에 사용 된 것과 동일한 텍스트 색상을 사용자 정의 레이블에 가져 오기 위해 스타일 을 추가 할 수 있습니다.
— se.solovyev

"하지만 같은 화면에서 EditText 뷰에 레이블을 붙인 경우에는 아마 약간 이상하게 보일 것입니다." ... 당신은 특정하고 스타일 이름을 지정할 수 있습니다 SpinnerLabel대신 InputLabel당신은 단지 스피너을 위해 그들을 사용하도록.
— Robin Hood

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

아주 영리한 해킹. 그러나 여전히 해킹입니다.
— Sevastyan Savanyuk 2011

4
을 사용 mTextView.setText(...)하면 드롭 다운에서 어댑터의 모든 값을받지 못합니다 ... Calling adapter.getFilter().filter(null);은 모든 제안을 다시 표시합니다.
— mmrmartin

텍스트를 설정 또한, 당신은 다음 닫지 드롭 다운 프로그래밍 할 수
— Mike6679

34

나는 당신이 가진 것과 같은 문제를 해결하기 위해 스스로 만든 요지를 가지고 있습니다.

확인 해봐:

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

이제 스피너가 필요하지 않습니다. 애니메이션이 포함 된 플로팅 레이블 효과는 계속 유지됩니다.


1
"스피너가 필요하지 않습니다" 란 정확히 무엇을 의미하며 " EditText를 스피너보다 더 나은 옵션으로 만드는 데 사용됨" 이라고 말하는 요점은 무엇입니까? UI는 단순히 EditText입니까?
— Farbod Salamat-Zadeh

스피너의 대안으로 TextInput Layout과 함께 EditText를 사용합니다. 사용자가이 사용자 정의 EditText를 클릭하면 선택할 수있는 옵션이있는 대화 상자가 열립니다. 물론 더 나을 수 있으며 스피너와 같은 다른 종류의 뷰로 옵션을 표시하는 것과 같은 개선 사항을 수락합니다.
— Rodrigo Henriques

1
이 요점을 샘플이있는 github 프로젝트로 업그레이드 한 다음이 솔루션을 개선하는 데 도움을 받기를 바랍니다.
— Rodrigo Henriques 2015 년

5
추가 setInputType(InputType.TYPE_NULL);받는 onDraw(canvas)글고 치기로 모든 입력을 해제하는 방법. 그렇지 않으면 예를 들어 길게 클릭하면 상황에 맞는 메뉴가 나타나고 사용자가 텍스트를 붙여 넣을 수 있습니다.
— Capricorn

1
이건 굉장했지만 github 라이브러리로 업그레이드하기로 결정한 적이 있다면 EditText또는 중에서 선택할 수있는 옵션을 제공 AppCompatEditText하십시오.
— Muhammad Naderi

11

View위에 레이블을 표시 하는 복합 구성 요소를 만들었습니다 Spinner. 레이블의 텍스트는 XML 또는 Java를 사용하여 설정할 수 있습니다.

구성 요소에는 Spinner( 모두 는 아님) 의 주요 기능이 있으며 TextInputLayout구성 요소 와 비슷해 보입니다 .

이름을으로 지정 했으며 Apache 2.0 라이선스에 따라 GitHub의 UsefulViews Android 라이브러리의 LabelledSpinner일부로 사용할 수 있습니다 .

이를 사용하려면 build.gradle파일에 라이브러리 종속성을 추가 하십시오.

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

사용 예는 GitHub 저장소 (샘플 앱 및 사용 가이드 모두)에서 확인할 수 있습니다.


내가 정확히 작동하거나 REPO에 문제가 열리지 않습니다 알려주십시오 @LavekushAgrawal
— Farbod 살라 - 자데

1
실제로는 작동하지만, 레이블은 글고처럼 떠되지 않는다
— Lavekush 아그라 왈

@LavekushAgrawal 위에 배치 된 작은 레이블이 있습니다 Spinner. 이는 EditText구성 요소 위에 작은 레이블이있는 것과 비슷합니다 TextInputLayout. 그것이 어떻게 될 것이라고 상상 했습니까?
— Farbod Salamat-Zadeh

@ FarbodSalamat-Zadeh 이것은 사용하기에 멋진 라이브러리이지만 Lollipop에서는 작동하지 않습니다.
— Jorge

2
Gradle을 3.5에서 작동하지 만 2.0 아주 오래된 라이브러리 Gradle을
— 아서 멜로


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 휴대 전화가 없습니다.
— Kenny Li

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
그것은 다른 디자인의 스피너입니다
— 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) {

        }
    });

질문이 있으면 물어보세요


내가 막히는 걸 도와 줄 수있어? 여러 편집 텍스트가 있으므로 레이아웃 포커스가 첫 번째 편집 텍스트로 이동하고 직접 회 전자를 눌러 편집 텍스트 위의 코드가 초점을 얻지 못합니다.하지만 회 전자 클릭에 초점을 맞춰야합니다. 어떻게 할 수 있습니까?
— sunita

내가 노력하고 때 내가 회에 집중할 수 있었기 때문에 @sunita 당신은 내가보기 순서를 알려 주시기 바랍니다 수 있습니다
— 미르 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>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.