[Android/Kotlin] RecyclerView ๋งŒ๋“ค๊ธฐ

2021. 1. 14. 02:40ใ†๐Ÿ“ฑAndroid/๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป Android ๊ฐœ๋ฐœ ์ผ์ง€

๋ฐ˜์‘ํ˜•

์˜ค๋Š˜์€ ๊ฐ„๋‹จํ•œ ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ ์‹œ๋ฆฌ์ฆˆ 1ํƒ„์ธ RecyclerView ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์†Œ๊ฐœํ•ด๋ณด๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค!

 

RecyclerView ๋ž€?!

RecyclerView๋ž€ ? ๋ฐ์ดํ„ฐ ์ง‘ํ•ฉ๋“ค์„ ๊ฐ๊ฐ์˜ ๊ฐœ๋ณ„ ์•„์ดํ…œ ๋‹จ์œ„๋กœ ๊ตฌ์„ฑํ•˜์—ฌ ํ™”๋ฉด์— ์ถœ๋ ฅํ•ด์ฃผ๋Š” ๋ทฐ ๊ทธ๋ฃน์ด๋ฉฐ, ์ˆ˜ ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์Šคํฌ๋กค ๊ฐ€๋Šฅํ•œ ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ํ‘œ์‹œํ•ด์ฃผ๋Š” ์œ„์ ฏ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, ์•„๋ž˜ ์‚ฌ์ง„๊ณผ ๊ฐ™์ด ๋™์ผํ•œ ํ˜•์‹์„ ๊ฐ–๋Š” ์ˆ˜ ๋งŽ์€ ๋ฆฌ์ŠคํŠธ๋“ค์„ ๊ตฌํ˜„ํ•  ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

RecyclerView์™€ ListView์˜ ์ฐจ์ด๋Š” ?!

๋‘˜๋‹ค ๋™์ผํ•œ ํ˜•์‹์˜ ๋ฆฌ์ŠคํŠธ๋“ค์„ ๊ตฌํ˜„ํ•  ๋•Œ ์‚ฌ์šฉํ•˜์ง€๋งŒ ListView์™€ RecyclerView์—๋Š” ๋น„์Šทํ•œ๊ฑฐ ๊ฐ™์ง€๋งŒ ์„ธ๋ฐ€ํ•œ ์ฐจ์ด๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

  RecyclerView ListView
ViewHolder ViewHolder ํŒจํ„ด์„ ์ด์šฉํ•œ๋‹ค. ViewHolder ํŒจํ„ด ์ด์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
Item Layout ๊ฐ€๋กœ, ์„ธ๋กœ, Grid ํ˜•์‹ ๋ชจ๋‘ ์ง€์› ์„ธ๋กœ ๋ฐฉํ–ฅ๋งŒ ์ง€์›
Item Animation  ์•„์ดํ…œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฒ˜๋ฆฌ ํด๋ž˜์Šค ์กด์žฌ ์•„์ดํ…œ ์ถ”๊ฐ€/์ œ๊ฑฐ์‹œ์— ์ ์šฉ๊ฐ€๋Šฅํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์—†๋‹ค.
Decoration RecyclerView.ItemDecoration ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ๋ถ„์„ ์„ ์„ค์ •ํ•ด์•ผํ•œ๋‹ค. Android:divider ์†์„ฑ์„ ์ด์šฉํ•˜์—ฌ ๋ฆฌ์ŠคํŠธ์— ์žˆ๋Š” ์•„์ดํ…œ์„ ์‰ฝ๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค.
Click Detection ๊ฐœ๋ณ„ ํ„ฐ์น˜ ์ด๋ฒคํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜์ง€๋งŒ ํด๋ฆญ ์ฒ˜๋ฆฌ ๊ธฐ๋Šฅ์ด ๋‚ด์žฅ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค. ๋ชฉ๋ก์˜ ๊ฐœ๋ณ„ ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ํด๋ฆญ ์ด๋ฒคํŠธ์— ๋ฐ”์ธ๋”ฉํ•˜๊ธฐ ์œ„ํ•œ AdapterView.OnItemClickListener ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ๋‹ค.

