본문 바로가기

TIL

[TIL] Kotlin Spinner

[오늘 배운 내용]

-1- Spinner

  • Spinner란 dropDown 형식으로 항목을 나타내는 ViewItem이다.

Spinner 생성하기

  • 기본적으로 만들 수 있는 Spinner를 생성하려면 가장먼저 Item을 클릭했을 시 DropDown되는 아이템들을 지정해주자
  • res/values 폴더 하위에 array.xml 파일을 생성해주고 해당 파일안에 DropDown 시 보여질 아이템들을 넣어주자

Array.xml

<resources>
    <string-array name="spinner_main_menu">
        <item>home</item>
        <item>work</item>
        <item>other</item>
        <item>custom</item>
    </string-array>
</resources>

 

 

 

  • Spinner가 들어갈 main.xml 로 가서, Spinner를 만들고 Spinner를 통해 TextView의 Text를 바꿀 수 있도록 TextView도 추가해준다.
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Spinner
        android:id="@+id/spinner"
        android:layout_width="120dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="30dp"
        android:layout_marginTop="30dp"
        android:layout_marginEnd="293dp"
        android:padding="10dp"
        android:background="@drawable/spinner_bg"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/text_View"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="248dp"
        android:layout_marginTop="30dp"
        android:text="textView"
        android:textSize="20sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>

 

  • main.kt Activity로 이동해서 xml에서 생성해놓은 Spinner와 adapter를 통해서 연결해주고 클릭 리스너를 달아주면 된다.
  • setOnClickListener는 AdapterView의 인터페이스가 아닌 Kotlin에서 제공하는 확장 함수이므로 OnItemSelectedListener와 구분해야 한다. setOnClickListener도 람다식으로 간결하고 편리하게 작동할 수 있다고 하는데, 복잡한 로직을 처리하기 위해서는 OnItemSelected 함수를 사용해야 한다고 한다.
  • DropDown 메뉴들의 아이템 Position은 0 부터 시작한다.
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val spinner = findViewById<Spinner>(R.id.spinner)
        val textView = findViewById<TextView>(R.id.text_View)

        spinner.adapter = ArrayAdapter.createFromResource(this,R.array.spinner_main_menu,android.R.layout.simple_spinner_item)
        spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
                when (position) {
                    0 -> {
                        textView.text = "1번 선택"
                    }
                    1 -> {
                        textView.text = "2번 선택"
                    }
                    2 -> {
                        textView.text = "3번 선택"

                    }
                    3 -> {
                        textView.text = "4번 선택"
                    }
                    else -> {
                        textView.text = "선택되지 않음"
                    }
                }
            }
            override fun onNothingSelected(parent: AdapterView<*>?) {
            }
        }

    }
}

 

 

-2- Spinner CustomAdapter

  • 여러가지 시도해보았으나 Spinner에 아이콘을 넣으면 DropDown에 나오는 아이템들도 같은 아이콘을 달고 나와서 다른 블로그에서 만든 CustomAdapter를 들고왔다.
  • 해당 블로그에서 코드를 가져왔는데, 확장함수도 명확하게 배우지 않은 상태라서 배우고 난 뒤에 다시 뜯어봐야겠다..

https://vintageappmaker.tistory.com/360

 

[예제] Kotlin에서 Spinner 커스텀

Android에서 앱을 만들다보면 Button TextEdit TextView 다음으로 Spinner를 커스텀해야 할 때가 많다. 그런데 위의 3개와는 달리 Spinner를 커스텀 할 때에는 해야할 일들이 많다. 일반적으로 1. Spinner 배경설

vintageappmaker.tistory.com

  • 완벽하게 이해 X 복붙해놓았음 이해하려고 시간을 굉장히 많이 보냈는데 아직 이해하기가 어려워서 코드만 작성해두고 추후에 수정.

res/drawable - spinner_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#333333"/>
            <corners android:radius="3dp" />
        </shape>
    </item>
    <item android:gravity="center_vertical|right" android:right="8dp">
        <layer-list>
            <item android:width="12dp" android:height="12dp"  android:gravity="center" android:bottom="10dp">
                <rotate
                    android:fromDegrees="45"
                    android:toDegrees="45">
                    <shape android:shape="rectangle">
                        <solid android:color="#eeeeee" />
                        <stroke android:color="#eeeeee" android:width="1dp"/>
                    </shape>
                </rotate>
            </item>
            <item android:width="20dp" android:height="11dp" android:bottom="21dp" android:gravity="center">
                <shape android:shape="rectangle">
                    <solid android:color="#333333"/>
                </shape>
            </item>
        </layer-list>
    </item>
