Android Spinner에서 한 항목을 숨기는 방법


101

Android 스피너 위젯에서 하나의 항목을 숨기는 방법을 찾고 있습니다. 이렇게하면 항목을 선택하지 않은 상태에서 스피너를 시뮬레이션 할 수 있으며 선택된 모든 항목에 대해 onItemSelected () 콜백이 항상 호출됩니다 (숨겨진 항목이 "현재"항목 인 경우). 일반적으로 콜백을 생성하지 않는 스피너에는 항상 하나의 항목, 즉 현재 항목이 있습니다.

항목을 비활성화 (회색으로 표시)하는 방법에 대한 일부 코드가 stackoverflow에 있지만 존재하지 않는 것처럼 항목을 완전히 숨기는 방법은 아닙니다.

많은 실험 끝에 다양한 구형 및 신규 Android 플랫폼에서 작동하는 다소 해킹 같은 솔루션을 찾았습니다. 눈에 띄지 않는 사소한 외관상의 단점이 있습니다. "스피너를 사용하지 마십시오"라는 것 외에 더 공식적인 솔루션에 대해 듣고 싶습니다.

이것은 항상 스피너의 첫 번째 항목을 숨기지 만 임의의 항목이나 둘 이상의 항목을 숨기도록 상당히 쉽게 확장 할 수 있습니다. 스피너 항목 목록의 시작 부분에 빈 문자열이 포함 된 더미 항목을 추가합니다. 스피너 대화 상자가 열리기 전에 현재 스피너 선택을 항목 0으로 설정할 수 있습니다. 이렇게하면 선택되지 않은 스피너가 시뮬레이션됩니다.

ArrayAdapter 메서드 재정의를 사용한 Spinner 설정 예 :

List<String> list = new ArrayList<String>();
list.add("");   //  Initial dummy entry
list.add("string1");
list.add("string2");
list.add("string3");

// Populate the spinner using a customized ArrayAdapter that hides the first (dummy) entry
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, list) {
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent)
    {
        View v = null;

        // If this is the initial dummy entry, make it hidden
        if (position == 0) {
            TextView tv = new TextView(getContext());
            tv.setHeight(0);
            tv.setVisibility(View.GONE);
            v = tv;
        }
        else {
            // Pass convertView as null to prevent reuse of special case views
            v = super.getDropDownView(position, null, parent);
        }

        // Hide scroll bar because it appears sometimes unnecessarily, this does not prevent scrolling 
        parent.setVerticalScrollBarEnabled(false);
        return v;
    }
};

dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);

다른 인터 웹에서 무엇을 찾았습니까? 지금까지 뭐 해봤 어?
dldnh

미안 해요, 어떻게하는지 모르겠어요.
Louisth

좋은 해결책! 하지만 그 tv.setVisibility(View.GONE);라인은 불필요 하다고 생각합니다 . 주석 처리는 적어도 Android 4.4.2 / KitKit (LG / Google Nexus 4에서)에서는 (시각적) 차이가없는 것 같습니다.
Matthias 2014 년

이 질문에 대한 대답은 잘 .. 작동
둥둥-A-문신 라따뚜이

이것은 개선되지 않을 수 있지만 setTag(1)위치 0의 textView에서 사용한 다음 convertView.getTag() != null재사용 된 뷰가 위치 0에 대해 생성 된 0 높이 뷰인지 또는 다른 스피너 항목에 사용되는 일반 뷰인지 확인하는 데 사용되었습니다. 이것은 super.getDropDownView(position, convertView, parent)항상 새로운 뷰를 만드는 대신 가끔 사용할 수 있기 때문 입니다.
Daniel Handojo

답변:


49

임의의 항목이나 둘 이상의 항목을 숨기려면 자체 어댑터를 구현하고 숨기려는 인덱스 (또는 인덱스 배열 목록)를 설정할 수 있다고 생각합니다.

public class CustomAdapter extends ArrayAdapter<String> {

     private int hidingItemIndex;

     public CustomAdapter(Context context, int textViewResourceId, String[] objects, int hidingItemIndex) {
         super(context, textViewResourceId, objects);
         this.hidingItemIndex = hidingItemIndex;
     }

     @Override
     public View getDropDownView(int position, View convertView, ViewGroup parent) {
         View v = null;
         if (position == hidingItemIndex) {
             TextView tv = new TextView(getContext());
             tv.setVisibility(View.GONE);
             v = tv;
         } else {
             v = super.getDropDownView(position, null, parent);
         }
         return v;
     }
 }

그리고 항목 목록을 만들 때 사용자 지정 어댑터를 사용합니다.

List<String> list = new ArrayList<String>();
list.add("");   //  Initial dummy entry
list.add("string1");
list.add("string2");
list.add("string3");