์ด๋•Œ ListView๋ณด๋‹ค RecyclerView๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์žฅ ํฐ ์ด์œ ๋Š” ์žฌ์‚ฌ์šฉ์„ฑ ์ด ํ›จ์”ฌ ์ข‹๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ListView๋Š” ViewHolder ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์‹œ ์•Š๊ณ  getView()๋ฅผ ์ด์šฉํ•˜์—ฌ View์— ์ ‘๊ทผํ•˜๋Š”๋ฐ , ์ด์ฒ˜๋Ÿผ getView()๋กœ ๋™์ž‘ํ•˜๊ฒŒ ๋˜๋ฉด ๋ฆฌ์Šคํฌ ๊ฐฏ์ˆ˜๋งŒํผ getView()๊ฐ€ ํ˜ธ์ถœ ๋˜๋ฏ€๋กœ ๋งค์šฐ ๋น„ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ RecyclerView๋Š” ViewHolder๋ฅผ ํ†ตํ•ด ๋งŒ๋“  ๊ฐ์ฒด๋ฅผ ์žฌ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ListView๋ณด๋‹ค RecyclerView๊ฐ€ ์žฌ ์‚ฌ์šฉ์„ฑ ๋ถ€๋ถ„์—์„œ ๋” ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

 

RecyclerView ์ฃผ์š” ํด๋ž˜์Šค 

View Holder 

๊ฐ๊ฐ์˜ ๋ทฐ๋ฅผ ๋ณด๊ด€ํ•˜๋Š” Holder ๊ฐ์ฒด ์ž…๋‹ˆ๋‹ค.

Item ๋ทฐ๋“ค์„ ์žฌํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ ์š”์†Œ๋ฅผ ์ €์žฅํ•ด๋‘๊ณ  ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์•„์ดํ…œ ์ƒ์„ฑ์‹œ ๋ทฐ ๋ฐ”์ธ๋”ฉ์€ ํ•œ ๋ฒˆ๋งŒํ•˜๋ฉฐ, ๊ทธ ๋ฐ”์ธ๋”ฉ ๋œ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ๋‹ค ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ ๋ถ€๋ถ„์—์„œ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

 

LayoutManager

์•„์ดํ…œ์˜ ๋ฐฐ์น˜๋ฅผ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. 

LinearLayoutManager - ๊ฐ€๋กœ / ์„ธ๋กœ

GridLayoutManager - ๊ทธ๋ฆฌ๋“œ ํ˜•์‹

StaggeredGridLayoutManager - ์ง€๊ทธ์žฌ๊ทธํ˜•์˜ ๊ทธ๋ฆฌ๋“œ ํ˜•์‹

 

Adapter

ListView์™€ ๋™์ผํ•œ Adapter์˜ ๊ฐœ๋…์œผ๋กœ ๋ฐ์ดํ„ฐ์™€ ์•„์ดํ…œ์— ๊ด€ํ•œ View๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

 

ItemAnimation

Item ์ถ”๊ฐ€ / ์‚ญ์ œ์‹œ์— ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

ItemDecoration

RecyclerView์˜ ์•„์ดํ…œ์„ ๊พธ๋ฏธ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ๋กœ Divider๋ฅผ ์„ค์ •ํ•  ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

 

Click Detection 

Click Listener๊ฐ€ ListView ์ฒ˜๋Ÿผ ๋‚ด์žฅ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฏ€๋กœ, onClickListner๋ฅผ ํ†ตํ•ด ์ง์ ‘ ๊ตฌํ˜„ํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

 

RecyclerView ๋งŒ๋“ค๊ธฐ

์ด์ œ RecyclerView๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

๋จผ์ € ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ์— ๋ฐ˜๋ณต๋  ์•„์ดํ…œ์˜ View๋กœ ์‚ฌ์šฉ๋  Layout์„ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•ด์ฃผ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“Œ item_recycler_ex.xml

layout -> New -> Layout Resource File

 

 

