티스토리 뷰

728x90

 


ListView

컨테이너 뷰에 자식 뷰들을 동적으로 넣는 방법.

• 같은 틀(배치, 속성)에 내용물만 다른 형태 뷰들을 반복적으로 넣을 때 사용

• Adapter를 사용한다.

• addView의 단점을 보완한 뷰

     addView는 앱 사용 도중 변경되는 데이터에 대한 갱신이 어렵다. -> ListView는 Adapter.notifyDataSetChanged()를 통해 쉽게 갱신 가능

     - addView는 100개의 아이템이 있으면 100개의 아이템을 모두 생성하여 출력해야 한다. -> ListView는 ViewHolder를 통해 아이템의 재사용 가능.

뷰 홀더를 사용하면 화면에 보이는 뷰 개수만큼만 생성하고, 나머지 뷰들은 화면을 움직이면서 사라진 뷰들을 재사용한다.

 

     * addView 참고 : [📱Android/💡개념] 16. AddView

 

[Android/개념] 16. AddView

AddView • 컨테이너 뷰에 자식 뷰들을 동적으로 넣는 방법. • 같은 틀(배치, 속성)에 내용물만 다른 형태 뷰들을 반복적으로 넣을 때 사용 ex) 리스트 • item_add_view16.xml - 아이템으로 쓸 뷰를 생성

apro-developer.tistory.com

 

 

• activity_list_view18.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=".ListView_18">

    <TextView
        android:id="@+id/addPeople"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="#AAAAFF"
        android:gravity="center"
        android:text="사람 추가"
        android:textSize="40dp" />

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

 

• ListView_18.kt

package com.example.fastcampus

import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*

class ListView_18 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_list_view18)

        // 데이터 준비
        val peopleList = mutableListOf<People>()
        for (i in 0..100) {
            peopleList.add(People("홍길동" + i, i))
        }

        // 어댑터 장착
        val adapter = ListViewAdapter(peopleList, LayoutInflater.from(this), this)
        val listView = findViewById<ListView>(R.id.listView)
        listView.adapter = adapter

        // 아이템 별 리스너 장착
        listView.setOnItemClickListener { parent, view, position, id ->
            val people: People = adapter.peopleList[position]
            val peopleName = people.name
            val peopleAge = people.age

            Toast.makeText(this, "이름 : " + peopleName + " / 나이 : " + peopleAge, Toast.LENGTH_LONG).show()
        }

        // 데이터 변경 갱신
        findViewById<TextView>(R.id.addPeople).setOnClickListener {
            adapter.peopleList.add(People("새로운 홍길동", 1234)) // 데이터 추가(변경)
            adapter.notifyDataSetChanged() // 데이터 갱신
        }
    }
}

class ListViewAdapter(val peopleList: MutableList<People>, val layoutInflater: LayoutInflater, val context: Context): BaseAdapter() {
    override fun getCount(): Int {
        // 전체 데이터의 크기(개수) 리턴
        return peopleList.size
    }

    override fun getItem(position: Int): Any {
        // 전체 데이터 중에서 해당 번째(Position)의 데이터를 리턴
        return peopleList[position]
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        // 뷰 홀더 사용 - tag를 이용하여 아이템 재사용
        val view: View
        val holder: ViewHolder
        if (convertView == null) {
            // 재활용 불가능
            view = layoutInflater.inflate(R.layout.item_add_view16, null)
            holder = ViewHolder()
            holder.peopleImage = view.findViewById(R.id.peopleImage)
            holder.peopleName = view.findViewById(R.id.peopleName)
            holder.peopleAge = view.findViewById(R.id.peopleAge)

            view.tag = holder
        } else {
            // 재활용 가능
            holder = convertView.tag as ViewHolder
            view = convertView
        }
        val people = peopleList[position]
        holder.peopleImage?.setImageDrawable(
            context.resources.getDrawable(R.drawable.people3, context.theme)
        )
        holder.peopleName?.text = people.name
        holder.peopleAge?.text = people.age.toString()

//        // 뷰 홀더 사용하지 않을 때 -> addView와 같은 방식
//        val view = layoutInflater.inflate(R.layout.item_add_view16, null)
//        val peopleImage = view.findViewById<ImageView>(R.id.peopleImage)
//        val peopleName = view.findViewById<TextView>(R.id.peopleName)
//        val peopleAge = view.findViewById<TextView>(R.id.peopleAge)
//
//        val people = peopleList[position]
//        peopleImage.setImageDrawable(
//            context.resources.getDrawable(R.drawable.people3, context.theme)
//        )
//        peopleName.text = people.name
//        peopleAge.text = people.age.toString()

        return view
    }
}

class ViewHolder {
    var peopleImage: ImageView? = null
    var peopleName: TextView? = null
    var peopleAge: TextView? = null
}

 

• 결과

홍길동0 ~ 홍길동100 모두 출력 - 101개가 모두 만들어진 것은 아니고 화면 밖으로 사라지는 뷰들을 재사용하여 다시 출력하는 것이다.

 

사람 추가를 누르면 peopleList에 새로운 항목이 추가되고(데이터의 변경) Adapter.notifyDataSetChanged()를 통해 갱신된다.

 

아이템을 클릭하면 listView.setOnItemClickListener을 통해 아이템 별 리스너가 작동된다.

 

 

 

 

 

 

 

 

 

이 글은

패스트 캠퍼스 Android 앱 개발의 정석 with Kotlin 올인원 패키지 Online

강의를 듣고 공부한 내용을 바탕으로 작성되었습니다.

 


728x90
댓글
공지사항