int hidingItemIndex = 0;

CustomAdapter dataAdapter = new CustomAdapter(this, android.R.layout.simple_spinner_item, list, hidingItemIndex);

dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);

(코드를 테스트하지 않았습니다) 도움이되기를 바랍니다.


1
이것은 해결책이 아닙니다. 질문에 대한 업데이트는 올바른 코드를 제공합니다.
dldnh 2013 년

13
tv.setHeight (0) 없이도 TextView는 계속 표시됩니다.
v4r 2014

안녕하세요,이 코드를 사용하여 스피너의 첫 번째 항목을 숨겼습니다. 잘 작동합니다. 스피너가 두 번째 항목을 표시하지만 두 번째 항목을 클릭하면 해당 항목의 텍스트가 스피너로 설정됩니다. 해당 항목을 클릭 할 때 스피너에 텍스트를 표시하고 싶지 않습니다. 안내해주세요.
Achin

1
신난다 :) 간단한 솔루션 :
Chaitanya

1
매력처럼 작동합니다 ..!
Krupa Kakkad

20

목록을 잘라서 목록 끝에있는 항목을 숨기는 것이 더 쉽습니다.

그러나 먼저 선택하여 스피너에 표시되도록 한 다음 선택 항목이 표시된 항목 중 하나로 변경되었는지 확인해야합니다.

List<String> list = new ArrayList<String>();
list.add("string1");
list.add("string2");
list.add("string3");
list.add("[Select one]");
final int listsize = list.size() - 1;

ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, list) {
    @Override
    public int getCount() {
        return(listsize); // Truncate the list
    }
};

dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);
mySpinner.setSelection(listsize); // Hidden item to appear in the spinner

3
나는 깨끗한 접근 방식을 찾으려고 30 분 동안 찾고 있었는데 이것이 최고의 접근 방식입니다. 목록을 자르면 항목이 실제로 존재합니다. 우수한.
KSdev

1
Lollipop에서는 작동하지 않는 것 같습니다. [Select one] 테스트는 처음에 Spinner에 표시되지 않습니다. 이전 Android 버전의 동일한 코드가 우리 모두가 원하는 작업을 수행하는 것 같습니다.
Jonathan Caryl 2015 년

1
스피너를 건드리지 않아도 방향 변경시 스피너 텍스트가 'String3'으로 변경됩니다. @Romich
Yksh

아무도 내 질문을 볼 수 있습니까?
Moeez

5

스피너 드롭 다운에서 항목을 숨기려면 필요한 기준에 따라 숨겨야하는 항목의 위치를 ​​전달해야합니다. 드롭 다운에서 선택한 항목을 숨기는 사용 사례에서이 작업을 수행했습니다.

public class CustomAdapter extends ArrayAdapter<String> {

private List<String> dates;
private int hideItemPostion;

public CustomAdapter (Context context, int resource, List<String> dates) {
    super(context, resource,dates);
    this.dates=dates;
}
public void setItemToHide(int itemToHide)
{
    this.hideItemPostion =itemToHide;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
    View v = null;
    if (position == hideItemPostion) {
        TextView tv = new TextView(getContext());
        tv.setVisibility(View.GONE);
        tv.setHeight(0);
        v = tv;
        v.setVisibility(View.GONE);
    }
    else
        v = super.getDropDownView(position, null, parent);
    return v;
}}

그리고 어댑터 설정은 다음과 같습니다.

final CustomAdapter dataAdapter = new CustomAdapter(this,R.layout.spinner_item,dates);
    dataAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
    spinner.setAdapter(dataAdapter);
    dataAdapter.setItemToHide(0);

드롭 다운에서 일부 항목을 선택하면 위치도 변경해야합니다.

 spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, final int i, long l) {
        dataAdapter.notifyDataSetChanged();
            mEPGDateSelector.setSelection(i);
            dataAdapter.setItemToHide(i);}

             @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    });

1

관심을 위해 "프롬프트"를 힌트로 사용하는 솔루션을 만들었습니다. 이 코드는를 위해 만들어 Xamarin.Android졌지만 10 분 안에 Java로 완벽하게 이식 될 수 있습니다. ArrayAdapter0 인덱싱 또는 개수 인덱싱 항목을 소스 배열에 추가하지 않고 간단하게 사용하십시오 . SpinnerGeolocation.SelectedItemId아무것도 선택하지 않은 경우 에도 -1로 설정 됩니다 ( hint현재 항목 임).

public class ArrayAdapterWithHint<T>: ArrayAdapter<T>
{
    protected bool HintIsSet = false;
    protected int HintResource = 0;

