[Android] AdapterView

leeehaยท2022๋…„ 9์›” 10์ผ
0
post-thumbnail

์ถœ์ฒ˜: https://sesac.seoul.kr/ (JetPack๊ณผ Kotlin์„ ํ™œ์šฉํ•œ Android App ๊ฐœ๋ฐœ ๊ฐ•์˜)

์–ด๋Œ‘ํ„ฐ๋ทฐ์˜ ๊ฐœ๋…

  • ํ•ญ๋ชฉ์„ ๋‚˜์—ดํ•˜๊ณ  ๊ทธ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ทฐ
  • ListView, AutoCompleteTextView, Spinner ๋“ฑ
  • Adapter์— ์˜ํ•ด ํ•ญ๋ชฉ์ด ๋งŒ๋“ค์–ด์ง€๋Š” ๋ทฐ


์–ด๋Œ‘ํ„ฐ๋ทฐ์˜ ์‚ฌ์šฉ

ArrayAdapter

ํ•œ ํ•ญ๋ชฉ์— ๋ฌธ์ž์—ด ๋ฐ์ดํ„ฐ ํ•˜๋‚˜๋ฅผ ๋‚˜์—ดํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์— ์‚ฌ์šฉ

  • simple_list_item1 : ํ•ญ๋ชฉ์— ๋ฌธ์ž์—ด ๋ฐ์ดํ„ฐ ํ•˜๋‚˜
  • simple_list_item2 : ํ•ญ๋ชฉ์— ๋ฌธ์ž์—ด ๋ฐ์ดํ„ฐ ๋‘๊ฐœ ์œ„์•„๋ž˜ ๋‚˜์—ด
  • simple_list_item_multiple_choice : ๋ฌธ์ž์—ด๊ณผ ์˜ค๋ฅธ์ชฝ ์ฒดํฌ๋ฐ•์Šค ์ œ๊ณต
  • simple_list_item_single_choice : ๋ฌธ์ž์—ด๊ณผ ์˜ค๋ฅธ์ชฝ ๋ผ๋””์˜ค ๋ฒ„ํŠผ ์ œ๊ณต
  • ํ•ญ๋ชฉ ํ•˜๋‚˜๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์ปค์Šคํ…€ ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ์ ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

๋ฐ์ดํ„ฐ ์ค€๋น„

values ํด๋” ๋ฐ‘์— arrays.xml ํŒŒ์ผ ์ƒ์„ฑ

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="locations">
        <item>๊ฐ•์›๋„</item>
        <item>๊ฒฝ๊ธฐ๋„</item>
        <item>๊ฒฝ์ƒ๋‚จ๋„</item>
        <item>๊ฒฝ์ƒ๋ถ๋„</item>
        <item>๊ด‘์ฃผ๊ด‘์—ญ์‹œ</item>
    </string-array>
</resources>

๋ ˆ์ด์•„์›ƒ ์ค€๋น„

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
</ListView>

์–ด๋Œ‘ํ„ฐ ์ƒ์„ฑ ํ›„ ๋ทฐ์— ์ ์šฉ

MainActivity.kt

package com.tutorial.c30

import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity

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

        val listView = findViewById<ListView>(R.id.main_list)
        val data = resources.getStringArray(R.array.locations)
        val adapter = ArrayAdapter(
            this,
            android.R.layout.simple_list_item_1,
            data
        )
        listView.adapter = adapter
    }
}
public ArrayAdapter(@NonNull Context context, int resource, @NonNull T[] objects) {
  throw new RuntimeException("Stub!");
}


SimpleAdapter

ํ•œ ํ•ญ๋ชฉ์— ๋ฌธ์ž์—ด ๋ฐ์ดํ„ฐ ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ๋‚˜์—ดํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์— ์‚ฌ์šฉ

๋ ˆ์ด์•„์›ƒ ์ค€๋น„

activiti_main.xml

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
</ListView>

๋ฐ์ดํ„ฐ ์ค€๋น„, ์–ด๋Œ‘ํ„ฐ ์ƒ์„ฑ ํ›„ ๋ทฐ์— ์ ์šฉ

MainActivity.kt

package com.tutorial.c32

