[안드로이드 프로그래밍] Adapter View

PUJIN·2023년 6월 18일
0

android programming

목록 보기
9/26
post-thumbnail

Adapter View


개발자의 데이터 설정으로 화면을 구성하는 view

  • 대부분의 view는 배치시 기본적으로 정해진 속성에 따라 모양 구성

Adapter Class

view를 구성하기 위해 설정해야하는 데이터를 관리하는 Class

  • 사용 목적이나 적용할 view에 따라 다양하게 제공
  • 직접 생성 가능



📌 ListView

사용자가 정의한 데이터 목록을 아이템 단위로 구성하여 화면에 출력하는 ViewGroup


주요 속성
  • setAdapter : AdapterView를 구성하기 위해 사용하는 adapter 설정
    • ArrayAdapter : 칸 하나에 문자열 1개만 사용하는 경우
    • SimpleAdapter : 항목을 자유롭게 디자인하여 사용하는 경우

  • Context, 항목 1개를 구성할 레이아웃, 텍스트뷰에 채워줄 문자열 배열
    • context : 어떠한 작업을 위해 정보를 관리하는 요소
      * 안드로이드는 시스템이나 애플리케이션과 관련된 정보
val adapter = ArrayAdapter<String>(
	// this = MainActivity
	this, android.R.layout.simple_list_item_1, data1
)
listView.run{
		setAdapter(adapter)
}
  • Context, 항목 1개를 구성할 레이아웃, layout 파일 내 문자열을 설정할 View ID, 텍스트뷰에 채워줄 문자열 배열
listView.run{
	adapter = ArrayAdapter<String>(
		this@MainActivity, R.layout.row, R.id.textView2, data1
	)
}

주요 이벤트
  • ItemClick : 항목을 터치할 때 발생
    • setOnItemClickListener : 항목 하나를 선택할 때 동작하는 함수
      • position : 사용자가 터치한 항목의 순서값 (0부터 1씩 증가)
activityMainBinding.run{
	listView.run{
		setAdapter(adapter)
        
		setOnItemClickListener { parent, view, position, id -> 
			textView.text = "${data1[position]} 클릭"
		}
	}
}



ArrayAdapter

문자열 1개를 설정하는 경우

  • Context, 항목 1개를 구성할 레이아웃, 텍스트뷰에 채워줄 문자열 배열
    • android.R.layout.simple_list_item1 : 리스트뷰 항목 하나(textView 1개)를 구성할 때 사용하는 layout
      → 지정된 레이아웃 안 android.R.id.text1 View에 문자열 세팅
val adapter = ArrayAdapter<String>(
	// this = MainActivity
	this, android.R.layout.simple_list_item_1, data1
)

activityMainBinding.run{
	listView.run{
		setAdapter(adapter)
	}
}


ListView 요소 추가/삭제

  • notifyDataSetChanged : 갱신 요청
val adapter = listView.adapter as ArrayAdapter<String>
adapter.notifyDataSetChanged()

  1. 데이터 리스트 생성
val rowList = mutableListOf<String>()
  1. adapter 설정
activityMainBinding.run{
	listView.run{
		adapter = ArrayAdapter<String>(
			this@MainActivity, android.R.layout.simple_list_item_1, rowList
            )
	}
}
  1. 요소 추가
rowList.add("row : ${System.currentTimeMillis()}")

textView.text = "항목 개수 : ${rowList.size}개"

val adapter = listView.adapter as ArrayAdapter<String>
adapter.notifyDataSetChanged()
  • 요소 삭제
rowList.removeLast()

textView.text = "항목 개수 : ${rowList.size}개"

val adapter = listView.adapter as ArrayAdapter<String>
adapter.notifyDataSetChanged()



SimpleAdapter

항목을 자유롭게 디자인한 경우 사용하는 Adapter Class

  1. SimpleAdapter에 설정하는 ArrayList 내의 HashMap 수 만큼 항목 생성
  2. 각 항목을 개별적으로 구성
  3. 항목 하나를 구성하기 위해 해당 순서의 HashMap을 추출
  4. HashMap에 있는 데이터를 keys 배열에 들어있는 이름의 순서대로 추출
  5. ids 배열에 설정되어 있는 View의 ID 순서대로 데이터를 설정


  1. ListView 한 칸을 차지하는 layout 구성
  2. 데이터 리스트 생성
