안드로이드 공부의 첫번째 장벽이라고 생각한다.
ListView는 Adapter를 경유해 사용한다.
아이템을 Adapter에 넣고, 그걸 ListView에 넣어서 그렇게 만들어진 ListView를 원하는 화면 xml파일에 구현하는 방식을 사용한다.
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
class ListAdapter(val List: MutableList<String>) : BaseAdapter() {
override fun getCount(): Int {
TODO("Not yet implemented")
}
override fun getItem(p0: Int): Any {
TODO("Not yet implemented")
}
override fun getItemId(p0: Int): Long {
TODO("Not yet implemented")
}
override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View {
TODO("Not yet implemented")
}
}
Adapter의 기본 틀이다. 데이터를 받아와야하므로 받아올 데이터에 맞게 매개변수를 설정하고, BaseAdapter import를 해준다. 지금은 String List이고 이름이 List인 객체를 가져왔다.
override된 네개의 함수는 기본으로 필요하니 Implement members 기능을 이용해 추가해준다.
getItem과 getItemId는 아직 잘 모르니 알고있는 getCount와 getView만 보도록하겠다. p0, p1, p2가 업데이트를 하면서 이름이 바뀐 것 같은데
p0 -> position
p1 -> convertView
p2 -> parent
이렇게 원래 이름이 지어져있었다.
메인 액티비티와 ListView로 사용될 xml을 보고 가자.
<?xml version="1.0" encoding="utf-8"?>
<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">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/listView"/>
</androidx.constraintlayout.widget.ConstraintLayout>
메인 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<TextView
android:layout_margin="8dp"
android:id="@+id/listViewItem"
android:text="Listview Item"
android:textSize="32sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
리스트뷰 레이아웃이다. 리스트뷰 레이아웃의 TextView가 이제 adapter를 통해 데이터가 전달될 부분이다.
이제 핵심인 Adapter를 살펴보겠다.
처음에는 이 개념이 잘 이해되지않을거라 확신한다. LayoutInflater는 프래그먼트에서도 사용되니 익숙해지는게 최선이다.
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.TextView
class ListAdapter(val List: MutableList<String>) : BaseAdapter() {
override fun getCount(): Int {
//TODO("Not yet implemented")
return List.size
}
override fun getItem(p0: Int): Any {
//TODO("Not yet implemented")
return List[p0]
}
override fun getItemId(p0: Int): Long {
//TODO("Not yet implemented")
return p0.toLong()
}
override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View {
//TODO("Not yet implemented")
var converView = p1
if(converView == null){
converView = LayoutInflater.from(p2?.context).inflate(R.layout.listview_item, p2, false)
}
val message = converView!!.findViewById<TextView>(R.id.listViewItem)
message.text = List[p0]
return converView!!
}
}
converView에 convertView를 우선 복사해준다.
converView에 위에 리스트뷰전용으로 만들어둔 listview 레이아웃을 연결해준다. inflate로 연결해주고 문법에 유의하자.
이제 mainactivity에서 setcontentview를 통해 쉽게 연결하던걸 지금 어댑터에서는 inflated된 converView를 통해 각 뷰 객체를 연결할 수 있게된다.
리스트뷰xml에 만들어둔 textView를 연결해준다. 그리고 텍스트뷰에 표시될 내용을 List[position]으로 전달해고, converview를 리턴해주면된다.
!!는 non-null임을 명시해주는 어노테이션이라고 보면된다.
이제 지금까지 한 것은 Adapter와 리스트뷰 전용으로 만들어둔 레이아웃을 연결해준 것이다. 받아올 데이터를 처리해주고 리스트뷰를 메인액티비티 레이아웃에 띄우는 과정을 진행하면 끝난다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val testList = mutableListOf<String>()
testList.add("a")
testList.add("b")
testList.add("c")
val listAdapter = ListAdapter(testList)
val listView = findViewById<ListView>(R.id.listView)
listView.adapter = listAdapter
}
}
넘겨줄 데이터는 a, b, c이다.
어댑터 클래스에 전달해줄 리스트를 넣어주고 listAdapter라는 이름으로 객체를 생성한다. 그리고 메인 액티비티에 만들어둔 listview 뷰 객체를 바인딩해주고 listview 객체의 adapter에 ListAdapter 객체인 listAdapter를 연결해준다.
말이 좀 번거롭긴한데 과정이 이렇다. 이렇게 하면 어댑터에서 데이터를 받아 리스트뷰 전용 레이아웃에 맞춰 데이터를 표시하면, 그 화면을 메인액티비티의 리스트뷰에 가져다가 준다.
어댑터의 인자로는 data class를 따로 만들어 넘겨주는 방식이 일반적인 것 같다.
"댓글, 공감 버튼 한 번씩 누르고 가주시면 큰 힘이 됩니다"