ImageView์™€ TextView๋กœ ์ด๋ฃจ์–ด์ง„ Layout ํ•˜๋‚˜๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:tools="http://schemas.android.com/tools"
    android:paddingHorizontal="20dp"
    android:paddingVertical="10dp"
    android:background="@color/purple_500"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <ImageView
        android:id="@+id/img_rv_photo"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@color/black"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

    <TextView
        android:id="@+id/tv_rv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="์ด๋ฆ„"
        android:textStyle="bold"
        android:layout_marginLeft="20dp"
        android:textSize="24sp"
        android:textColor="@color/white"
        app:layout_constraintLeft_toRightOf="@id/img_rv_photo"
        app:layout_constraintTop_toTopOf="parent"/>

    <TextView
        android:id="@+id/tv_rv_age"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="๋‚˜์ด"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="20dp"
        android:textSize="18sp"
        android:textColor="@color/white"
        app:layout_constraintLeft_toRightOf="@id/img_rv_photo"
        app:layout_constraintTop_toBottomOf="@id/tv_rv_name"/>


</androidx.constraintlayout.widget.ConstraintLayout>

 

๐Ÿ“Œ activity_main.xml ์— RecyclerView ์ถ”๊ฐ€ํ•ด์ฃผ๊ธฐ

Linear ํ˜•์‹์˜ ์„ธ๋กœ๋กœ ๋‚˜์—ด ๋œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ ์ €๋Š” LinearLayout, Vertical ๋กœ ์„ค์ •ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

app:layoutMananger = "androidx.recyclerview.widget.LinearLayoutManager"
android:orientation ="vertical" 

<?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">

   <androidx.recyclerview.widget.RecyclerView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:id="@+id/rv_profile"
       app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
       android:orientation="vertical"
       tools:listitem="@layout/item_recycler_ex"
       app:layout_constraintTop_toTopOf="parent"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

 

RecyclerView ๋งŒ๋“ค๊ธฐ - Adapter / ViewHolder ๋งŒ๋“ค์–ด์ฃผ๊ธฐ

๋ทฐ ๊ฐ์ฒด๋ฅผ ๊ทธ๋ ค์ฃผ๋Š” ViewHolder์™€ Data์™€ View๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” Adapter๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“Œ ProfileAdpater.kt

ProfileAdpater์— ViewHolder๋ฅผ ๊ฐ™์ด inner class๋กœ ๋งŒ๋“ค์–ด์ฃผ์—ˆ์œผ๋ฉฐ, ProfileData๋ฅผ ๋งŒ๋“ค์–ด data๋ฅผ view์™€ ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

img๋ฅผ ์‰ฝ๊ฒŒ imgProfile์— ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ๊ธฐ ์œ„ํ•ด์„œ Glide๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

 

bumptech/glide

An image loading and caching library for Android focused on smooth scrolling - bumptech/glide

github.com

package com.example.recyclerview_ex

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide

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

    var datas = mutableListOf<ProfileData>()
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.item_recycler_ex,parent,false)
        return ViewHolder(view)
    }

    override fun getItemCount(): Int = datas.size

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

    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {

        private val txtName: TextView = itemView.findViewById(R.id.tv_rv_name)
        private val txtAge: TextView = itemView.findViewById(R.id.tv_rv_age)
        private val imgProfile: ImageView = itemView.findViewById(R.id.img_rv_photo)

        fun bind(item: ProfileData) {
            txtName.text = item.name
            txtAge.text = item.age.toString()
            Glide.with(itemView).load(item.img).into(imgProfile)

        }
    }


}

๐Ÿ“Œ ProfileData.kt

package com.example.recyclerview_ex

data class ProfileData (
    val name : String,
    val age : Int,
    val img : Int
)

 

RecyclerView ๋งŒ๋“ค๊ธฐ - MainActivity.kt  Adatper์™€ RecyclerView ์—ฐ๊ฒฐ

RecyclerView๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์œ„์—์„œ ๋งŒ๋“ค์–ด์ค€ Adpater์™€ RecyclerView๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์„œ๋ฒ„์™€ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๋ฉด ๋”๋ฏธ data๋ฅผ Adapter์— ๋„ฃ์–ด์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿ“Œ MainActivity.kt