val dataList = ArrayList<HashMap<String, Any>>()
  1. 데이터 세팅
  • map : 항목 1개를 구성하기 위해 필요한 데이터 저장
for(idx in 0 until imgData.size){
	val map = HashMap<String, Any>()
                    
	map["img"] = imgData[idx]
	map["data1"] = textData1[idx]
	map["data2"] = textData2[idx]

	dataList.add(map)
}
  1. HashMap 데이터 구성시 사용한 key를 저장한 배열
val keys = arrayOf("img", "data1", "data2")
  1. 데이터를 저장해줄 View의 ID 배열
    * View의 ID : 'int' 타입으로 저장
val ids = intArrayOf(R.id.imageViewRow, R.id.textViewRow1, R.id.textViewRow2)
  1. SimpleAdater 생성
adapter = SimpleAdapter(
	this@MainActivity, dataList, R.layout.row, keys, ids
)



CustomAdapter

AdapterView 자체를 커스터마이징하여 특별한 기능을 사용하는 경우

BaseAdapter

baseAdapter를 상속받아 AdapterView 커스터마이징

  • getCount : 보여줄 항목의 개수 반환
  • getItem : 현재 순서의 보여줄 View 반환
  • getItemId : 현재 순서의 보여줄 View ID 반환
  • getView : 보여줄 항목의 View를 생성하여 반환
    → 해당 함수에서 반환하는 View를 현재 순서의 Row로 사용
    • view : 항목별 관리할 viewBinding 객체 필요
    • tag : view 안에 정보를 저장할 수 있는 요소 (객체 저장 가능)
    • 모든 항목의 viewBinding 객체는 pool로 이동
      → 새롭게 보이는 view에 보였다가 스크롤되어 보이지 않게된 항목의 viewBinding 객체를 추출하여 사용 → pool에서 관리
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
	// layout binding 객체를 담을 변수
	var rowBiding : RowBinding? = null
	// 항목 View를 담을 변수
	var mainView = convertView
	// 재사용 가능한 뷰가 없는 경우
	if(mainView == null){
    	// viewBinding 객체 생성
		rowBiding = RowBinding.inflate(layoutInflater)
		mainView = rowBiding.root
		mainView!!.tag = rowBiding
	}
	// 재사용 가능한 View가 있는 경우
	else {
    	// view에 저장되어 있는 viewBinding 객체 추출하여 사용
		rowBiding = mainView!!.tag as RowBinding
	}
}



📌 Spinner

항목을 나열하고 선택할 수 있도록 제공하는 AdapterView


주요 메서드
  • setSelection : 항목 선택 (index : 0부터 시작)
  • getSelectedItemPosition : 현재 선택된 항목의 인덱스 추출
val position = spinner.selectedItemPosition
textView.text = "선택 항목 : ${dataList[position]}"
  • setAdapter : AdapterView를 구성하기 위해 사용하는 adapter 설정
    • R.layout.simple_spinner_item : 접혔을 때의 모양
    • android.R.layout.simple_spinner_dropdown_item : 펼쳐져 있을 때의 항목 모양
      • setDropDownViewResource : 펼쳐져 있을 때의 항목 모양 설정
// spinner 항목 설정
val dataList = arrayOf(
	"data1","data2","data3"
)

activityMainBinding.run{
	spinner.run{
		val a1 = ArrayAdapter<String>(
			this@MainActivity, 
            R.layout.simple_spinner_item,
			dataList
		)
        
      	a1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
	}
}   

주요 이벤트
  • ItemSelected : 항목을 선택했을 때 발생
onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
                   
	override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
		textView.text = "${dataList[position]} 항목 선택"
	}

	override fun onNothingSelected(parent: AdapterView<*>?) {
		// TODO("Not yet implemented")
	}
}



📌 RecyclerView

  • lisView보다 효율적 → 작업의 간편성/효율성
  • 보였다가 스크롤되어 보이지 않게된 항목의 객체 전체가 pool에 저장되는 것이 아니라 항목 하나를 구성하는 view의 ID를 ViewHolder에 저장
  • Holder : 항목 1개를 구성하기 위해 포함되어 있는 view의 객체 주소값 관리

AdapterClass

  1. 아무것도 상속받지 않은 클래스 생성
inner class RecyclerAdapterClass {}
  1. ViewHolder 생성