import android.os.Bundle
import android.widget.ListView
import android.widget.SimpleAdapter
import androidx.appcompat.app.AppCompatActivity

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

        val listView = findViewById<ListView>(R.id.main_list)
        val data: ArrayList<HashMap<String, String>> = ArrayList()
        var map: HashMap<String, String> = HashMap()
        map["name"] = "LG ํŠธ์œˆ์Šค"
        map["content"] = "์„œ์šธ, ์ž ์‹ค ์•ผ๊ตฌ์žฅ"
        data.add(map)

        map = HashMap()
        map["name"] = "๋‘์‚ฐ ๋ฒ ์–ด์Šค"
        map["content"] = "์„œ์šธ, ์ž ์‹ค ์•ผ๊ตฌ์žฅ"
        data.add(map)

        map = HashMap()
        map["name"] = "KT ์œ„์ฆˆ"
        map["content"] = "์ˆ˜์›, KT ์œ„์ฆˆ ํŒŒํฌ"
        data.add(map)

        val adapter = SimpleAdapter(
            this,
            data,
            android.R.layout.simple_list_item_2,
            arrayOf("name", "content"),
            intArrayOf(android.R.id.text1, android.R.id.text2)
        )
        listView.adapter = adapter
    }
}
 public SimpleAdapter(
     Context context, 
     List<? extends Map<String, ?>> data, 
     int resource, 
     String[] from, int[] to) {
     throw new RuntimeException("Stub!");
}


ListView ํ•ญ๋ชฉ ์ถ”๊ฐ€, ์‚ญ์ œ

๋ ˆ์ด์•„์›ƒ ์ค€๋น„

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">

    <ListView
        android:id="@+id/main_list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:orientation="horizontal">
        <EditText
            android:id="@+id/edit"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:inputType="text"/>
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="add"/>
    </LinearLayout>

</LinearLayout>

์–ด๋Œ‘ํ„ฐ ์ƒ์„ฑ ํ›„ ๋ทฐ์— ์ ์šฉ

package com.tutorial.c33

import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.EditText
import android.widget.ListView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    var todo = mutableListOf<String>()
    lateinit var adapter: ArrayAdapter<String>
    lateinit var listView: ListView
    lateinit var editText: EditText
    lateinit var button: Button

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

        listView = findViewById(R.id.main_list)
        editText = findViewById(R.id.edit)
        button = findViewById(R.id.button)

        adapter = ArrayAdapter(
            this,
            android.R.layout.simple_list_item_1,
            todo
        )
        listView.adapter = adapter

        // ๋ฆฌ์ŠคํŠธ๋ทฐ์˜ ํ•ญ๋ชฉ์„ ํด๋ฆญํ•˜๋ฉด ํ•ญ๋ชฉ ์ œ๊ฑฐ ์—ฌ๋ถ€๋ฅผ ๋ฌป๋Š” ๋‹ค์ด์–ผ๋กœ๊ทธ ๋„์šฐ๊ธฐ
        listView.setOnItemClickListener { adpaterView, view, i, l ->
            AlertDialog.Builder(this)
                .setTitle("Remove TODO")
                .setPositiveButton("OK") { dialog, which ->
                    todo.removeAt(i)
                    adapter.notifyDataSetChanged()
                }
                .setNegativeButton("CANCEL", null)
                .create()
                .show()
        }

        // add ๋ฒ„ํŠผ ๋ˆ„๋ฅด๋ฉด ๋ฆฌ์ŠคํŠธ๋ทฐ์— ํ•ญ๋ชฉ ์ถ”๊ฐ€
        button.setOnClickListener {
            todo.add(editText.text.toString())
            editText.text.clear()
            adapter.notifyDataSetChanged()
        }
    }
}

ezgif com-gif-maker


CustomAdapter

  • ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ •ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋Œ€๋กœ ํ•ญ๋ชฉ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์„ค์ •๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
  • ๊ฐœ๋ฐœ์ž์˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋Œ€๋กœ ํ•ญ๋ชฉ๋ณ„ View์˜ ์ด๋ฒคํŠธ๋ฅผ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
  • ๊ฐœ๋ฐœ์ž์˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋Œ€๋กœ ํ•ญ๋ชฉ๋ณ„ Layout์„ ๋‹ค๋ฅด๊ฒŒ ์ ์šฉ์‹œ์ผœ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ

๋ฆฌ์ŠคํŠธ์˜ ๊ฐ ํ•ญ๋ชฉ์„ ์œ„ํ•œ ์ปค์Šคํ…€ ๋ ˆ์ด์•„์›ƒ