    public ArrayAdapterWithHint(Context context, int textViewResourceId,
                   T[] objects)
        : base(context, textViewResourceId, objects)
    {
    }
    public ArrayAdapterWithHint(Context context, int hintResource,
                   int textViewResourceId, T[] objects)
        : base(context, textViewResourceId, objects)
    {
        HintResource = hintResource;
    }
    public ArrayAdapterWithHint(Context context, int textViewResourceId,
             IList<T> objects)
        : base(context, textViewResourceId, objects)
    {
    }
    public ArrayAdapterWithHint(Context context, int hintResource,
                    int textViewResourceId, IList<T> objects)
        : base(context, textViewResourceId, objects)
    {
        HintResource = hintResource;
    }

    public override View GetDropDownView(int position, View convertView,
                ViewGroup parent)
    {
        if (HintIsSet)
            return base.GetDropDownView(position + 1,
                               convertView, parent);
        return base.GetDropDownView(position, convertView, parent);
    }

    public override View GetView(int position, View convertView,
                      ViewGroup parent)
    {
        if (!HintIsSet && parent is Spinner && 
                    !string.IsNullOrWhiteSpace((parent as Spinner).Prompt))
        {
            Insert((parent as Spinner).Prompt, 0);
            HintIsSet = true;
            (parent as Spinner).SetSelection(base.Count - 1);
        }
        if (HintIsSet && position >= base.Count - 1)
        {
            View hintView = base.GetView(0, convertView, parent);
            if (hintView is TextView)
                (hintView as TextView).SetTextAppearance(
                                                     Context, HintResource);
            return hintView;
        }
        if (HintIsSet && position < base.Count - 1)
            return base.GetView(position + 1, convertView, parent);
        return base.GetView(position, convertView, parent);
    }

    public override long GetItemId(int position)
    {
        if (HintIsSet)
        {
            if (position >= base.Count - 1)
                return -1;
            return position;
        }
        return base.GetItemId(position);
    }

    public override int Count
    {
        get
        {
            return base.Count > 0 && HintIsSet ? base.Count - 1 : base.Count;
        }
    }
}

아무도 내 질문을 볼 수 있습니까?
Moeez

1

내 문제를 해결 한이 솔루션을 찾았습니다.

final Spinner mySpinner = (Spinner)findViewById(R.id.spinner_triptype);

   final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.spinner_item, R.id.weekofday, triptype_initial);

   final ArrayAdapter<String> adapter_temp = new ArrayAdapter<String>
(this,R.layout.spinner_item, R.id.weekofday, triptype_array);


   mySpinner.setAdapter(adapter);
    mySpinner.setOnTouchListener(new View.OnTouchListener() {
       @Override
       public boolean onTouch(View v, MotionEvent event) {
       // display your error popup here
        if(flag_spinner_isFirst){
           mySpinner.setAdapter(adapter_temp);
           flag_spinner_isFirst = false;
          }
           v.onTouchEvent(event);
           return true;

       }
    });

0

항목이 필터링되면 Spinner에 추가하는 것이 안전하기 때문에 Spinner보다는 Array List에 유효성 검사를 두는 것이 더 낫다고 생각합니다.


0

나를 위해 가장 잘 작동하는 또 다른 접근 방식은 새로운 빈 뷰 객체를 반환하는 것입니다. 이것은 배열 요소를 가지고 놀지 않기 때문에 상당히 깔끔한 접근 방식입니다.

어댑터 클래스 확장 만들기 ArrayAdapter

당신의 방법 안에

public View getView(int position, View convertView, ViewGroup parent) {
    View row = getCustomView();
    if(position==0) // put the desired check here.
         {
            row  = new View(context);
         }
    }
    return row;
}

0

이것은 매우 오래된 질문이지만 첫 번째 항목도 표시하지 않는 좋은 (아마도) 깨끗한 방법을 찾았습니다. @Romich의 답변에 영감을 받아 첫 번째 항목을 건너 뛰는 유사한 논리를 추가했습니다.

이렇게하면 임의의 항목 수 (기본적으로 1 개)가 효과적으로 숨겨집니다. 이 코드는 렌더링 할 객체의 크기 만 실제보다 짧게보고하고 렌더링 할 항목의 인덱스를 변경하여 임의의 항목을 건너 뜁니다.

단순하게 유지하기 위해 현재 사용중인 임의 항목 목록 숨기기를 지원하는 솔루션을 제외했지만 코드를 약간만 수정하면 쉽게 관리 할 수 ​​있습니다.

class ArrayAdapterCustom(context: Context, textViewResourceId: Int, vararg objects: String)
    : ArrayAdapter<String>(context, textViewResourceId, objects) {

    //Can skip first n items (skip 1 as default)
    var hideFirstItemsCount = 1

    override fun getCount(): Int {
        return super.getCount() - hideFirstItemsCount
    }

    override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
        return super.getDropDownView(position + hideFirstItemsCount, convertView, parent)
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.