본문 바로가기
개발

(20) 독학으로 앱 만들어보기 (RecycleView 3편)

by 라이프_디자이너 2023. 1. 8.
반응형

지난 글에 이어서 RecycleView 사용법 설명을 이어간다.


(여담) 글을 잘 보고 있다는 댓글이 가끔 보이는데 글 작성에 많은 힘이 된다. 감사합니다.

 

2022.03.16 - [개발] - (5) 독학으로 앱 만들어보기 (아이디어 도출, 구상하는 법)

 

(5) 독학으로 앱 만들어보기 (아이디어 도출, 구상하는 법)

이 글은 독학으로 앱 만들어보기 시리즈로 앱을 만들기 위한 기술 공부와 기획 디자인 모두 다뤄볼 예정입니다. 이번 포스팅에서는 앱을 만들기 위한 아이디어 도출 및 구상하는 방법에 대해 알

dev-nasus.tistory.com

2023.01.05 - [개발] - (18) 독학으로 앱 만들어보기 (RecycleView 1편)

 

(18) 독학으로 앱 만들어보기 (RecycleView 1편)

23년이 되었네요. 새해 복 많이 받으세요. 지난 글에 이어서 적어보겠습니다. 지난 글에서 2개의 의문점을 남겼는데 그중에서 RecycleView는 어떻게 사용하는 거지? 에 대한 의문점을 해소해 본다.

dev-nasus.tistory.com

2023.01.06 - [개발] - (19) 독학으로 앱 만들어보기 (RecycleView 2편)

 

(19) 독학으로 앱 만들어보기 (RecycleView 2편)

어제에 이어서 RecycleView 설명 2편! 2023.01.05 - [개발] - (18) 독학으로 앱 만들어보기 (RecycleView 1편) (18) 독학으로 앱 만들어보기 (RecycleView 1편) 23년이 되었네요. 새해 복 많이 받으세요. 지난 글에 이

dev-nasus.tistory.com

 

어떤 화면을 보여줄 것인지에 대해서는 코딩을 완료했다. 이제는 Android 공식 홈페이지를 통해 연마했던 Kotlin을 사용해서 코딩을 해보자!

 

4. DataSet

지난 글에서 정해두었던 내용을 코딩으로만 옮겨본다. data 라는 키워드를 사용하여 View 안에 들어가 데이터들의 껍데기를 만든다고 생각하면 된다. 개발 공부하면 객체의 개념 설명으로 자주 나오는 붕어빵 틀이라고 보면 된다.

반응형

 

 GoalData.kt
package com.example.cometrue

data class GoalData (
    val goalContent : String,
    val goalCount : Int,
    val isNowGoal : Boolean
)

 

5. Adapter에서 Layout과 DataSet 합체!

 

이제 대망의 Adapter 코딩 차례다. 여기서는 RecycleView 안에서 반복되는 View와 DataSet을 연결하고 컨트롤하는 코딩을 한다. Adapter 구성요소로 6개가 있다. 하나씩 설명해 본다.

  • mutableListOf<DataSet>()
  • getItemCount(): Int
  • getItemViewType(position: Int) : Int
  • onCreateViewHolder(parent: ViewGroup, viewType: Int) : ViewHolder
  • onBindViewHolder(holder: ViewHolder, position: Int)
  • inner class ViewHolder(view: View)

 

mutableListOf<DataSet>()

View에 보여줄 데이터들을 저장하고 있을 변수가 필요하다. mutableListOf 예약어를 통해 우리가 미리 정의한 DataSet 배열리스트 변수를 만들어 준다.

var dataList = mutableListOf<GoalData>()

 

getItemCount(): Int

 

RecycleView는 View의 반복이라고 했다. 그렇다면 언제까지 반복할 것인가? 이 문제를 해결하기 위해 getItemCount 라는 함수가 Adapter에 존재하고 여기에는 우리가 보여줄 데이터가 몇 개인지를 알려주는 코딩을 하면 된다. View에서 보여줄 데이터는 위에서 dataList 라는 변수를 만들었다.

override fun getItemCount(): Int = dataList.size

 

getItemViewType(position: Int) : Int

 

getItemCount()를 통해 몇 번 반복할 건지는 정했는데, 반복되는 View가 컴퓨터에서 모두 동일하게  인식된다면 우리는 View 각각을 컨트롤 할 수 없다. 그래서 getItemViewType 함수에서 View의 번호를 알려주는 역할을 한다. 말 그대로 번호를 알려주는 역할만 하기때문에 코딩을 생략해도 된다.

    override fun getItemViewType(position: Int): Int {
        return super.getItemViewType(position)
    }

 

onCreateViewHolder(parent: ViewGroup, viewType: Int) : ViewHolder

 

어떤 데이터로 몇번 View를 반복할건지 그리고 View의 번호까지 부여했다. onCreateViewHolder 함수를 통해서 번호를 부여받은 View가 어떤 Layout인지 연결해주는 코드가 들어간다. 지난 글에서 보여주려는 View를 goal_item.xml 파일에 정의하였고 아래 코드를 통해 Adapter와 View를 연결했다.

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.goal_item,parent,false)
        return ViewHolder(view)
    }

 