custom_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/custom_item_type_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:id="@+id/custom_item_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@+id/custom_item_type_image"
        android:layout_marginStart="16dp"/>
    <TextView
        android:id="@+id/custom_item_date"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/custom_item_title"
        android:layout_alignStart="@id/custom_item_title"/>
    <ImageView
        android:id="@+id/custom_item_menu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:src="@drawable/ic_menu"/>
</RelativeLayout>

๋ฐ์ดํ„ฐ ํด๋ž˜์Šค์™€ ๋ฐ์ดํ„ฐ ํ™€๋”

DriveVO.kt

package com.tutorial.c34

data class DriveVO(
    var type: String,
    var title: String,
    var date: String
)

DriveHolder.kt

package com.tutorial.c34

import android.view.View
import android.widget.ImageView
import android.widget.TextView

class DriveHolder(root: View) {
    var typeImageView: ImageView
    var titleView: TextView
    var dateView: TextView
    var menuImageView: ImageView

    init {
        typeImageView = root.findViewById(R.id.custom_item_type_image)
        titleView = root.findViewById(R.id.custom_item_title)
        dateView = root.findViewById(R.id.custom_item_date)
        menuImageView = root.findViewById(R.id.custom_item_menu)
    }
}

๋ฐ์ดํ„ฐ์™€ ๋ทฐ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ์ปค์Šคํ…€ ์–ด๋Œ‘ํ„ฐ

package com.tutorial.c34 

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.core.content.res.ResourcesCompat

class DriveAdapter(cxt: Context, val resId: Int, val data: MutableList<DriveVO>)
    : ArrayAdapter<DriveVO>(cxt, resId){

    override fun getCount(): Int {
        return data.size
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        var view = convertView
        if (view == null) {
            val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
                    as LayoutInflater
            view = inflater.inflate(resId, null)

            val holder = DriveHolder(view)
            view!!.tag = holder
        }

        // ๋ทฐ ํ™€๋”์—์„œ ๋ทฐ ๊บผ๋‚ด๊ธฐ
        val holder = view.tag as DriveHolder
        val typeImageView = holder.typeImageView
        val titleView = holder.titleView
        val dateView = holder.dateView
        val menuImageView = holder.menuImageView

        // ๊ฐ ํ•ญ๋ชฉ์— ์žˆ๋Š” ๋ทฐ๋“ค์˜ ์†์„ฑ ๋ณ€๊ฒฝ
        val (type, title, date) = data[position]
        titleView.text = title
        dateView.text = date

        // ๊ฐ ํ•ญ๋ชฉ์˜ ํƒ€์ž…์— ๋”ฐ๋ผ ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ
        when (type) {
            "doc" -> {
                typeImageView.setImageDrawable(
                    ResourcesCompat.getDrawable(
                        context.resources,
                        R.drawable.ic_type_doc, null
                    )
                )
            }
            "file" -> {
                typeImageView.setImageDrawable(
                    ResourcesCompat.getDrawable(
                        context.resources,
                        R.drawable.ic_type_file, null
                    )
                )
            }
            "img" -> {
                typeImageView.setImageDrawable(
                    ResourcesCompat.getDrawable(
                        context.resources,
                        R.drawable.ic_type_image, null
                    )
                )
            }
        }

        // ๋ฉ”๋‰ด ์ด๋ฏธ์ง€ ํด๋ฆญํ•˜๋ฉด ํ† ์ŠคํŠธ ๋ฉ”์‹œ์ง€ ๋œจ๋„๋ก
        menuImageView.setOnClickListener {
            Toast.makeText(context, "$title menu click", Toast.LENGTH_SHORT).show()
        }

        return view
    }
}

๋ฐ์ดํ„ฐ ์ถ”๊ฐ€, ๋ฆฌ์ŠคํŠธ๋ทฐ์— ์ปค์Šคํ…€ ์–ด๋Œ‘ํ„ฐ ์ ์šฉ

MainActivity.kt

package com.tutorial.c34

import android.os.Bundle
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity

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

        val mutableList = mutableListOf<DriveVO>()
        mutableList.add(DriveVO("doc", "์•ˆ๋“œ๋กœ์ด๋“œ", "2์›” 6์ผ"))
        mutableList.add(DriveVO("file", "db.zip", "2์›” 6์ผ"))
        mutableList.add(DriveVO("img", "exam.png", "2์›” 6์ผ"))

        val listView = findViewById<ListView>(R.id.custom_list)
        val adapter = DriveAdapter(this, R.layout.custom_item, mutableList)
        listView.adapter = adapter
    }
}

