728x90
이번에는 계산기 앱을 아래와 같이 제작했다.
핸드폰의 기본어플로만 사용하다가 직접 만들어보니 생각보다 많은 부분을 고려해야 했다.
각 칸의 위치부터 시작하여 눌렀을때 색깔 변환 등
해당 강의에서도 3개의 강의로 할 만큼 내용이 많았다.
생각보다 오래 걸렸지만 포기하지 않고 끝까지 실시한 나에게 칭찬한다
한걸음 한걸음 가보자!
@file:OptIn(ExperimentalMaterial3Api::class)
package com.jeong.mycalculator2
import android.nfc.Tag
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.*
import androidx.compose.material3.CardDefaults.cardElevation
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.jeong.mycalculator2.MainActivity.Companion.TAG
import com.jeong.mycalculator2.ui.theme.ActionButtonBgColor
import com.jeong.mycalculator2.ui.theme.MyCalculator2Theme
import com.jeong.mycalculator2.ui.theme.Purple40
import com.jeong.mycalculator2.ui.theme.PurpleGrey80
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
companion object {
const val TAG = "메인"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyCalculator2Theme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Calculator()
}
}
}
}
}
@Composable
fun Calculator(){
val numbers : List<Int> = listOf<Int>(0,1,2,3,4,5,6,7,8,9)
val actions : Array<CalculateAction> = CalculateAction.values()
val buttons = listOf(
CalculateAction.Divide,
7,8,9, CalculateAction.Multiply,
4,5,6, CalculateAction.Minus,
1,2,3, CalculateAction.Plus,
0
)
//첫번째 입력
var firstInput by remember { mutableStateOf("0")}
//두번째 입력
var secondInput by remember { mutableStateOf("")}
val selectedAction: MutableState<CalculateAction?> = remember {
mutableStateOf(null)
}
val selectedSymbol : String = selectedAction.value?.symbol?:""
val calculateHistories : MutableState<List<String>> = remember{ mutableStateOf(emptyList())}
val coroutineScope = rememberCoroutineScope()
val scrollState = rememberLazyListState()
var isCalcuateHistoryVisible by remember { mutableStateOf(true)}
val watchHistoryToggleTitle : String = if(isCalcuateHistoryVisible) "계산 기록 안보기" else "계산 기록 보기"
val verticalSpacerWeight : Float = if (isCalcuateHistoryVisible) 0.1f else 1f
Column(modifier = Modifier.fillMaxSize()){
Card(
elevation = CardDefaults.cardElevation(8.dp),
onClick = {
isCalcuateHistoryVisible = !isCalcuateHistoryVisible
}
){
Text(text = watchHistoryToggleTitle,
modifier = Modifier
.padding(horizontal = 6.dp)
.padding(3.dp)
)
}
AnimatedVisibility(
visible = isCalcuateHistoryVisible,
modifier = Modifier.weight(1f)
) {
LazyColumn(
state = scrollState,
verticalArrangement = Arrangement.spacedBy(4.dp),
contentPadding = PaddingValues(vertical = 10.dp),
reverseLayout =true,
content = {
items(calculateHistories.value){ aHistory ->
Text(text = aHistory, modifier = Modifier.background(PurpleGrey80))
}
})
}
Spacer(modifier = Modifier.weight(verticalSpacerWeight))
LazyVerticalGrid(columns = GridCells.Fixed(4),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
content ={
item(span={GridItemSpan(maxLineSpan) }){
NumberText(
firstInput,
secondInput,
selectedSymbol,
modifier = Modifier.fillMaxSize()
)
}
item(span={GridItemSpan(2) }){
ActionButton(
action = CalculateAction.AllCelar,
onClicked = {
firstInput = "0"
secondInput = ""
selectedAction.value = null
}
)
}
item(span={GridItemSpan(1) }){
ActionButton(action = CalculateAction.Del, onClicked = {
if (secondInput.length>0){
secondInput = secondInput.dropLast(1)
return@ActionButton
}
if (selectedAction.value != null){
selectedAction.value = null
return@ActionButton
}
firstInput = if(firstInput.length ==1) "0" else firstInput.dropLast(1)
})
}
items(buttons) { aButton ->
when(aButton){
is CalculateAction -> ActionButton(aButton, selectedAction.value,
onClicked ={
selectedAction.value = aButton
})
is Int -> NumberButton(aButton, onClicked = {
if (selectedAction.value == null){
if (firstInput == "0") firstInput = aButton.toString() else firstInput += aButton
} else{
secondInput += aButton
}
})
}
}
item(span={GridItemSpan(maxCurrentLineSpan) }){
ActionButton(action = CalculateAction.Calculate,
onClicked = {
if (secondInput.isEmpty()){
return@ActionButton
}
selectedAction.value?.let{
val result = doCalculate(
firstNumber = firstInput.toFloat(),
secondNumber = secondInput.toFloat(),
action = it
)
val calculateHistory = "$firstInput $selectedSymbol $secondInput = $result"
calculateHistories.value += calculateHistory
coroutineScope.launch {scrollState.animateScrollToItem(calculateHistories.value.size)}
firstInput = result.toString()
secondInput = ""
selectedAction.value = null
Log.d(TAG, "계산결과 : $result")
} ?: Log.d(TAG, "선택된 연산이 없습니다!")
})
}
item(span = {GridItemSpan(maxLineSpan)}){
Text("구글 광고 처리",
textAlign = TextAlign.Center,
modifier = Modifier
.border(1.dp,Color.Blue)
.height(60.dp)
.wrapContentHeight()
)
}
} )
}
}
@Composable
fun NumberText(
firstInput: String,
secondInput: String,
selectedSymbol: String,
modifier: Modifier = Modifier
){
Row(
modifier = modifier,
verticalAlignment = Alignment.Bottom,
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.End)
){
Text(
text = firstInput,
fontSize = 50.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
lineHeight = 50.sp,
maxLines = 1,
color = Color.Black
)
Text(
text = selectedSymbol,
fontSize = 50.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
lineHeight = 50.sp,
maxLines = 1,
color = Purple40
)
Text(
text = secondInput,
fontSize = 50.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
lineHeight = 50.sp,
maxLines = 1,
color = Color.Black
)
}
}
@Composable
fun NumberButton(number: Int, onClicked : () -> Unit){
Card(
elevation = CardDefaults.cardElevation(8.dp),
onClick = onClicked
) {
Text(number.toString(),
modifier = Modifier
.padding(16.dp)
.fillMaxSize(),
textAlign = TextAlign.Center,
fontSize = 30.sp,
fontWeight = FontWeight.Bold
)
}
}
@Composable
fun ActionButton(action: CalculateAction,
selectedAction : CalculateAction?=null,
onClicked: (() -> Unit)?=null){
val isSelected : Boolean = selectedAction == action
val cardContainerColor : Color = if(isSelected) Purple40 else ActionButtonBgColor
val cardContentColor : Color = if(isSelected) Color.White else Color.Black
Card(
elevation = CardDefaults.cardElevation(8.dp),
colors = CardDefaults.cardColors(cardContainerColor, cardContentColor),
onClick = {
Log.d(TAG, "Card가 클릭되었다.")
onClicked?.invoke()
}
) {
Text(
action.symbol,
modifier = Modifier
.padding(16.dp)
.fillMaxSize(),
textAlign = TextAlign.Center,
fontSize = 30.sp,
fontWeight = FontWeight.Bold
)
}
}
fun doCalculate(
firstNumber: Float,
secondNumber: Float,
action: CalculateAction) : Float?{
return when(action){
CalculateAction.Plus -> firstNumber + secondNumber
CalculateAction.Minus -> firstNumber - secondNumber
CalculateAction.Multiply -> firstNumber * secondNumber
CalculateAction.Divide -> firstNumber / secondNumber
else -> null
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
MyCalculator2Theme {
Greeting("Android")
}
}
728x90
'[여러가지 시도] > 코틀린 결과물' 카테고리의 다른 글
[결과물_앱] 챗봇앱 (0) | 2022.11.12 |
---|---|
[결과물_앱] 타이머 (0) | 2022.10.29 |
[결과물_앱] 로또번호 생성기 (0) | 2022.10.28 |