이 글은 이것이 안드로이드다 with 코틀린(개정판)를 참고하여 작성하였습니다.
작성자 : 심덕수
개발환경은 Windows, Android Studio입니다.
1. 리사이클러뷰
- 많은 수의 데이터 집합을 제한된 영역 내에서 유연하게 표시할 수 있도록 만들어주는 위젯이다.
- 한 화면에 표시되기 힘든 많은 수의 데이터를 스크롤 가능한 리스트로 표시해준다.
2. 리사이클러뷰 생성하기
(1) 레이아웃 폴더에 레이아웃 리소스 파일 생성하기
** 파란 하이라이트 부분을 변경하여 레이아웃 유형을 변경할 수 있다. linear로 변경
(2) 레이아웃 리소스 파일의 레이아웃을 horizontal로 설정한 뒤 text view 위젯 3개 추가한다.
** 각 위젯의 layout_weight를 1:5:3 비율로 설정한다.
이때, layout_width값이 0dp여야만 설정값만큼의 비율로 나누어진다.
(3) data 클래스 생성 : 사용할 데이터 정의
** data class Memo (var no:Int, var title:String, var timestamp:Long)
-> timestamp는 1970년 1월 1일 00시 00분 00초부터 헤아려진 날짜를 숫자로 표현한 것이다.
** val memoList = mutableListOf<memo>()
for(idx in 1..100){
val memo = Memo(idx, "첼로", 123456878)
memoList.add(memo)
}
-> memo 클래스형의 데이터를 리사이클러뷰에 담기 위한 데이터를 생성하기 위한 반복문이다.
memo 클래스 형의 반복문을 통해 생성된 데이터를 담을 리스트를 생성한다.
(4) main activity에서 data를 생성하는 로드 데이터 라는 메시지를 생성한다.
** fun loadData() : MutableList<Memo>{
val memoList = MutableListOf<Memo>()
for(no in 1..100){
val title = "이것이 안드로이드다 $no"
val date = System.currentTimeMillis()
val memo = Memo(no, title, date)
memoList.add(memo)
}
return memoList
}
-> loadData() 함수를 호출할 경우, memoList 리스트에 인덱스가 1~100까지의 메모형 가상 데이터들이 생성되어 넘겨진다.
(5) main activity에서 어댑터를 생성한다.(어댑터 틀 생성하기)
**
class CustomAdapter : RecyclerView.Adapter<CustomAdapter.Holder>(){
class Holder(binding: ItemRecyclerBinding): RecycleView.ViewHolder(binding.root){ }
}
-> RecyclerView 화면 전체를 관리한다.
-> holder : 화면 내에 이치한 아이템 하나하나를 관리한다. 홀더는 클래스로 미리 만들어놓아야 한다. 이후 RecyclerView에 집어넣는다.
-> 위의 어댑터를 연결하기 위해서는 gradle 파일에 미리 뷰바인딩을 연결해놓아야 한다.
-> class CustomAdapter : RecyclerView.Adapter<CustomAdapter.Holder>()
제네릭은 위에서 해당 홀더를 통해 개별 아이템을 관리하여야 하므로 홀더를 설정해놓는다.
CustomAdapter 는 RecyclerView.Adapter를 상속받는다.
-> class Holder(binding: ItemRecyclerBinding): RecycleView.ViewHolder(binding.root)
Holder 는 RecycleView.ViewHolder를 상속받는다.
Holder의 파라미터를 통해 미리 생성해놓은 ItemRecyclerBinding 레이아웃을 연결하고
viewHolder의 파라미터로는 binding.root를 받는다.
(6) main activity에서 어댑터를 생성한다.(어댑터 세부 메서드 구현하기)
** ctrl + i를 통해 인터페이스 내부의 메서드를 구현한다.
class CustomAdapter : RecyclerView.Adapter<CustomAdapter.Holder>(){
class Holder(binding: ItemRecyclerBinding): RecycleView.ViewHolder(binding.root){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val binding = ItemRecyclerBinding.inflate(LayoutInflater.from(parent.context), parent, attatchParent: false)
return Holder(binding)
}
override fun getItemCount(): Int {
return listData.size
}
override fun onBindViewHolder(holder: Holder, position: Int) {
val memo = listData.get(position)
holder.setMemo(memo)
}
class Holder(val binding:ItemRecyclerBinding):recyclerView.ViewHolder(binding.root){
fun setMemo(memo:Memo){
binding.textNo.text = "${memo.no}"
binding.textTitle.text = memo.title
val sdf = SimpleDateFormet(pattern: "yyyy-MM-dd")
val formattedDate = sdf.format(memo.timestamp)
textDate.text = formattedDate
}
}
}
}
-> holder 메서드의 경우 밖으로 빼낼 수도 있지만, 주로 내부에서 사용하기 때문에 내장 함수로 사용하는 것이 좋다.
-> var listData = MutableListOf<Memo> : 어댑터가 사용할 데이터 목록을 생성한다.
코드의 양을 줄이기 위하여 CustomAdapter(var listData:MutableListOf<Memo>)로 사용가능하다.
loadData() 의 데이터 타입과 동일하다.
-> override fun getItemCount(): Int : 목록의 개수를 알려준다. 목록의 사이즈(높이)가 여기서 결정된다.
-> override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder :
화면에 위치시킬 아이템을 하나하나 생성한다.
화면에 보이는 만큼만 생성해 놓고 재사용하는 것이 리사리클러뷰의 특징이다.
-> override fun onBindViewHolder(holder: Holder, position: Int) :
이때 재사용 리사이클러뷰의 특징이 사용된다.
oncreateViewHolder에서 생성된 아이템 이후에 새롭게 호출되어야 하는 아이템들을 재사용하여 호출한다.
** 홀더의 패턴 : 사용할 데이터를 꺼낸다(val memo = listData.get(position)) : position의 값을 통해 사용자가 선택한 데이터를 담는다.
-> 홀더에 데이터를 전달한다(holder.setMemo(memo)) : memo의 값을 홀더에 전달한다.
-> 받은 데이터를 화면에 출력한다.(홀더 클래스에서 일어난다.) : binding을 통해 화면의 위젯에 직접접근하여 각각의 데이터를 넣어준다.
이때, with scope 함수를 통해 binding을 축약하여 간단한 코드작성이 가능하다.
** SimpleDateFormet(pattern: "yyyy-MM-dd") : 이때 date은 형식을 지정해주는 메서드를 사용한다.
(7) mainActivity에서 가상의 데이터를 생성하고 어댑터를 통해 레이아웃에 연결한다.
- 데이터를 생성한다.
- 앞서 생성해놓은 어댑터를 생성하는 메서드를 통해 어댑터를 생성하고 recyclerView 내부의 adapter 메서드를 활용하여 화면과 연결한다.
- 레이아웃 매니저를 설정하는 과정에서 리스트 형태로 화면을 구성할 수도, 그리드 형태로 구성할 수도 있다.
class MainActivity : AppCompatActivity() {
val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
1. 데이터 불러오기
val data = loadData()
2. 커스텀어댑터 생성하기
val customAdapter = CustomAdapter(data)
3. 화면의 RecyclerView와 연결하기
binding.recyclerView.adapter = customAdapter
4. 레이아웃 매니저
binding.recyclerView.layoutManager = LinearLayoutManager(this)
}
(8) 클릭처리 설정하기
- 각 데이터 한 칸이 클릭되었을 때의 처리동작을 설정한다.
- 클릭처리는 init 에서만 해야 한다. 그렇지 않을 경우, 심각한 자원낭비를 유발한다.
class Holder(val binding:ItemRecyclerBinding):recyclerView.ViewHolder(binding.root){
var currentMemo:Memo? = null
init {
binding.root.setOnClickListener { int: View!
Toast.makeText(binding.root.context, "클릭된 아이템: ${currentMemo.title}", Toast.LENGHT_SHORT).show()
}
fun setMemo(memo:Memo){
binding.textNo.text = "${memo.no}"
binding.textTitle.text = memo.title
val sdf = SimpleDateFormet(pattern: "yyyy-MM-dd")
val formattedDate = sdf.format(memo.timestamp)
textDate.text = formattedDate
}
}
-> var currentMemo:Memo? = null : 전역변수를 통해 클릭된 아이템을 저장함으로써 화면에 출력한다.
이렇게 구성할 경우, 화면에 출력하지 않은 데이터를 활용할 수도 있다.
만약 계속해서 데이터를 클릭하는 경우라면, lateinit var currentMemo: Memo 로 작성할 수도 있다.
'GDSC HUFS 3기 > Android with Kotlin Team 3' 카테고리의 다른 글
[3팀] 14-9 화면 구성하기: 탭메뉴 뷰 페이저와 프래그먼트 (0) | 2021.11.14 |
---|---|
[3팀] 11. 화면 구성하기_프래그먼트와 프래그먼트끼리 값주고받기 (0) | 2021.11.08 |
[3팀] 9. 화면 구성하기_스피너 (0) | 2021.11.06 |
[3팀] 8.액티비티 값주고받기 뷰바인딩 (0) | 2021.11.06 |
[3팀] 7-2. 위젯활용(2) (0) | 2021.10.29 |