package com.example.recyclerview_ex

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    lateinit var profileAdapter: ProfileAdapter
    val datas = mutableListOf<ProfileData>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        initRecycler()
    }
    private fun initRecycler() {
        profileAdapter = ProfileAdapter(this)
        rv_profile.adapter = profileAdapter


        datas.apply {
            add(ProfileData(img = R.drawable.profile1, name = "mary", age = 24))
            add(ProfileData(img = R.drawable.profile3, name = "jenny", age = 26))
            add(ProfileData(img = R.drawable.profile2, name = "jhon", age = 27))
            add(ProfileData(img = R.drawable.profile5, name = "ruby", age = 21))
            add(ProfileData(img = R.drawable.profile4, name = "yuna", age = 23))

            profileAdapter.datas = datas
            profileAdapter.notifyDataSetChanged()

        }
    }
}

 

์œ„ ์ˆœ์„œ๋ฅผ ์ฐจ๋ก€๋กœ ๋”ฐ๋ผ์˜ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ๊ฐ€ ์™„์„ฑ๋ฉ๋‹ˆ๋‹ค!

ํ•˜์ง€๋งŒ ! ๊ฐ„๊ฒฉ ์กฐ์ ˆ์ด ๋˜์–ด์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. 

RecyclerView์˜ ์กด์žฌํ•˜๋Š” ItemDecoration()์„ ์ด์šฉํ•˜์—ฌ Item๋งˆ๋‹ค์˜ ๊ฐ„๊ฒฉ์„ ์กฐ์ •ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

 

VerticalItemDecorator / HorizontalItemDecorator Class ๋งŒ๋“ค๊ธฐ

RecyclerView์˜ ItemDecoration()์„ ์ด์šฉํ•˜์—ฌ Item์˜ ๊ฐ„๊ฒฉ์„ ์กฐ์ •ํ•ด์ฃผ๋Š” ItemDecoratorClass๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.RecyclerView


class VerticalItemDecorator(private val divHeight : Int) : RecyclerView.ItemDecoration() {

    @Override
    override fun getItemOffsets(outRect: Rect, view: View, parent : RecyclerView, state : RecyclerView.State) {
        super.getItemOffsets(outRect, view, parent, state)
        outRect.top = divHeight
        outRect.bottom = divHeight
    }
}
import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.RecyclerView

class HorizontalItemDecorator(private val divHeight : Int) : RecyclerView.ItemDecoration() {

    @Override
    override fun getItemOffsets(outRect: Rect, view: View, parent : RecyclerView, state : RecyclerView.State) {
        super.getItemOffsets(outRect, view, parent, state)
        outRect.left = divHeight
        outRect.right = divHeight
    }
}

 

๐Ÿ“Œ RecyclerView์— ItemDecorator ์ ์šฉํ•˜๊ธฐ (MainActivity.kt)

rv_profile.addItemDecoration(VerticalItemDecorator(20))
rv_profile.addItemDecoration(HorizontalItemDecorator(10))

MainActivity์— ์œ„์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด !? ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ„๊ฒฉ์ด ์กฐ์ •๋œ ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ๋ฅผ ๋งŒ๋“œ์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

 

๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ๋Š” ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ์—์„œ ์œ ์šฉํ•˜๊ฒŒ ์“ฐ์ด๋Š” ํด๋ฆญ์ด๋ฒคํŠธ์™€, Animation_transition์„ RecyclerView์— ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž‘์„ฑํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

 

 

์ฐธ๊ณ 

 

RecyclerView ํŠน์ง• / RecyclerView์™€ ListView์˜ ์ฐจ์ด

RecyclerView ์ƒˆ๋กœ์šด ViewGroup์œผ๋กœ, ListView์™€ GridView์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. RecyclerView์™€ ListView์˜ ์ฐจ์ด์  ์š”์•ฝ ListView์—์„œ๋Š” ๊ฐ ์•„์ดํ…œ๋“ค์„ ์ƒ์„ฑํ•  ๋Œ€๋งˆ๋‹ค ๋ทฐ ๋ฐ”์ธ๋”ฉ์„ ๊ณ„์†ํ•ด์„œ ํ•ด์ฃผ์–ด ์„ฑ๋Šฅ์ €ํ•˜๊ฐ€ ์ผ..

beenii.tistory.com

 

 

๋ฐ˜์‘ํ˜•