Spinner

  • ์—ฌ๋Ÿฌ ํ•ญ๋ชฉ ์ค‘์— ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•˜๋Š” ๋ทฐ (์ฝค๋ณด ๋ฐ•์Šค๋ผ๊ณ ๋„ ๋ถˆ๋ฆผ)
  • dropdown layout์œผ๋กœ๋Š” simple_spinner_item๊ณผ simple_spinner_dropdown_item ์ œ๊ณต
  • spinnerMode="dialog"๋กœ ์ง€์ •ํ•˜๋ฉด ๋‹ค์ด์–ผ๋กœ๊ทธ ํ˜•ํƒœ๋กœ ๋„์šธ ์ˆ˜ ์žˆ์Œ.

AutoCompleteTextView

  • ์œ ์ €์—๊ฒŒ ๊ธ€์„ ์ž…๋ ฅ๋ฐ›๊ธฐ ์œ„ํ•œ ๋ทฐ
  • EditText์™€์˜ ์ฐจ์ด์ ์€ ์ผ๋ถ€ ๊ธ€์ž๋งŒ ์ž…๋ ฅํ•ด๋„ ์ž๋™ ์™„์„ฑ ๊ธฐ๋Šฅ์ด ์ œ๊ณต๋˜์–ด ์ถ”์ฒœ ๋‹จ์–ด๋ฅผ ๋ณด์—ฌ์ค€๋‹ค๋Š” ๊ฒƒ
  • android:completionThreshold="1" : ํ•œ๊ธ€์ž๋งŒ ์ž…๋ ฅํ•ด๋„ ์ž๋™ ์™„์„ฑ ๊ธฐ๋Šฅ ์ œ๊ณต (๊ธฐ๋ณธ์€ ๋‘๊ธ€์ž)
  • android:completionHint="ํ•ญ๋ชฉ์„ ์„ ํƒํ•˜์„ธ์š”" : ์œ ์ € ์ž…๋ ฅ์„ ๋ฐ›๊ธฐ ์œ„ํ•œ ์„ค๋ช… ๊ธ€
  • android:dropDownWidth="200dp" : dropdown์˜ ๊ฐ€๋กœ ํฌ๊ธฐ
  • android:dropDownHeight="200dp" : dropdown์˜ ์„ธ๋กœ ํฌ๊ธฐ
  • android:dropDownVerticalOffset="100dp" : ์„ธ๋กœ ๋ฐฉํ–ฅ์˜ offset
  • android:dropDownHorizontalOffset="100dp" : ๊ฐ€๋กœ ๋ฐฉํ–ฅ์˜ offset

์˜ˆ์ œ

<?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"
    android:padding="16dp"
    tools:context=".MainActivity">

    <Spinner
        android:id="@+id/spinner"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:spinnerMode="dialog"/>

    <AutoCompleteTextView
        android:id="@+id/auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"/>

</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="language">
        <item>ํ•œ๊ตญ์–ด</item>
        <item>์˜์–ด</item>
        <item>์ค‘๊ตญ์–ด</item>
        <item>๋…์ผ์–ด</item>
    </string-array>
</resources>
package com.tutorial.c35

import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import android.widget.Spinner
import androidx.appcompat.app.AppCompatActivity

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

        val spinner = findViewById<Spinner>(R.id.spinner)
        val autoCompleteTextView = findViewById<AutoCompleteTextView>(R.id.auto)

        val data = resources.getStringArray(R.array.language)
        val adapter = ArrayAdapter(
            this,
            android.R.layout.simple_dropdown_item_1line,
            data
        )
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        spinner.adapter = adapter

        val autoData = arrayOf("apply", "apple", "below", "coco")
        val autoAdapter = ArrayAdapter(
            this,
            android.R.layout.simple_dropdown_item_1line,
            autoData
        )
        autoCompleteTextView.setAdapter(autoAdapter)
    }
}
profile
์Šต๊ด€์ด ๋  ๋•Œ๊นŒ์ง€ ๐Ÿ“

0๊ฐœ์˜ ๋Œ“๊ธ€