본문 바로가기

기타/안드로이드

20. My Art Gallery App

나만의 갤러리 만들어보기

Art Space 앱 만들기

 

Art Space 앱 만들기  |  Android Developers

나만의 예술 공간을 선보이는 Android 앱을 만드는 방법을 알아봅니다.

developer.android.com

위의 페이지를 참고하여 나만의 갤러리를 만들어보자

 

개요

지금까지 배운 내용을 바탕으로 조잡하지만 갤러리를 만들어보았다

 

 

완성코드

코드는 다음과 같다

package com.example.myartspace

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.*
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.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.myartspace.ui.theme.MyArtSpaceTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyArtSpaceTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    GalleryUI()
                }
            }
        }
    }
}

@Composable
fun GalleryUI(){
    var page by remember { mutableStateOf(4) }
    var theme by remember { mutableStateOf("space") }
    var picNum by remember { mutableStateOf(0) }

    val setPicNum: (Int) -> Unit = { it -> picNum = it}
    val setTheme: (String) -> Unit = { it -> theme = it}
    val setPage: (Int) -> Unit = { it -> page = it }

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Top
    ) {
        if(page != 0) {
            Button(
                modifier = Modifier.padding(25.dp),
                onClick = { ifBackButtonClicked(page, theme, setPage, setTheme)
                }) { Text("back") }
        }
        Spacer(modifier = Modifier.height(40.dp))
        if (page == 0) {
            GalleryHallUI(setTheme, setPage)
        } else if (page == 1) {
            ThemeGalleryUI("space", setPage, setPicNum)
        } else if (page == 2) {
            ThemeGalleryUI("flower", setPage, setPicNum)
        } else if (page == 3) {
            ThemeGalleryUI("car", setPage, setPicNum)
        } else {
            PaintingUI(theme, picNum, setPicNum)
        }
    }
}

@Composable
fun GalleryHallUI(setTheme:(String) -> Unit, setPage: (Int) -> Unit) {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.SpaceEvenly
    ){
        Text(
            "My Art Gallery",
            fontSize = 50.sp,
            fontWeight = FontWeight.Bold
        )
        GalleryHallThemeUI(theme = "space", page = 1, setTheme = setTheme , setPage = setPage)
        GalleryHallThemeUI(theme = "flower", page = 2, setTheme = setTheme , setPage = setPage)
        GalleryHallThemeUI(theme = "car", page = 3, setTheme = setTheme , setPage = setPage)
    }
}

@Composable
fun GalleryHallThemeUI(theme: String, page: Int, setTheme:(String) -> Unit, setPage: (Int) -> Unit){
    val painter = setPainter(theme)

    Column(
        modifier = Modifier
            .width(200.dp)
            .clickable(onClick = {
                setPage(page)
                setTheme(theme)
            }),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Image(
            modifier = Modifier.height(150.dp),
            painter = painterResource(painter),
            contentDescription = null
        )
        Text(text = theme, fontSize = 24.sp, fontWeight = FontWeight.Bold)
    }
}

@Composable
fun ThemeGalleryUI(theme: String, setPage: (Int) -> Unit, setPicNum: (Int) -> Unit){

    var paintArray = Array(10, {0})
    setPaintArray(paintArray, theme)

    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ){
        Text(text = theme, fontSize = 40.sp, fontWeight = FontWeight.Bold)
        ThemeGalleryRowUI(paintArray, 0, setPage, setPicNum)
        ThemeGalleryRowUI(paintArray, 3, setPage, setPicNum)
        ThemeGalleryRowUI(paintArray, 6, setPage, setPicNum)
    }
}

@Composable
fun PaintingUI(theme: String, picNum: Int, setPicNum: (Int) -> Unit){

    var paint = getPaint(theme, picNum)
    var paintDescription = getPaintDescription(theme, picNum)

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.SpaceEvenly
    ) {
        Column(
            modifier = Modifier.height(500.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            Image(
                modifier = Modifier.width(300.dp),
                painter = painterResource(paint), contentDescription = null)
            Text(stringResource(paintDescription))
        }
        Row(
            modifier = Modifier
                .height(100.dp)
                .fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceAround,
            verticalAlignment = Alignment.CenterVertically
        ){
            Button(onClick = { setPicNum(calculatePicNum(picNum)) }){ Text("previous")}
            Button(onClick = { setPicNum((picNum+1)%9) }){ Text("next")}
        }
    }
}

@Composable
fun ThemeGalleryRowUI(paintArray: Array<Int>, startNum: Int, setPage: (Int) -> Unit, setPicNum: (Int) -> Unit){
    Row(
        modifier = Modifier
            .height(200.dp)
            .fillMaxWidth(),
        horizontalArrangement = Arrangement.SpaceEvenly,
        verticalAlignment = Alignment.CenterVertically
    ) {
        ThemeGalleryImage(paint = paintArray[startNum], startNum, setPage, setPicNum)
        ThemeGalleryImage(paint = paintArray[startNum+1], startNum+1, setPage, setPicNum)
        ThemeGalleryImage(paint = paintArray[startNum+2], startNum+2, setPage, setPicNum)
    }
}

@Composable
fun ThemeGalleryImage(paint: Int, picNum: Int, setPage: (Int) -> Unit, setPicNum: (Int) -> Unit){
    Image(modifier = Modifier
        .height(100.dp)
        .width(100.dp)
        .clickable(onClick = {
            setPage(4)
            setPicNum(picNum)
        }),
        contentScale= ContentScale.Crop,
        painter = painterResource(paint),
        contentDescription = null)
}

