Idealim
article thumbnail

/* 본 게시물은 ' 취준생을 위한 안드로이드 앱만들기 콤포즈UI 기본개념 Jetpack Compose '

의 내용을 토대로 작성되었습니다. */

참고 자료

[취준생을 위한 안드로이드 앱만들기 콤포즈UI 기본개념 Jetpack Compose] : https://www.youtube.com/watch?v=1apENzDbtCQ&t=190s 


#Jetpack Compose 사용해보기

 

build.gradle

Jetpack Compose 는 kotlin 1.5.10 이상 버전에서 실행 가능하다.

 

MainActivity

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import com.example.composeuibasic.ui.theme.ComposeUIBasicTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeUIBasicTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    Greeting(name = "IdeaLim")
                }
            }
        }
    }
}

// @Composable : compose view를 반환 / view
@Composable
fun Greeting(name: String) {
    //Scaffold : 기본 메터리얼 디자인 Drawer, FloatingActionButton, TopApp Bar 등 다양한 컴포저블을 제공
    Scaffold(
        //TopBar
        topBar = {
        TopAppBar(title = {Text("Compose AppBar")},
        backgroundColor = Color(0xffE5FBB8)) },
        //FloatingActionButton
        floatingActionButtonPosition = FabPosition.End,
        floatingActionButton = {
            FloatingActionButton(onClick = {}) {
                Text("클릭")
            } },
        )
    
    // TextBlock
    {
        Text(text = "Hello $name!") // ctrl + B 로 Modifier 확인 가능
    }
    
}

//미리보기
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    ComposeUIBasicTheme {
        Greeting("Android")
    }
}

  • @Composable : View를 만드는 애노테이션이다. 
  • @Preview : 미리보기 
  • Scaffold : 기본 메터리얼 디자인 제공.

실행 결과

 

Layout : Column, Row

@Composable
fun MyComposableView() {
    Log.d("Tag", "MyComposableView:")

    Column(Modifier.background(Color(0xffC0FEFC))){
        // Row: horizontal linear layout
        Row(
            Modifier.padding(10.dp).background(Color(0xff628395)),
            //gravity
            verticalAlignment = Alignment.CenterVertically
        ) {
            Text(text = "안녕하세요",
                modifier = Modifier.background(Color(0xffF9F9F9)).padding(10.dp),
                color = Color(0xffD83A56))
            Spacer(modifier = Modifier.size(10.dp))
            Text(text = "Hello")
        }

        Row(
            Modifier.padding(10.dp).background(Color(0xff628395)),
            //gravity
            verticalAlignment = Alignment.CenterVertically
        ) {
            Text(text = "안녕하세요",
                modifier = Modifier.background(Color(0xffF9F9F9)).padding(10.dp),
                color = Color(0xffD83A56))
            Spacer(modifier = Modifier.size(10.dp))
            Text(text = "Hello")
        }
        Row(
            Modifier.padding(10.dp).background(Color(0xff628395)),
            //gravity
            verticalAlignment = Alignment.CenterVertically
        ) {
            Text(text = "안녕하세요",
                modifier = Modifier.background(Color(0xffF9F9F9)).padding(10.dp),
                color = Color(0xffD83A56))
            Spacer(modifier = Modifier.size(10.dp))
            Text(text = "Hello")
        }
    }
}

Row 부분을 함수로 만들어서 깔끔하게 나타내보자. 

@Composable
fun MyRow(){
    Row(
        Modifier
            .padding(10.dp)
            .background(Color(0xff628395)),
        //gravity
        verticalAlignment = Alignment.CenterVertically
    ) {
        Text(text = "안녕하세요",
            modifier = Modifier
                .background(Color(0xffF9F9F9))
                .padding(10.dp),
            color = Color(0xffD83A56))

        Spacer(modifier = Modifier.size(10.dp))

        Text(text = "Hello",
            modifier = Modifier.padding(10.dp))
    }
}
//스택 Column, Row, Box(겹치기)
@Composable
fun MyComposableView() {
    Log.d("Tag", "MyComposableView:")

    Column(
        Modifier
            .background(Color(0xffC0FEFC))
            .verticalScroll(rememberScrollState()) // 스크롤 가능하게..
    ){
        // MyRow() 20개 생성
        for (i in 1..20){
            MyRow()
        }
    }
}

실행결과


이번에는 LazyColumn을 이용해서 메모리 관리를 하는 List를 만들어보자.

 

LazyColumnActivity

class LazyColumnActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeUIBasicTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    ContextLayout()
                }
            }
        }
    }
}

// TopAppBar 생성 / RandomUserListView 생성 
@Composable
fun ContextLayout() {
    Surface(color = MaterialTheme.colors.background) {
        Scaffold(
            topBar = {
                AppBar()
            }
        ) {
            RandomUserListView(randomUsers = DummyDataProvider.userList)
        }
    }

}

// AppBar Setting
@Composable
fun AppBar(){
    TopAppBar(
        title = { Text("Lazy Column", fontSize = 20.sp) },
        backgroundColor = TopBarColor,
        elevation = 10.dp,
        modifier = Modifier.height(58.dp)
        )
}

// RandomUserListView: LazyColumn을 randomUsers
@Composable
fun RandomUserListView(randomUsers: List<RandomUser>){
    //메모리 관리하는 LazyColumn (RecyclerView 와 비슷)
    LazyColumn(){
        // items() : randomUsers 의 리스트 데이터 하나 씩 가져옴
        items(randomUsers){ randomUser ->
            RandomUserView(randomUser) // RandomUserView(it) 으로 간략히 쓸 수 있음.
        }
    }
}

@Composable
fun RandomUserView(randomUser: RandomUser){
    //cardView
    Card(modifier = Modifier
        .fillMaxWidth() //  match_parent
        .padding(10.dp),
        elevation = 10.dp,
        shape = RoundedCornerShape(12.dp)
        ) {
        RandomUserCardView(randomUser = randomUser)
    }
}

@Composable
fun RandomUserCardView(randomUser: RandomUser){
    Row(modifier = Modifier.padding(10.dp),
        verticalAlignment = Alignment.CenterVertically  // 세로로 Card 안에 있는 View 를 가운데 정렬
    ){
//        Box(modifier = Modifier
//            .size(width = 50.dp, height = 50.dp)
//            .clip(CircleShape)
//            .background(TopBarColor)
//            )
        RandomUserProfileImage(imgUrl = randomUser.profileImage)
        RandomUserNameAndDescription(randomUser = randomUser)
    }
}

@Composable
fun RandomUserNameAndDescription(randomUser: RandomUser){
    Column(
        modifier =  Modifier.padding(10.dp)
    ) {
        // custom style 은 Theme > typography > subtitle1
        Text(text = randomUser.name, style = MaterialTheme.typography.subtitle1)
        Text(text = randomUser.description, style = MaterialTheme.typography.body1)
    }
}

@Composable
fun RandomUserProfileImage(imgUrl: String, modifier: Modifier = Modifier) {
    // 이미지 비트맵 가져오기
    val bitmap : MutableState<Bitmap?> =  remember { mutableStateOf(null) }

    Glide.with(LocalContext.current)
        .asBitmap()
        .load(imgUrl)
        .into(object : CustomTarget<Bitmap>(){
            override fun onLoadCleared(placeholder: Drawable?) {
            }

            override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                bitmap.value = resource // resource 는 다운 받은 이미지.
            }
        })

    bitmap.value?.asImageBitmap()?.let {
        Image(bitmap = it,
            contentScale = ContentScale.Fit,
            contentDescription = null,
            modifier = modifier
                .size(50.dp)
                .clip(CircleShape)
        )
    } ?: Image(painter = painterResource(id = R.drawable.ic_profile_null),
            contentScale = ContentScale.Fit,
            contentDescription = null,
            modifier = modifier
                .size(50.dp)
                .clip(RoundedCornerShape(10.dp))
    )
}


@Preview(showBackground = true)
@Composable
fun DefaultPreview2() {
    ComposeUIBasicTheme {
        ContextLayout()
    }
}
 
 

<중요 Point>

1. LazyColumn을 RecyclerView 처럼 사용.

2. Glide를 사용해 Url에서 image를 bitmap으로 가져오기

3. MaterialTheme.typography.subtitle1 처럼 MaterialTheme 를 커스터마이징 가능.

DummyDataProvider

data class RandomUser(
    val name: String = "이름",
    val description: String = "설명",
    val profileImage: String = "https://randomuser.me/api/portraits/women/76.jpg"
)

object DummyDataProvider {

    val userList = List<RandomUser>(200) { RandomUser() }

}

실행결과

 

반응형
profile

Idealim

@Idealim

읽어주셔서 감사합니다. 잘못된 내용이 있으면 언제든 댓글로 피드백 부탁드립니다.