본문 바로가기

기타/안드로이드

BirthDayCard App - Image Composable, wrapContentWidth, stringResource

BirthDayCard App - Image Composable, wrapContentWidth, stringResource

Android 앱에 이미지 추가

 

Android 앱에 이미지 추가  |  Android Developers

구성 가능한 함수로 간단한 앱을 빌드하는 방법을 알아봅니다.

developer.android.com

위의 페이지를 참고해서 사진을 보여줄 수 있는 Image Composable과

composable 정렬에 사용하는 wrapContentWidth,

문자열을 resource로 빼서 읽어올 수 있는 stringResource에 대해서 같이 배워보자

 

개요

저번에 만들었던 코드를

다음과 같이 발전시켜보려고 한다

package com.example.birthdaycard

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.birthdaycard.ui.theme.BirthdayCardTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            BirthdayCardTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    BirthdayGreetingWithImage(getString(R.string.happy_birthday_text), getString(R.string.happy_birthday_from))
                }
            }
        }
    }
}

@Composable
fun BirthdayGreetingWithText(message: String, from: String){
    Column {
        Text(
            text = message,
            fontSize = 36.sp,
            modifier = Modifier
                .fillMaxWidth()
                .wrapContentWidth(Alignment.CenterHorizontally)
                .padding(start = 16.dp, end = 16.dp)
        )
        Text(
            text = from,
            fontSize = 24.sp,
            modifier = Modifier
                .fillMaxWidth()
                .wrapContentWidth(Alignment.CenterHorizontally)
                .padding(start = 16.dp, end = 16.dp)
        )
    }
}

@Composable
fun BirthdayGreetingWithImage(message: String, from: String){
    val image = painterResource(R.drawable.androidparty)
    Box {
        Image(
            painter = image,
            contentDescription = null,
            modifier = Modifier
                .fillMaxHeight()
                .fillMaxWidth(),
            contentScale = ContentScale.Crop
        )
        BirthdayGreetingWithText(message, from)
    }
}

@Preview(showBackground = false)
@Composable
fun DefaultPreview() {
    BirthdayCardTheme {
        BirthdayGreetingWithText("Happy Birthday computer science student!", "- from professor")
    }
}

짚어볼 포인트는 크게 세가지이다

Image Composable 추가하기

wrapContentWidth로 composable 정렬하기

문자열을 리소스로 빼놓고 stringResource로 추가하기

하나하나 짚어보자

 

Image Composable 추가하기

화면 왼쪽의 Recource Manager에서 저 더하기 버튼을 클릭하고 Import Drawble을 선택해서 사진을 하나 넣자

 

Qualify Type에서 Density를 고르고 Value는 No로 설정한다

근데 이게 무슨 설정인지 잘 모르겠다 아마 dp와 관련있는 듯

그럼 이제 리소스 폴더인 res->drawble에서 내가 import한 파일을 확인가능하다

 

확인한 androidparty.png 옆에 nodpi라는 것은

화면이 변할 때마다 크기를 계속 알맞게 조정하는 과정을 없애서 성능을 올리는 설정이라고 한다

배경 사진은 크기를 계속 조정할 일이 없어서 그런 것 같다

 

이렇게 drawble 리소스를 하나 추가한 후에 BirthdayGreetingWithImage 함수를 만들어

@Composable
fun BirthdayGreetingWithImage(message: String, from: String){
    val image = painterResource(R.drawable.androidparty)
    Box {
        Image(
            painter = image,
            contentDescription = null,
            modifier = Modifier
                .fillMaxHeight()
                .fillMaxWidth(),
            contentScale = ContentScale.Crop
        )
        BirthdayGreetingWithText(message, from)
    }
}

이렇게 Image를 추가한다

R은 리소스 클래스들을 종합해서 들고 있는 객체이다

R.drawble에는 우리가 추가한 drawble의 id 값(Int)이 들어있다

이걸 painterResource에 넘겨주면 Painter를 반환한다

 

contentDescription은 html의 alternative text 같은 느낌이다

시각이 불편한 사람들에게 읽어주는 기능 등을 위한 인자인데 지금은 필요없으니 null 값을 넣어준다

무조건 명시해야하는 인자인 듯 하다

 

크기와 위치 등을 조정하는 modifier 인자로 크기를 최대한 키운다

contentScale은 이미지의 배율을 조정하는 인자이다

ContentScale.Crop, Fit, FillBounds가 있는데

Crop은 이미지 비율을 유지하면서 가로 세로 중 짧은 쪽이 화면과 같아지게 (즉 화면에 넘치게) 조절해주는 것이고

Fit은 이미지 비율을 유지하되 가로 세로 중 긴 쪽이 화면과 같아지게 (즉 화면에 남는 공간이 있게) 조절 하는 것이다

FillBounds는 이미지 비율을 유지하지 않고 화면에 딱 맞게 확대하는 것이다

 

wrapContentWidth로 composable 정렬하기

BirthdayGreetingWithText 함수를 다음과 같이 수정한다

@Composable
fun BirthdayGreetingWithText(message: String, from: String){
    Column {
        Text(
                text = message,
                fontSize = 36.sp,
                modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentWidth(Alignment.CenterHorizontally)
                    .padding(start = 16.dp, end = 16.dp)
        )
        Text(
                text = from,
                fontSize = 24.sp,
                modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentWidth(Alignment.CenterHorizontally)
                    .padding(start = 16.dp, end = 16.dp)
        )
    }
}

크기나 위치 등을 조정할 때 넘겨주는 인자 Modifier를 추가했다

fillMaxWidth()는 대충 봐도 너비를 최대로 설정하는 함수이다

그리고 javascript에서처럼 함수를 연달아 호출할 수 있다(chaining)

 

wrapContentWidth는 이름 그대로 Composable의 내용을

주어진 너비로 포장(너비 안에 들어가게 조정)할 수 있는 메소드이다

그런데 포장하면서 align 인자에 값을 넘겨줘 수평적인(너비) 정렬까지 해줄 수 있다

넘겨줄 인자에는 Alignment.start, end, CenterHorizontally 등이 있다

start는 왼쪽 끝, end는 오른쪽 끝, CenterHorizontally는 가운데 정렬이다

 

padding은 padding이다 위에서와 마찬가지로 왼쪽과 오른쪽이라는 뜻의 start와 end를 썼다

 

 

문자열을 리소스로 빼놓고 stringResource로 추가하기

기본적으로 문자열이 들어가는 부분에 직접 문자열을 넣으면 이것은 하드코딩이 된다

즉 나중에 변경점이 생길 때 우아하지 못하게 하나하나 찾아서 코드를 직접 수정해야한다

따라서 문자열을 직접 넣지 않고 문자열에 이름을 붙여 그 이름을 직접 넣어준 뒤

그 이름에 해당하는 문자열은 외부파일(string.xml)에서 따로 관리해준다

 

이제 문자열을 Resource로 뽑아내보자

문자열을 선택하고(따옴표 제외) Alt+Enter를 누르면 문자열 추출하기 기능이 있다

 

이름을 지어주고 OK를 누르면

문자열을 외부파일(string.xml)에서 불러와서 입력하는 형식이 된다

 

res->strings.xml 파일은 이렇게 생겼다

딱 봐도 어떻게 추가하고 불러오는지 xml을 몰라도 알겠다

같은 방식으로 뒤에 있는 문자열도 뽑아낸다

 

 

결과화면