private fun ifBackButtonClicked(page: Int, theme: String, setPage: (Int) -> Unit, setTheme: (String) -> Unit){
    if (page in 1..3) {
        setPage(0)
        setTheme("")
    } else if (page == 4) {
        when (theme) {
            "space" -> setPage(1)
            "flower" -> setPage(2)
            else -> setPage(3)
        }
    }
}
private fun setPainter(theme: String): Int{
    val painter = when(theme){
        "space" -> R.drawable.space0
        "flower" -> R.drawable.flower0
        else -> R.drawable.car0
    }
    return painter
}
private fun setPaintArray(paintArray: Array<Int>, theme: String){
    when (theme) {
        "space" -> {
            paintArray[0] = R.drawable.space0
            paintArray[1] = R.drawable.space1
            paintArray[2] = R.drawable.space2
            paintArray[3] = R.drawable.space3
            paintArray[4] = R.drawable.space4
            paintArray[5] = R.drawable.space5
            paintArray[6] = R.drawable.space6
            paintArray[7] = R.drawable.space7
            paintArray[8] = R.drawable.space8
        }
        "flower" -> {
            paintArray[0] = R.drawable.flower0
            paintArray[1] = R.drawable.flower1
            paintArray[2] = R.drawable.flower2
            paintArray[3] = R.drawable.flower3
            paintArray[4] = R.drawable.flower4
            paintArray[5] = R.drawable.flower5
            paintArray[6] = R.drawable.flower6
            paintArray[7] = R.drawable.flower7
            paintArray[8] = R.drawable.flower8
        }
        else -> {
            paintArray[0] = R.drawable.car0
            paintArray[1] = R.drawable.car1
            paintArray[2] = R.drawable.car2
            paintArray[3] = R.drawable.car3
            paintArray[4] = R.drawable.car4
            paintArray[5] = R.drawable.car5
            paintArray[6] = R.drawable.car6
            paintArray[7] = R.drawable.car7
            paintArray[8] = R.drawable.car8
        }
    }
}
private fun getPaint(theme: String, picNum: Int): Int{
    var paint = 0
    if(theme == "space"){
        paint = when(picNum){
            0 -> R.drawable.space0
            1 -> R.drawable.space1
            2 -> R.drawable.space2
            3 -> R.drawable.space3
            4 -> R.drawable.space4
            5 -> R.drawable.space5
            6 -> R.drawable.space6
            7 -> R.drawable.space7
            else -> R.drawable.space8
        }
    } else if (theme == "flower"){
        paint = when(picNum){
            0 -> R.drawable.flower0
            1 -> R.drawable.flower1
            2 -> R.drawable.flower2
            3 -> R.drawable.flower3
            4 -> R.drawable.flower4
            5 -> R.drawable.flower5
            6 -> R.drawable.flower6
            7 -> R.drawable.flower7
            else -> R.drawable.flower8
        }
    } else {
        paint = when(picNum){
            0 -> R.drawable.car0
            1 -> R.drawable.car1
            2 -> R.drawable.car2
            3 -> R.drawable.car3
            4 -> R.drawable.car4
            5 -> R.drawable.car5
            6 -> R.drawable.car6
            7 -> R.drawable.car7
            else -> R.drawable.car8
        }
    }
    return paint
}
private fun getPaintDescription(theme: String, picNum: Int): Int{
    var description = 0
    if(theme == "space"){
        description = when(picNum) {
            1 -> R.string.space0
            2 -> R.string.space1
            3 -> R.string.space2
            4 -> R.string.space3
            5 -> R.string.space4
            6 -> R.string.space5
            7 -> R.string.space6
            8 -> R.string.space7
            else -> R.string.space8
        }
    } else if(theme == "flower") {
        description = when (picNum) {
            1 -> R.string.flower0
            2 -> R.string.flower1
            3 -> R.string.flower2
            4 -> R.string.flower3
            5 -> R.string.flower4
            6 -> R.string.flower5
            7 -> R.string.flower6
            8 -> R.string.flower7
            else -> R.string.flower8
        }
    } else {
        description = when(picNum) {
            1 -> R.string.car0
            2 -> R.string.car1
            3 -> R.string.car2
            4 -> R.string.car3
            5 -> R.string.car4
            6 -> R.string.car5
            7 -> R.string.car6
            8 -> R.string.car7
            else -> R.string.car8
        }
    }
    return description
}
private fun calculatePicNum(picNum: Int): Int{
    var temp = (picNum-1)
    var result = 0
    if(picNum >= 0){
        result = temp%9
    } else {
        result = ((temp%9)+9)
    }
    return result
}



@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    MyArtSpaceTheme {
        GalleryUI()
    }
}

 

코드 설명

페이지 변경을 이런 식으로 구현하는게 일반적인 지는 잘 모르겠지만

내가 생각해본 방법으로 만들었다

 

가장 메인화면은 GalleryHall

테마별 갤러리 화면은 ThemeGallery

각 그림을 보는 화면은 Painting

이라고 이름 지었고

 

화면 구성은 UI라는 이름의 composable에

어떤 페이지로 이동하고 어떤 리소스를 출력할지 결정하는 로직은

모두 private 함수에 집어넣었다

 

getPaintDescription과 같은 로직 함수에서 페이지나 테마, 그림 번호를 가지고

적절한 리소스를 가져오는 부분이 있는데

코드를 좀 더 간략하게 짤 수 있는 방법이 궁금했지만 찾지 못했다

javascript의 eval() 함수와 비슷한 느낌이면 될 거 같은데...

 

그리고 아직 문법적으로 배우지는 않았지만 배열이 필요해져서 써봤다

관련 문법은 다음에 정리하기로 했다

 

 

 

 

 

 

결과화면