inner class ViewHolderClass(rowBinding: RowBinding) : RecyclerView.ViewHolder(rowBinding.root) {}
  1. AdapterClass : RecyclerView.Adapter 상속
inner class RecyclerAdapterClass : RecyclerView.Adapter<RecyclerAdapterClass.ViewHolderClass>(){}
  1. 필요한 메서드 구현
  • implement members로 메서드 override
  • onCreateViewHolder : ViewHolder의 객체를 생성해서 반환
  • getItemCount : 전체 행의 개수 반환
  • onBindViewHolder : viewHolder를 통해 View에 접근하여 View 값 설정
    • holder: ViewHolderClass : viewHolder 객체
    • position : 특정 행의 순서값
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolderClass {

	val rowBinding = RowBinding.inflate(layoutInflater)       
	val viewHolderClass = ViewHolderClass(rowBinding)

	return viewHolderClass
}
        
override fun getItemCount(): Int {}
        
override fun onBindViewHolder(holder: ViewHolderClass, position: Int) {}

  • 항목 view의 가로/세로 길이 설정
    → 항목의 길이가 짧아도 끝부분에서 터치 가능하도록 MATCH_PARENT 설정
val params = RecyclerView.LayoutParams(
	// 가로 길이
	RecyclerView.LayoutParams.MATCH_PARENT,
 	// 세로 길이
	RecyclerView.LayoutParams.WRAP_CONTENT
)

rowBinding.root.layoutParams = params
  • recyclerView 구분선 설정
recyclerView.addItemDecoration(DividerItemDecoration(mainActivity, DividerItemDecoration.VERTICAL))

💻 전체 코드

inner class RecyclerAdapterClass : RecyclerView.Adapter<RecyclerAdapterClass.ViewHolderClass>(){
	inner class ViewHolderClass(rowBinding: RowBinding) : RecyclerView.ViewHolder(rowBinding.root), OnClickListener {

		var textViewRow:TextView
		var imageViewRow:ImageView

        init{
			textViewRow = rowBinding.textViewRow
			imageViewRow = rowBinding.imageViewRow
        }

		override fun onClick(v: View?) {
			activityMainBinding.textView.text = data[adapterPosition]
		}
        
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolderClass {
            // ViewBinding
            val rowBinding = RowBinding.inflate(layoutInflater)
            // ViewHolder
            val viewHolderClass = ViewHolderClass(rowBinding)

            // 클릭 이벤트 설정
            rowBinding.root.setOnClickListener(viewHolderClass)

            return viewHolderClass
        }
        
        override fun getItemCount(): Int {
            return imgList.size
        }
        
        override fun onBindViewHolder(holder: ViewHolderClass, position: Int) {
            holder.textViewRow.text = data[position]
            holder.imageViewRow.setImageResource(imgList[position])
        }
}

layoutManager (필수)

  • LinearLayoutManager : 위에서 아래(linear) 방향
  • GridLayoutManager : grid 모양
    • 한 항목의 사이즈가 다른 항목과 다를때 같은 행의 모든 뷰가 모두 같은 크기로 조정
    • spanCount : 한줄에 몇칸 사용할 것인지 설정
      • 1인 경우 : LinearLayoutManager와 동일
  • StaggeredGridLayoutManager : grid 모양
    • 한 항목의 사이즈가 다른 항목과 다를때 필요한 만큼만 사용하며 자신의 크기 유지 (빈칸 X)
activityMainBinding.run{
	recyclerView.run{
		adapter = RecyclerAdapterClass()

		layoutManager = LinearLayoutManager(this@MainActivity)
	}
}

notifyDataSetChanged

  • recyclerView 갱신하는 메서드
    • onResume에 설정하여 화면 전환 후 다시 돌아왔을 때 갱신할 수 있도록 세팅 가능
var adapter = activityMainBinding.recyclerView.adapter as MainActivity.RecyclerAdapter
adapter.notifyDataSetChanged()



🔥 listView VS RecyclerView


listView

adapter : 항목 view 생성

  • 거쳐가야하는 단계가 많다.
  • view 재사용

recyclerView

pool : 화면에 보여주기 위한 역할
adapter : 항목 view 생성 + holder 관리
holder : 항목 1개를 구성하는 view ID 값
-> 해당 항목의 holder에 접근하여 사용

  • viewHolder 재사용
  • view에 재사용에 관련한 코드 구현 완료
  • holder 사용에 관련된 코드 구현 필요

0개의 댓글