티스토리 뷰

728x90

Spinner란 왼쪽뷰이고 오른쪽 DropDown 리스트를 손쉽게 붙일 수 있게 해준다. 
(Spinner + ArrayAdapter) 

사실 요즘은 AutoCompleteTextView 에 ArrayAdapter를 연결하는 방식으로 많이 쓰고 있다. 다만, 오래된 코드의 경우 Spinner 를 사용하는 경우가 종종 있으니 알아는 둬야겠지.. 

커스터마이징 하고자 했던 것은 DropDown 아이템을 클릭했을 때 리스너를 붙이는 것이었다. 

그러기 전에 일단 Spinner 와 AutoCompleteTextView 에서 ArrayAdapter의 동작 차이점을 살펴보자. 

Spinner vs AutoCompleteTextView


Spinner

binding.spinner.onItemSelectedListener = object : OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
                if (position > 0) {
                    // action 
                }
            }

            override fun onNothingSelected(parent: AdapterView<*>?) {}
        }

onItemSelected 를 체크할 수 있다. 하지만 나는 클릭을 했을 때만 리스너를 받고 싶은데 그게 안된다.. 

그래서 ArrayAdapter 에서 View inflate 시점에 clickListener (또는 onTouchListener) 를 붙여서 해결해보기로 했다. 

public class SpinnerAdapter extends ArrayAdapter<String> {
    public interface OnItemClickListener {
        void onItemClickListener(int position);
    }

  	...

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        Holder holder;
        if (convertView == null) {
            @SuppressLint("InflateParams")
            View v = inflater.inflate(R.layout.spinner_row_child, null);
            convertView = v;
            holder = new Holder();
            holder.name = (TextView) convertView.findViewById(R.id.text_item);
            convertView.setTag(holder);
        } else {
            holder = (Holder) convertView.getTag();
        }
        
        holder.name.setText(values[position]);
        if (onItemClickListener != null) {
            convertView.setOnClickListener(view -> onItemClickListener.onItemClickListener(position));
        }
        return convertView;
    }
    
    ...

}

convertView.setOnClickListener 코드를 보면 DropDown View에 클릭 리스너를 달고 있다. 

해결이 되었다! 싶었지만, 문제가 발견되었다. 😭

DropDown이 사라지지 않고, 선택도 되지 않는다는 것! 

버그의 원인이 뭘까⁇


구글링 결과 추측되는 원인은 If any row item of list contains focusable or clickable view then OnItemClickListener won't work.

아마 내가 DropDown View에 setOnClickListener를 선언하면서 ArrayAdapter 내부에서 사용하는 것을 빼앗아서 동작 버그가 생긴것 같다. 

결국은 어떻게 해결을 했는가?

  1. setOnClickListener 클릭이벤트 삽입
  2. SpinnerAdapter 에 커스텀으로 onItemClickListener 삽입 (호출부와 연결하기 위해서)
  3. 동작되지 않는 항목들 수동으로 코드 삽입 (1-1 참고)
spinner.hideSpinnerDropDown()
spinner.setSelection(position)
요렇게 임시 해결을 했다.
UX 적으로 전혀 부자연스러움이 없다.
binding.spinner.let { spinner ->
    spinner.adapter = SpinnerAdapter(baseContext, android.R.layout.simple_spinner_dropdown_item, elms)
        .apply {
            onItemClickListener = OnItemClickListener { position ->
                ...
                spinner.hideSpinnerDropDown()
                spinner.setSelection(position)
            }
        }
    ...
}
 
다만, 3번의 수동 코드 삽입에 대한 boilerPlate 코드들은 우짤꼬..
=> 1차적으로 커스텀 onItemClickListener에 주석으로 boilerPlate 정책을 작성해놓았다.
 

AutoCompleteTextView

val items = arrayOf<String>("item1", "item2", "item3");
val itemAdapter = ArrayAdapter<String>(context, R.layout.item_list, items); 
autoCompleteTextView.setAdapter(itemAdapter);

autoCompleteTextView.setOnItemClickListener(object : AdapterView.OnItemClickListener() {
	@Override
    fun onItemClick(adapterView, view, position, id) {
    	text.setText(adapterView.getItemAtPosition(position));
        }
})

오 이 친구는 onItemClickListener() 가 라이브러리 단에서 제공해주는군! 


<결론>


DropDown 메뉴를 활용하려면 Spinner와 AutoCompleteTextView 를 활용하는 방법이 있다. 

DropDown 메뉴의 클릭리스너를 달려면
Spinner는 커스터마이징의 한계가 있으나 우회하는 방법이 있다. 
AutoCompleteTextView를 사용하면 더 편하게 개발할 수 있다. 


 

<참조> 

https://aries574.tistory.com/157

 

[안드로이드] Material Dropdown menu 쉽게 만드는 방법

2021.12.12 - [안드로이드] - [안드로이드] custom spinner 만드는 방법 [안드로이드] custom spinner 만드는 방법 이번 시간에는 스피너를 내맘대로 바꿔보겠습니다. 미리 알아보자면 아이콘 넣기, 글씨색깔

aries574.tistory.com

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함