Adapter View
- 개발자는 화면의 다양한 View 들을 배치해 화면을 구성하게 된다.
- 대부분의 뷰들은 배치를 하면 기본적으로 정해진 속성에 따라 모양이 구성된다.
- 하지만 일부 View 들은 스스로 결정할 수 없는 부분이 있어 개발자가 반드시 데이터를 설정해야만 구성이 가능하다. 이렇게 개발자가 반드시 설정해야 화면을 구성할 수 있는 View 들을 가르켜 Adapter View라고 부른다.
Adapter Class
- Adapter View 들은 View 구성하기 위해서 개발자가 다양한 데이터를 설정해줘야 한다.
- 이러한 데이터를 관리하는 Class 를 Adapter Class라고 부른다.
- Adapter Class는 사용 목적이나 적용할 View 에 따라 다양하게 제공되고 있으며 원한다면 직접 생성해서 사용할 수도 있다.
- 주로 다양한 항목을 제공하는 View를 구성할 때 사용한다.
주요 AdapterView 종류
ListView (ArrayAdapter)
CustomListView (ArrayAdapter)
CustomListView (SimpleAdapter)
CustomAdapter (BaseAdapter)
Spinner (ArrayAdapter)
GrideView (ArrayAdapter)
ViewPager
AutoCompleteTextView (ArrayAdapter)
Single/Multi ChoiceListView (ArrayAdapter)
RecyclerView (RecyclerView.Adapter)
ArrayAdapter
- ArrayAdapter를 이용해 Adapter 객체를 만들 때 개발자가 작성한 layout 파일을 지정할 수 있다.
- 만약 기본 ListView 를 사용한다면 안드로이드에서 제공해주는 android.R.layout.simple_list_item_1 폼을 사용한다.
- 두 번째 매개 변수로 layout 파일을, 세 번째 layout 파일 내에서 문자열을 설정한 View의 아이디를 설정한다.
ListView를 위한 ArrayAdapter (android.R.layout.simple_list_item_1 안드로이드 제공)
val mAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, adapterViewDatas)
CustomListView를 위한 ArrayAdapter (row.xml 사용자 지정)
val mAdapter = ArrayAdapter(this, R.layout.row, R.id.textView, data)
ListView (ArrayAdapter)
- 가장 대표적이고 가장 많이 사용하는 Adapter View 이다.
- 지금은 RecyclerView 사용을 추천하고 있지만 AdapterView 개념을 공부하기에 적당하다.
- RecyclerView가 내부적으로 관리의 효율성을 가지고 있지만 지금도 ListView를 많이 사용하고 있다.
- RecyclerView를 사용할 정도가 아니라면 ListView를 사용해도 된다.
ListView 의 주요 프로퍼티
- adapter : AdapterView를 구성하기 위해 사용하는 adapter를 관리한다.
ListView 의 주요 이벤트
- ItemClick : 항목을 터치하면 발생된다.
AdapterView.OnItemClickListener{
// onItemClick (이벤트가 발생한 항목을 가지고 있는 AdapterView, 이벤트가 발생한 항목View, 이벤트가 발생한 항목의 index)
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
when(parent?.id){
R.id.listView -> {
textViewTitle.text = "${adapterViewDatas[position]} 보러가기 !! "
}
}
}
}
전체 소스코드
MainActivity.kt
class MainActivity : AppCompatActivity() {
val adapterViewDatas = arrayOf("ListView", "CustomListView",
"ArrayAdapter", "SimpleAdapter", "CustomAdapter",
"Spinner", "GrideView", "ViewPager",
"AutoCompleteTextView", "Single/Multi ChoiceListView",
"RecyclerView")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// ArrayAdapter(Context, 항목 하나를 구성하기 위해 사용할 layout 파일)
val adapter1 = ArrayAdapter(this, android.R.layout.simple_list_item_1, adapterViewDatas)
listView.adapter = adapter1
listView.setOnItemClickListener(listener1)
}
val listener1 = object : AdapterView.OnItemClickListener{
// onItemClick (이벤트가 발생한 항목을 가지고 있는 AdapterView, 이벤트가 발생한 항목View, 이벤트가 발생한 항목의 index)
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
when(parent?.id){
R.id.listView -> {
textViewTitle.text = "${adapterViewDatas[position]} 보러가기 !! "
}
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textViewTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Custom ListView (ArrayAdapter)
- 기본으로 제공되는 layout 파일 대신해 개발자가 직접 작성한 layout을 이용해 ListView를 구성할 수 있다.
- ListView 뿐만 아니라 모든 AdapterView는 동일한 방법으로 설정이 가능하다.
- 여기서는 문자열 하나를 설정하는 방법을 살펴본다.
CustomListViewActivity.kt
class CustomListViewActivity : AppCompatActivity() {
val titleData = arrayOf("문자열1", "문자열2", "문자열3", "문자열4", "문자열5")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_custom_list_view)
val adapter1 = ArrayAdapter(this, R.layout.row_custom_list, R.id.rowTextView, titleData)
customList.adapter = adapter1
customList.setOnItemClickListener { parent, view, position, id ->
textView.text = "${titleData[position]}를 터치하였습니다"
}
}
}
activity_custom_list_view.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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
app:layout_constraintBottom_toTopOf="@+id/rowTextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/rowTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar" />
</androidx.constraintlayout.widget.ConstraintLayout>
row_custom_list.xml ( 직접 작성한 layout!!! )
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".CustomListViewActivity">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="CustomListView"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<ListView
android:id="@+id/customList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
SimpleAdapter
- 개발자가 ListView 의 항목을 자유롭게 디자인 했을 때 사용하는 Adapter Class이다.
- ListView의 항목 내에 배치된 View들을 직접 지정하면서 데이터를 설정할 수 있다.
val mAdapter = SimpleAdapter(this, dataList, R.layout.row, keys, ids)
Custom ListView (SimpleAdapter)
CustomListView2Activity.kt
class CustomListView2Activity : AppCompatActivity() {
val imgRes = arrayOf(R.drawable.food_icon_barbecue, R.drawable.food_icon_beer,
R.drawable.food_icon_bobatea, R.drawable.food_icon_burger, R.drawable.food_icon_coffee,
R.drawable.food_icon_cupcake, R.drawable.food_icon_donut, R.drawable.food_icon_noodle,
R.drawable.food_icon_pizza, R.drawable.food_icon_steak)
val dataKR = arrayOf("바베큐", "맥주", "버블티", "버거", "커피",
"컵케이크", "도넛", "국수", "피자", "스테이크")
val dataEN = arrayOf("barbecue", "beer", "bobatea", "burger", "coffee",
"cupcake", "donut", "noodle", "pizza", "steak")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_custom_list_view2)
// simple adapter에 셋팅할 데이터를 가지고 있을 ArrayList
val dataList = ArrayList<HashMap<String, Any>>()
for(i in imgRes.indices){
// 항목 하나를 구성하기 위해 필요한 데이터를 담고 있는 HashMap
val map = HashMap<String, Any>()
map["img"] = imgRes[i]
map["data_kr"] = dataKR[i]
map["data_en"] = dataEN[i]
dataList.add(map)
}
// HashMap에 데이터를 저장했을 때 사용했던 이름 배열
val keys = arrayOf("img", "data_kr", "data_en")
// 데이터를 셋팅할 View의 id 배열
val ids = intArrayOf(R.id.rowImageView, R.id.rowKRTextView, R.id.rowENTextView)
val adapter1 = SimpleAdapter(this, dataList, R.layout.row_custom_list2, keys, ids)
listView.adapter = adapter1
listView.setOnItemClickListener { parent, view, position, id ->
textView.text = "${dataKR[position]}항목을 터치하였습니다"
}
}
}
activity_custom_list_view2.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".CustomListView2Activity">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="SimpleAdapter를 사용한 \nCustomListView입니다."
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
row_custom_list2.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.3"/>
<ImageView
android:id="@+id/rowImageView"
android:layout_width="50dp"
android:layout_height="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline_vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/rowKRTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/rowENTextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/guideline_vertical"
/>
<TextView
android:id="@+id/rowENTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintTop_toBottomOf="@+id/rowKRTextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/guideline_vertical"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
BaseAdapter
BaseAdapter
- BaseAdapter를 상속받아 다음 메서드를 구현하면 된다.
- getCount : AdapterView를 통해 보여줄 항목의 개수를 반환한다.
- getView : AdapterView를 통해 보여줄 항목의 View를 반환한다.
Custom Adapter View(BaseAdapter)
- BaseAdapter를 상속받은 클래스를 직접 만들면 AdapterView를 커스터마이징 할 수 있다.
- AdapterView의 항목을 자유롭게 디자인해서 사용할 때는 SimpleAdapter 만으로도 충분하다.
- 하지만 AdapterView 자체를 커스터마이징하여 특별한 기능을 부여하고 싶을 때는 Adapter 클래스를 구현하면된다.
CustomAdapterViewActivity.kt
class CustomAdapterViewActivity : AppCompatActivity() {
val data1 = arrayOf("데이터1", "데이터2", "데이터3", "데이터4", "데이터5")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_custom_adapter_view)
customAdapter.adapter = adapter1
}
/**
* "BaseAdapter"클래스 상속받아서 adapter1를 구현함
**/
val adapter1 = object : BaseAdapter(){
// 항목의 개수를 반환한다.
override fun getCount(): Int {
return data1.size
}
override fun getItem(position: Int): Any? {
return null
}
override fun getItemId(position: Int): Long {
return 0
}
// 항목 하나를 구성하기 위해 호출되는 메서드
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
// 재사용 가능한 View를 변수에 담는다.
var rowView = convertView
if(rowView == null){
rowView = layoutInflater.inflate(R.layout.row_custom_adapter, null)
}
// 원하는 기능 구현
rowView?.run{
rowTextView.text = data1[position]
rowButton1.tag = position
rowButton2.tag = position
rowButton1.setOnClickListener { textView.text = "첫 번째 버튼을 눌렀습니다 : ${it.tag}" }
rowButton2.setOnClickListener { textView.text = "두 번째 버튼을 눌렀습니다 : ${it.tag}" }
}
return rowView!!
}
}
}
activity_custom_adapter_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".CustomAdapterViewActivity">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<ListView
android:id="@+id/customAdapter"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
row_custom_adapter.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/rowTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TextView"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<Button
android:id="@+id/rowButton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="12dp"
android:text="기능 1" />
<Button
android:id="@+id/rowButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="12dp"
android:text="기능 2" />
</LinearLayout>
Adapter 종류 정리!!!!!!!
문자열 등 1개의 배열(Array)로 만들고싶을때는 ArrayAdapter로 구현하고,
항목을 자유롭게(문자열을 포함한 항목 1개 이상 Map) 하고싶을때는 SimpleAdapter로 구현하고,
데이터 뿐 아니라 기능을 자유롭게 하고싶을때는 BasdAdapter를 상속받아서 CustomAdapter를 직접 구현한다.
원하는 기능 | Adapter 종류 | xml 파일의 위젯 |
문자열 1개등의 Array 데이터 | ArrayAdapter | ListView |
여러 항목을 나타내는 Map 데이터 | SimpleAdapter | ListView |
기능 자유롭게 구현하고 싶을 때 | BaseAdapter 상속받아 직접 구현 | ListView |
Spinner
- Spinner는 선택할 항목의 메뉴를 숨기고 있다가 필요할 때 화면에 표시하는 Adapter View다.
- 사용자에게 항목을 주고 선택 하게 할 수 있는 AdapterView
- 작은 스마트폰 화면을 효율적으로 사용할 수 있다는 장점을 가지고 있다.
Spinner의 주요 속성
- spinnerMode : 나타나는 메뉴 항목의 타입을 설정한다.
Spinner의 주요 프로퍼티
- selectedItemPosition : 현재 선택되어 있는 항목이 인덱스(0 부터 시작)를 관리한다.
- adapter : View 구성을 위한 Adapter를 관리한다.
- onItemSelectedListener : 항목을 선택했을 때 사용할 리스너를 설정한다.
Spinner의 주요 이벤트
- ItemSelected : 사용자가 항목을 선택했을 경우. 이 이벤트의 리스너는 프로퍼티로 설정한다.
GridView
ListView와 거의 동일하며 항목을 그리드 형태로 보여 줄 수 있는 View 이다.
GridView의 주요 속성
- numColumns : 그리드로 구성할 칸의 개수. auto_fit 으로 설정하면 디바이스에 맞게 자동으로 구성된다.
GridView의 주요 이벤트
- ItemClick : 사용자가 항목을 선택했을 경우.
ViewPager(PagerAdapte)
- ViewPager는 좌우로 스와이프 할 때 View가 전환된는 AdapterView 이다.
- 화면이 바뀌는 것이 아닌 화면의 크기만한 View들을 생성하여 View들을 전환하는 개념이다.
- 현재 ViewPager를 업그레이드한 ViewPager2를 제공하고 있다.
- ViewPager, ViewPager2 모두 정상 작동하며 ViewPager는 View를 전환할 때, ViewPager2는 프래그먼트라는 것을 전환할 때 사용한다.
PagerAdapter
ViewPager는 PagerAdapter를 구현하여 사용한다.
PagerAdapter메서드
- getCount : ViewPager로 보여줄 View의 전체 개수
- instantiateItem : ViewPager로 보여줄 View 객체를 생성한다.
- isViewFromObject : instantiateItem 에서 만든 객체를 사용할 것인지의 여부를 결정한다.
- destroyItem : ViewPager에서 View가 사라질 때 제거하는 작업을 한다.
ViewPager의 주요 이벤트
PageChange : ViewPager에서 View가 전환될 때 반응하는 리스너
AutoCompleteTextView
EditText에 자동완성 기능을 추가한 View 이다.
사용자가 문자열을 입력하면 설정한 문자열 항목을 통해 자동완성 리스트를 제공한다.
MultiAutoCompleteTextView
Single/Multi ChoiceListView
SingleChoiceListView
Multi ChoiceListView
RecyclerView
- Android 5.0 때 추가된 View 이다.
- ListView와 GridView의 구현이 비슷한 부분이 많이 이를 통합한 View이다.
- RecyclerView는 ListView와 GridView를 합쳐 구현할 수 있도록 제공되는 View이다.
- RecyclerView는 Adapter를 직접 구현해 줘야 하며 이를 통해 항목을 자유롭게 구성할 수 있다.
- RecyclerView는 반드시 항목들을 어떠한 형태로 보여줄 것인가를 설정해야 한다. ()
ViewHolder 만들기
- ViewHolder 클래스는 항목 하나를 구성하는 View 들의 주소 값을 가지고 있는 클래스이다.
- 이 클래스는 RecyclerView의 Adapter 클래스 내부에 구현하여 준다.
inner class ViewHolderClass(itemView : View) : RecyclerView.ViewHolder(itemView) {
val rowImageView = itemView.rowImageView
val rowTextView = itemView.rowTextView
}
RecyclerView의 Adapter 클래스
- RecyclerView는 RecyclerView.Adapter 클래스를 상속받은 클래스를 작성하여 Adapter를 구성해야 한다.
- onCreateVeiwHolder : RecyclerView는 항목 하나를 구성하기 위해 ViewHolder를 사용한다. ViewHolder는 항목 내부를 구성하는 View 객체들을 관리하는 객체로 ViewHolder를 생성하고자 할 때 이 메서드를 호출한다.
- onBindViewHolder : 항목을 구성하기 위해 호출한다. 여기에서 ViewHolder가 가지고 있는 View들을 구성해준다.
- getItemCount : RecyclerView의 항목의 개수를 반환한다.
RecyclerView의 항목 배치
- RecyclerView는 ListView와 GridView를 통합한 View이다. 따라서 ListView 처럼 보여줄 것인지 GridView 처럼 보여줄 것인지 결정해야 한다.
- LinearLayoutManager : ListView 처럼 항목을 보여준다.
- GridLayoutManager : GridView 처럼 항목을 보여준다.
- StaggerGridLayoutManager : GridView 처럼 보여주지만 완전한 그리드가 아닌 각 항목의 크기에 따라 유동적으로 조절된다.
recycler_view.layoutManager = LinearLayoutManager(this)
recycler_view.layoutManager = GridLayoutManager(this, 2)
recycler_view.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
recycler_view.layoutManager = StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.HORIZONTAL)
'Android > Android UI' 카테고리의 다른 글
[Appbar] - Toolbar (0) | 2021.12.31 |
---|---|
View를 만드는 가장 기본적인 방법, LayoutInflater (0) | 2021.12.20 |
android custom ui (0) | 2021.08.24 |
[View]: Widget, layout (0) | 2021.04.17 |