onBindViewHolder(holder: ViewHolder, position: Int)

 

onCreateViewHolder를 통해 어떤 View와 연결할 것인지 정해졌고, onBindViewHolder 에서는 View와 실제 어떤 데이터를 연결할 것인지 알려준다. dataList는 전체 데이터를 갖고 있는 변수다. position 이라는 View를 구분하는 값에 따라 데이터를 하나씩 View에 전달해 준다.

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(dataList[position])
    }

 

inner class ViewHolder(view: View)

onBindViewHolder에서 데이터와 View를 연결할 때, View안에서도 여러 가지 요소들이 있다. 텍스트나 이미지와 같은 것들이다. 내가 goal_item.xml 에서 정의한 요소들은 3가지였다.

  • 목표 내용
  • 목표 달성 횟수
  • 라디오 버튼

inner class ViewHolder 에서는 이 3가지 항목에 어떻게 데이터를 표현할 것인지 코딩한다.

    inner class ViewHolder(view : View): RecyclerView.ViewHolder(view){
        private val textGoalContent: TextView = itemView.findViewById(R.id.text_goal_content)
        private val textGoalCount: TextView = itemView.findViewById(R.id.text_goal_count)
        private val radioIsNowGoal : RadioButton = itemView.findViewById(R.id.radio_is_now_goal)

        fun bind(item: GoalData) {
            textGoalContent.text = item.goalContent
            textGoalCount.text = item.goalCount.toString() + "번 달성"
            radioIsNowGoal.isChecked = item.isNowGoal
        }

    }

 

GoalListAdapter.kt
package com.example.cometrue

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RadioButton
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class GoalListAdapter(private val context: Context) : RecyclerView.Adapter<GoalListAdapter.ViewHolder>() {

    var dataList = mutableListOf<GoalData>()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.goal_item,parent,false)
        return ViewHolder(view)
    }

    override fun getItemCount(): Int = dataList.size

    override fun getItemViewType(position: Int): Int {
        return super.getItemViewType(position)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(dataList[position])
    }

    inner class ViewHolder(view : View): RecyclerView.ViewHolder(view){
        private val textGoalContent: TextView = itemView.findViewById(R.id.text_goal_content)
        private val textGoalCount: TextView = itemView.findViewById(R.id.text_goal_count)
        private val radioIsNowGoal : RadioButton = itemView.findViewById(R.id.radio_is_now_goal)

        fun bind(item: GoalData) {
            textGoalContent.text = item.goalContent
            textGoalCount.text = item.goalCount.toString() + "번 달성"
            radioIsNowGoal.isChecked = item.isNowGoal
        }

    }

}

 

6. Activity에서 Adapter와 보여줄 화면 Layout 결합!

 

이제 화면을 보여주는 MainActivity에 RecycleView Layout과 Adapter를 결합한다. setContentView에 RecycleView가 있는 goal_list.xml Layout을 설정했다. 그다음 initRecycler 라는 함수를 만들어서 RecycleView에다가 Adapter를 연결했다. 마지막으로 이미 저장되어 있는 보여줄 데이터가 없어서, dataList.apply 를 구현하였다. notifyDataSetChanged 함수는 RecycleView에 데이터가 변경되었음을 알려주는 함수다. ※increaseGoalCount, showText 함수는 무시하면 된다.

 

MainActivity.kt
package com.example.cometrue

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.*
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {
    private var goalCount: Int = 0
    lateinit var goalListAdapter: GoalListAdapter
    val dataList = mutableListOf<GoalData>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

//        setContentView(R.layout.lock)
//        val btnGoal : Button = findViewById(R.id.btn_goal)

//        btnGoal.setOnClickListener { showText() }
//        btnGoal.setOnClickListener {increaseGoalCount()}

        setContentView(R.layout.goal_list)
        initRecycler()
    }
    private fun initRecycler(){
        goalListAdapter = GoalListAdapter(this)
        this.findViewById<RecyclerView>(R.id.list_goal).adapter = goalListAdapter

        dataList.apply {
            add(GoalData("23년 12월 31일 월 순수익 1억을 벌었다.",110, true))
            add(GoalData("23년 9월 31일 건강한 세 식구를 가졌다.",20, false))
            add(GoalData("23년 2월 1일 어플 5개를 개발했다.",50, false))

            goalListAdapter.dataList = dataList
            goalListAdapter.notifyDataSetChanged()
        }
    }

    private fun increaseGoalCount() {
        val textGoalCount: TextView = findViewById(R.id.text_count)
        goalCount++

//        textGoalCount.setText(""+goalCount)
        textGoalCount.setText(goalCount.toString())
    }

    private fun showText() {
        val editGoal: EditText = findViewById(R.id.edit_goal)
        Toast.makeText(this,editGoal.text, Toast.LENGTH_SHORT).show()
    }
}

최종 결과

 

의도한 대로 RecycleView에 반복적으로 View가 표시되는 것을 확인할 수 있다.

 

이제 보여주는 화면도 만들었으니 다음 글에서는 목표를 추가, 삭제하는 기능을 구현하기 위한 sqlite 데이터베이스 사용에 대해 다뤄보도록 한다.

반응형

댓글