</layer-list>

 

res/layout - spinner_drop_down_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/text_drop_down_item"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="#333333"
        android:ellipsize="marquee"
        android:gravity="left|center_vertical"
        android:minWidth="130dp"
        android:paddingStart="20dp"
        android:singleLine="true"
        android:textColor="#eeeeee"
        android:textSize="12dp" />
    
</LinearLayout>

 

res/layout - main.xml

    <Spinner
        android:id="@+id/spinner"
        android:layout_width="200dp"
        android:layout_height="60dp"
        android:layout_marginStart="30dp"
        android:layout_marginTop="30dp"
        android:layout_marginEnd="170dp"
        android:background="@drawable/spinner_bg"
        android:padding="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

 

mainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val spinner = findViewById<Spinner>(R.id.spinner)
        val textView = findViewById<TextView>(R.id.text_View)

        val category = mutableListOf("없음","outer","tops","bottoms","shorts","hats")
        
        // custom
        spinner.setCustomAdapter(this,category)

        spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
                when (p2){
                    0 -> { }
                    1 -> { textView.text = category[p2] + " 선택"}
                    2 -> { textView.text = category[p2] + " 선택"}
                    3 -> { textView.text = category[p2] + " 선택"}
                    else -> { textView.text = category[p2] + " 선택"}
                }
            }

            override fun onNothingSelected(p0: AdapterView<*>?) {
                textView.text = "선택되지 않음"
            }

        }
    }
}

fun View.dpToPx(dp:Float): Int = context.dpToPx(dp)
fun Context.dpToPx(dp:Float) : Int = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,resources.displayMetrics).toInt()
fun View.setHeight(context: Context,value: Int){
    val lp = layoutParams
    lp?.let {
        lp.height = dpToPx(value.toFloat())
        layoutParams = lp
    }
}

fun Spinner.setCustomAdapter(context: Context, list : MutableList<String>,unselectedTitle : String = "선택"){
    class CustomSpinnerAdapter : BaseAdapter {
        var list : MutableList<String> = mutableListOf<String>()
        var context: Context
        var unselectedTitle : String

        constructor(context: Context,list:MutableList<String>,unselectedTitle: String){
            this.context = context
            this.list = list
            this.unselectedTitle = unselectedTitle
        }

        override fun getCount(): Int {
            return list.size
        }

        override fun getItem(n: Int): Any {
            return list[n]
        }

        override fun getItemId(p0: Int): Long {
            return 0
        }

        override fun getView(n: Int, p1: View?, p2: ViewGroup?): View {
            val v = LayoutInflater.from(context).inflate(R.layout.spinner_drop_down_bg,null)
            v.findViewById<TextView>(R.id.text_first)?.apply {
                text = "선택"
                text = list[n]

                if (p2 is Spinner){

                    background = context.getDrawable(R.drawable.spinner_bg)
                    if (p2.selectedItemPosition < 0){
                        p2.setHeight(context,60)
                        setTextColor(Color.WHITE)
                        text = unselectedTitle
                        textSize = 18f
                    }
                }
            }
            return v
        }
    }
    adapter = CustomSpinnerAdapter(context,list,unselectedTitle)
    this.setSelection(-1)
}

-3-

 

 

 

 


 

[오늘 복습한 내용]

1. 복습은 아니고 노트프로그램을 정했다 TIL 작성과 별개로 노트도 작성해보려고 마음 먹었다. 크롬 북마크 수가 너무 많기도 해서 노트앱에 별도로 정리할 수 있는 저장공간으로 써보려고 한다.

 


[오류,에러 등등]

1.  특이점 없음

 


[느낀 점]

1. 점점 더 어려워 지는 것 같아서 집중 하는 시간을 늘리고 열심히 따라가야겠다.

 

2. 잡생각이 너무 많아서 좀 단순하게 생각하는 습관을 들여야겠다.

 

3. Adapter와 연결하는 부분은 항상 어려운 느낌인데 얼른 익숙해지도록 노력해야겠다.

 

 


[Reference]

 

// Spinner

https://vintageappmaker.tistory.com/360

https://aries574.tistory.com/381?category=375976