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 내부에서 사용하는 것을 빼앗아서 동작 버그가 생긴것 같다.
결국은 어떻게 해결을 했는가?
-
setOnClickListener 클릭이벤트 삽입
-
SpinnerAdapter 에 커스텀으로 onItemClickListener 삽입 (호출부와 연결하기 위해서)
-
동작되지 않는 항목들 수동으로 코드 삽입 (1-1 참고)
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)
}
}
...
}
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
'android' 카테고리의 다른 글
view ratio 강제 적용하기 (0) | 2023.04.18 |
---|---|
나는 제대로된 Clean Architecture를 사용하고 있을까? (0) | 2023.04.14 |
ConstraintLayout - 가변형 속성 (0) | 2022.05.01 |
Compose 나도 시작해보려합니다✌️ (0) | 2022.03.30 |
스레드간 데이터 통신 (0) | 2021.02.16 |