본문 바로가기

기타/안드로이드

24. Affirmation App : Scroll 기능

Affirmation App : Scroll 기능

스크롤 가능한 목록 추가

 

스크롤 가능한 목록 추가  |  Android Developers

텍스트와 이미지로 이루어진 스크롤 가능한 격언 목록을 표시하는 앱을 빌드합니다.

developer.android.com

위의 페이지를 참고하여 카드를 스크롤하는 어플을 만들어보자

 

개요

오늘은 그동안 추가로 배운 kotlin의 list 문법을 이용해

데이터를 이쁘게 표현하는 어플을 만들어보자

 

 

코드작성

총 3가지 kt파일로 이루어지는데

MainActivity.kt

Affirmation.kt

Datasource.kt

이다

 

여기서 Affirmation은 동기부여라는 뜻이다

 

Datasource.kt

package com.example.affirmations.data
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation

/**
 * [Datasource] generates a list of [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.affirmation3, R.drawable.image3),
            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))
    }
}

 

Affirmation.kt

package com.example.affirmations.model

import androidx.annotation.DrawableRes
import androidx.annotation.StringRes

data class Affirmation(@StringRes val stringId: Int, @DrawableRes val paitingId: Int)

 

 

MainActivity.kt

package com.example.affirmations
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.ButtonDefaults.elevation
import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.affirmations.data.Datasource
import com.example.affirmations.model.Affirmation
import com.example.affirmations.ui.theme.AffirmationsTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AffirmationApp()
        }
    }
}

@Composable
fun AffirmationApp() {
    val affirmationList = Datasource().loadAffirmations()
    AffirmationsTheme {
        AffirmationList(affirmationList)
    }
}

@Composable
fun AffirmationList(affirmationList: List<Affirmation>){
    LazyColumn(){
        items(affirmationList){ affirmation ->
            AffirmationCard(affirmation, Modifier)
        }
    }
}

@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier){
    Card(modifier = Modifier.padding(8.dp), elevation = 4.dp){
        Column(){
            Image(
                painter = painterResource(affirmation.paitingId),
                contentScale = ContentScale.Crop,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(194.dp),
                contentDescription = null
            )
            Text(
                text = stringResource(affirmation.stringId),
                modifier = Modifier.padding(16.dp),
                style = MaterialTheme.typography.h6
            )
        }
    }
}

@Preview
@Composable
fun CardPreivew(){
    AffirmationsTheme {
        AffirmationCard(Affirmation(R.string.affirmation1, R.drawable.image1), Modifier)
    }
}

짚어볼 포인트는

1. 데이터를 불러오는 방식

2. LazyColumn의 사용

3. Text의 style 속성과 MaterialTheme, Card와 elevation 속성

이렇게 3가지다

하나하나 차근히 살펴보자

 

 

1. 데이터를 불러오는 방식

저번에 내가 만들어보았던 My Art Gallery 어플은

어떤 예제 없이 그냥 내가 만들어 보았던 친구이다

 

그걸 만들면서 들었던 의문점이 바로 수많은 리소스들의 아이디를 어떻게 관리하는가였는데

오늘 동기부여 카드 어플 예제를 따라 만들면서 해답을 얻은 것 같다

 

Datasource 클래스를 보면 리소스의 아이디를 List에 저장하는 것을 알 수 있다

그러고는 AffirmationCard라는 이름의 data class에 저장해서 참조하고 있다

javascript의 eval() 함수 등을 이용하지 않고도 쉽게 순서대로 참조할 수 있고

반복문도 이용할 수 있는 방법이 바로 리스트를 이용하는 것이라는 걸 배웠다

 

 

 

 

2. LazyColumn의 사용

코틀린과 컴포즈 공부를 하면서 구글링을 할 때

자꾸 lazy 함수라는 걸 접하게 됐는데

중요한 건가? 이름이 왜 저따구지? 같은 생각을 했던 기억이 있다

물론 빠르게 진도를 빼려고 당시에 알아보지 않았었는데

오늘 처음 배우게 되었다

 

이름 그대로 게을러서 화면에 보이는 것만 렌더링하고 composition하는 역할을 해주는게 Lazy이다

예전에 유튜브에서 본 영상중에는

게임의 최적화를 위해 플레이어가 보는 장면만 렌더링하는 그런 기술이 있다

라는 내용이 나왔었다

그게 딱 이런 거라고 볼 수 있겠다

 

Lazy한 친구들 중 우리가 오늘 쓴 건 LazyColumn이다

LazyColumn은 안에서 items이라는 함수를 이용해 항목들을 배열하는데

이는 일반적인 방법은 아니고 LazyColumn이 특히 이런 방법을 쓴다고 한다

 

 

3. Text의 style 속성과 MaterialTheme, Card와 elevation 속성

그동안 텍스트에는 기껏해서 fontSize와 fontWeight만 넣어줬었는데

style이라는 속성이 있어서 좀 더 쉽게 rich한 느낌을 줄 수 있을 것 같다

 

MaterialTheme이라는 친구는 공식문서로 가보면 알 수 있듯이 

Colors, Shapes, Typography 3가지 속성으로 이루어져있다

 

그 중 Typography는 보통 많이 쓰이는 TextStyle들을 모아놓은 친구이고

TextStyle은 fontSize, fontWeight, color, fontStyle(글씨체) 등 말 그대로 텍스트의

모든 스타일 정보를 담고 있는 친구다

 

그러니깐 TextStyle 중 h6라는 친구를 쓰겠다는 건데

h6는 html을 배워봤다면 어떤 친구인지 짐작이 갈 것이다

 

Card는 그냥 container이다

그런데 Box와 다르게 겹치지는 않게 해주는 것 같은데

Column, Row처럼 방향이 있는 지는 잘 모르겠다

 

그리고 Card의 elevation 속성은 말 그대로 약간 띄우는 친구이다

그래서 그림자가 생기고 테두리 느낌을 줄 수 있다

그러니까 카드 같은 느낌을 줄 수 있다는 뜻이다

 

결과화면