간단한 코틀린의 문법 (Mutable List, Immutable List)
여러가지 레이아웃 (FramLayout : RecyclerView, LinearLayout, Material Card View)을 사용해 Scrollable list 만들기
Unit 2 : Display a scrollable list
- 코틀린 문법 공부를 먼저 할 필요가 있다.
- How to create and use lists in Kotlin
- The difference between the List and MutableList, and when to use each one
- How to iterate over all items of a list and perform an action on each item.
- 위 kotlinplayground에서 코틀린 문법을 실습할 수 있다.
List
- 선언과 출력
val numbers: List<Int> = listOf(1, 2, 3, 4, 5, 6)
val numbers = listOf(1, 2, 3, 4, 5, 6)
println("List: $numbers")
println("List: " + numbers) //string + int 도 출력이 가능
- str + int ??
fun main() {
val num: Int = 1
val word: String = "word"
//============================
val mix = word + num
val mix = num + word
//==============================
println("${num::class.simpleName}") //type을 물어보는 함수
println("${word::class.simpleName}")
println("${mix::class.simpleName}")
}
-
다른 자료형 끼리 연산하면 앞에 있는 자료형을 따라간다.
-
word[0, 1, 2, 3] < = > [0, 1, 2, 3, word]
-
리스트 내부 함수
println("Size: ${numbers.size}") //배열의 크기를 알아보는 함수
numbers[0] == numbers.get(0) //get 함수로 원하는 인덱스를 얻을 수 있다.
numbers.first()
numbers.last()
numbers.reversed()
numbers.sorted()
- 출력문 안에서 객체 안의 함수를 사용할 때엔 $뒤에 {}를 포함하는 모습을 보인다.
Mutable List
//val entrees = mutableListOf()
val entrees = mutableListOf<String>()
val entrees: MutableList<String> = mutableListOf()
println("Add noodles: ${entrees.add("noodles")}") // 리스트도 넣을 수 있다.
println("Entrees: $entrees")
- mutable list에서만 사용 가능한 함수들
entrees.remove("삭제할 요소")
entrees.removeAt("삭제할 인덱스")
entrees.clear() //리스트의 요소를 모두 비운다.
entrees.isEmpty() //리스트가 비어있는가?
- var : 가변적
- val : 불변적
반복문
for (item in list) print(item) // Iterate over items in a list
for (item in 'b'..'g') print(item) // Range of characters in an alphabet
for (item in 1..5) print(item) // Range of numbers
for (item in 5 downTo 1) print(item) // Going backward
for (item in 3..6 step 2) print(item) // Prints: 35
CodeLab Solution Code
- 코틀린에서 출력과 클래스의 상속 등 기본적인 문법을 사용해 보는 실습
open class Item(val name: String, val price: Int) //open : 부모 클래스 앞에 붙이는 키워드
class Noodles : Item("Noodles", 10) {
override fun toString(): String {
return name
}
}
class Vegetables(vararg val toppings: String) : Item("Vegetables", 5) {
override fun toString(): String {
if (toppings.isEmpty()) {
return "$name Chef's Choice"
} else {
return name + " " + toppings.joinToString()
}
}
}
class Order(val orderNumber: Int) {
private val itemList = mutableListOf<Item>()
fun addItem(newItem: Item): Order {
itemList.add(newItem)
return this
}
fun addAll(newItems: List<Item>): Order {
itemList.addAll(newItems)
return this
}
fun print() {
println("Order #${orderNumber}")
var total = 0
for (item in itemList) {
println("${item}: $${item.price}")
total += item.price
}
println("Total: $${total}")
}
}
fun main() {
val ordersList = mutableListOf<Order>()
// Add an item to an order
val order1 = Order(1)
order1.addItem(Noodles())
ordersList.add(order1)
// Add multiple items individually
val order2 = Order(2)
order2.addItem(Noodles())
order2.addItem(Vegetables())
ordersList.add(order2)
// Add a list of items at one time
val order3 = Order(3)
val items = listOf(Noodles(), Vegetables("Carrots", "Beans", "Celery"))
order3.addAll(items)
ordersList.add(order3)
// Use builder pattern
val order4 = Order(4)
.addItem(Noodles())
.addItem(Vegetables("Cabbage", "Onion"))
ordersList.add(order4)
// Create and add order directly
ordersList.add(
Order(5)
.addItem(Noodles())
.addItem(Noodles())
.addItem(Vegetables("Spinach"))
)
// Print out each order
for (order in ordersList) {
order.print()
println()
}
}
-
vararg : " 가변 인자 " [variable argument]
⇒ 매개변수의 개수를 동적으로 지정할 수 있는 방법
-
Learn More
What you'll learn
- How to use a RecyclerView to display a list of data.
- How to use organize your code into packages
- How to use adapters with RecyclerView to customize how an individual list item looks.
사전 준비하기!
implementation 'androidx.appcompat:appcompat:1.2.0'
// and change it to
implementation 'com.google.android.material:material:1.2.0'
- string.xml 추가
<resources>
<string name="app_name">Affirmations</string>
<string name="affirmation1">I am strong.</string>
<string name="affirmation2">I believe in myself.</string>
<string name="affirmation3">Each day is a new opportunity to grow and be a better version of myself.</string>
<string name="affirmation4">Every challenge in my life is an opportunity to learn from.</string>
<string name="affirmation5">I have so much to be grateful for.</string>
<string name="affirmation6">Good things are always coming into my life.</string>
<string name="affirmation7">New opportunities await me at every turn.</string>
<string name="affirmation8">I have the courage to follow my heart.</string>
<string name="affirmation9">Things will unfold at precisely the right time.</string>
<string name="affirmation10">I will be present in all the moments that this day brings.</string>
</resources>
- 패키지를 생성하고, kt 파일을 추가하는 과정을 거친다.
- com.example.affirmations.model : affirmation.kt
- data class : 데이터만 갖고 기능이 없는 클래스
package com.example.affirmations.model
data class Affirmation(val stringResourceId: Int)
- com.example.affirmations.data : datasource.kt
package com.example.affirmations.data
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
class Datasource {
fun loadAffirmations(): List<Affirmation> {
return listOf<Affirmation>(
Affirmation(R.string.affirmation1),
Affirmation(R.string.affirmation2),
Affirmation(R.string.affirmation3),
Affirmation(R.string.affirmation4),
Affirmation(R.string.affirmation5),
Affirmation(R.string.affirmation6),
Affirmation(R.string.affirmation7),
Affirmation(R.string.affirmation8),
Affirmation(R.string.affirmation9),
Affirmation(R.string.affirmation10)
)
}
}
- Affirmation객체로 반환한다.
Recycler View
-
리스트뷰(ListView)의 경우, 리스트 항목이 갱신될 때마다 매번 아이템 뷰를 새로 구성해야 한다
-
이는 많은 수의 데이터 집합을 표시하는데 있어서, 성능 저하를 야기할 수 있는 요인이 된다.
-
item - One data item of the list to display. Represents one Affirmation object in your app.
-
Adapter - Takes data and prepares it for RecyclerView to display.
-
ViewHolders - A pool of views for RecyclerView to use and reuse to display affirmations.
-
RecyclerView on Screen
-
사용자가 관리하는 많은 수의 데이터 집합(Data Set)을 개별 아이템 단위로 구성하여 화면에 출력하는 뷰그룹(ViewGroup)이며, 한 화면에 표시되기 힘든 많은 수의 데이터를 스크롤 가능한 리스트로 표시해주는 위젯
-
어댑터 : 리사이클러뷰에 표시될 아이템 뷰를 생성한다.
-
뷰홀더 : 화면에 표시될 아이템 뷰를 저장하는 객체이다.
-
레이아웃 매니저 : 리사이클러뷰가 아이템을 화면에 표시할 때, 아이템 뷰들이 리사이클러뷰 내부에서 배치되는 형태를 관리하는 요소
실습 진행하기
-
레이아웃 추가
-
어댑터 추가
- list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
- 아이템어댑터 클래스 추가
package com.example.affirmations.adapter
import android.content.Context
import com.example.affirmations.model.Affirmation
class ItemAdapter(private val context: Context, private val dataset: List<Affirmation>) {
}
- 뷰홀더 추가
class ItemAdapter(private val context: Context, private val dataset: List<Affirmation>) {
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.item_title)
}
}
class ItemAdapter(
private val context: Context,
private val dataset: List<Affirmation>
) : RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() { //추상 클래스에서 확장
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.item_title)
}
}
- 위처럼 코드를 적는다면, 오류가 발생한다.
- 빨간줄 위에서 ALT + ENTER를 누르면 다음과 같이 해결 방안을 보여준다.
- 위 오류는 필요한 추상 메서드를 구현하지 않았기 때문에 발생한 오류이다.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
TODO("Not yet implemented")
}
override fun getItemCount(): Int {
TODO("Not yet implemented")
}
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
TODO("Not yet implemented")
}
-
필요한 override를 진행하면 빨간줄이 사라진다.
-
결과 코드
package com.example.affirmations.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
class ItemAdapter(
private val context: Context,
private val dataset: List<Affirmation>
) : RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() {
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.item_title)
}
//뷰 생성
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
// create a new view
val adapterLayout = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item, parent, false)
return ItemViewHolder(adapterLayout)
}
//데이터집합 크기 반환
override fun getItemCount() = dataset.size
//뷰 내용 변경
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val item = dataset[position]
holder.textView.text = context.resources.getString(item.stringResourceId)
}
}
- Summary
- Learn More
Display a list of images using cards
What you'll learn
- How to add images to the list of displayed affirmations in a RecyclerView.
- How to use MaterialCardView in a RecyclerView item layout.
- How to make visual changes in the UI to make the app look more polished.
시작하기 전에
- 다운로드 받은 이미지를 app/src/main/res/drawable 에 복사한다. ⇒ R.drawable.image1
Affirmation.kt
package com.example.affirmations.model
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
data class Affirmation(
@StringRes val stringResourceId: Int,
@DrawableRes val imageResourceId: Int
)
- annotation을 추가한다.
- annotation ?
Dataresource.kt
- affirmation 객체의 인자가 두개가 되었다. 오류가 발생하지 않게 고쳐주자
package com.example.affirmations.data
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
class Datasource() {
fun loadAffirmations(): List<Affirmation> {
return listOf<Affirmation>(
Affirmation(R.string.affirmation1, R.drawable.image1),
Affirmation(R.string.affirmation2, R.drawable.image2),
Affirmation(R.string.affirmation4, R.drawable.image4),
Affirmation(R.string.affirmation5, R.drawable.image5),
Affirmation(R.string.affirmation6, R.drawable.image6),
Affirmation(R.string.affirmation7, R.drawable.image7),
Affirmation(R.string.affirmation8, R.drawable.image8),
Affirmation(R.string.affirmation9, R.drawable.image9),
Affirmation(R.string.affirmation10, R.drawable.image10)
)
}
}
list_item.xml
- 레이아웃을 Linear로 변경하고 수직 방향으로 바꾼다.
- 이미지도 적절한 높이와 함께 추가한다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:layout_width="match_parent"
android:layout_height="194dp"
android:id="@+id/item_image"
android:importantForAccessibility="no"
android:scaleType="centerCrop" />
</LinearLayout>
ItemAdapter.kt
- 이미지뷰를 추가한다.
class ItemViewHolder(private val view: View): RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.item_title)
val imageView: ImageView = view.findViewById(R.id.item_image)
}
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val item = dataset[position]
holder.textView.text = context.resources.getString(item.stringResourceId)
holder.imageView.setImageResource(item.imageResourceId)
}
예쁜 사진과 글귀가 추가되었다!
Polishing the UI : 더 예쁘게 앱을 다듬어 보자!
-
padding 조절
-
글씨 변경
-
색깔 변경 ( app/res/values : colors.xml)
-
테마 추가
-
앱 아이콘 변경
결과 화면!
- Summary
- Learn More
퀴즈!
- 가변적인 배열로 선언해야 요소를 추가하거나 제거할 수 있다.
'안드로이드' 카테고리의 다른 글
[android - 1team] 안드로이드 experince 1 (0) | 2021.01.13 |
---|---|
[안드로이드 2팀] Layouts - LinearLayout, ConstraintLayout, Data binding (0) | 2020.12.27 |
[안드로이드 1팀] layouts_get user input in an app (0) | 2020.11.27 |
[안드로이드 2팀] Build an interactive app (0) | 2020.11.22 |
[안드로이드 1팀] kotlin 간략 문법 (0) | 2020.11.16 |