2026/03/11

오늘의 이야기

https://relay.material.io/getting-started







Relay


Instant Handoff for Android UI. Design UI components in Figma and use them directly in Jetpack Compose projects.


relay.material.io





Relay


릴레이, 계전기, 교체 구글 번역기가 말해주는 번역된 단어입니다. 알게 된 것은 HOLIX라는 앱에서 jetpack compose 채팅방에 들어가 보다가 workspace 님이 올리신 글을 보고 알게 되었습니다.

찾아서 가 따라 해 보기를 해 보았습니다. 그 동안 고민했던 것들 중에 화면 구성을 어떻게 하면 그나마 쉽게 다이내믹하게 할 수 있을 까에 대한 고민을 해소할 수 있을 것 같은 생각이 듭니다.

그동안의 화면 구성은 그냥 단순하게 Object을 위치하는 것으로 대신하는 중이었습니다. 뭐 아직은 화려하거나 이쁘거나 한 화면 구성을 못해보는 것이 아쉬울 따름 이었지만, Figma라는 것이 온라인으로 화면 디자인을 할 수 있다는 것 정도만 알고 있었지 이것을 UI와 연동할 수 있다는 것을 모르고 있었으니까요.

샘플앱


이런 디자인은 간단한 것이라 그냥 그려도 되겠지만, 연동을 해서 만들어 보면 좋을 것 같다는 생각이 들었습니다.

차근 차근 배워 봐야 할 것 같아요.

이번 이야기는 10/24 에 있었던 Android Dev Summit 2022 에서 발표된 이야기 랍니다.





오늘의 이야기

TabRow  


앱을 구성하는 부분 중에서 메뉴판 같은 것을 구현하게 되는 경우가 발생합니다. 다른 방법도 있기는 하겠지만, 카테고리별로 TabRow을 구현해서 만들면 같은 종류의 상품을 배열하거나 할 때 도움이 될 것 같습니다.  그래서 오늘은 그걸 만들어 보려고 합니다. 


 


gradle (Module) 파일에 아래 2줄을 추가해 주었습니다.


// tab layout 구현
implementation "com.google.accompanist:accompanist-pager:0.20.1"
implementation "com.google.accompanist:accompanist-pager-indicators:0.20.1"

이제 코드 구현을 해 보겠습니다. 


 


val pagerState = rememberPagerState(0)

먼저 사용할 탭의 상태를 기억할 변수를 선언 합니다. 괄호 안에 숫자는 시작 시 어디에 위치하게 할 건가를 정하게 됩니다. 인덱스는 0부터 시작됩니다.


 


구성된 화면은 다음 그림과 같이 될 예정입니다.


구성된 화면



그래서 화면을 구성할 때 상단에 있는 Tab을 나타내는 부분과 그 아래 내용을 보여줄 부분으로 나누어서 설정을 하게 됩니다. (*맨 아래는 BottomNavigation으로 이번 글과는 무관한 구현이라 설명을 생략합니다.)


 


Column(
modifier = Modifier.background(grayWhite)
) {
Tabs(pagerState = pagerState)
TabsContent(pagerState = pagerState)
}

위에 Tabs는 화면 상단에 표시할 탭을 나타내며 아래 TabsContent는 아래 화면을 구성할 내용을 채워 넣을 공간입니다.


 


@ExperimentalPagerApi
@Composable
fun Tabs(pagerState: PagerState) {
val list = listOf(
"Order" to Icons.Outlined.GifBox,
"Shopping" to Icons.Outlined.ShoppingCart,
"Payments" to Icons.Outlined.Payments
)
val scope = rememberCoroutineScope()
TabRow(

selectedTabIndex = pagerState.currentPage,
backgroundColor = softBlue,
contentColor = Color.White,
indicator = { tabPositions ->
TabRowDefaults.Indicator(
Modifier.pagerTabIndicatorOffset(pagerState, tabPositions),
height = 2.dp,
color = Color.White
)
}
) {
list.forEachIndexed { index, _ ->
Tab(
icon = {
Icon(imageVector = list[index].second, contentDescription = null)
},
text = {
Text(
list[index].first,
color = if (pagerState.currentPage == index) grayWhite else Color.LightGray
)
},
selected = pagerState.currentPage == index,
onClick = {
scope.launch {
pagerState.animateScrollToPage(index)
}
}
)
}
}
}

먼저 배열에 표시할 Tab의 제목으로 사용할 부분을 만들고, TabRow을 이용해서 그 항목들을 나열하는 구현을 하게 됩니다. 


 


@ExperimentalPagerApi
@Composable
fun TabsContent(pagerState: PagerState) {
HorizontalPager(modifier = Modifier.fillMaxSize(), state = pagerState, count = 5) {
page ->
when (page) {
0 -> TabContentScreen(data = "Order")
1 -> TabContentScreen(data = "Shipping")
2 -> TabContentScreen(data = "Payments")
}
}
}

다음은 그 내용들을 표시할 화면을 만들고 HorizontalPager을 이용해서 어느 탭을 선택했는지 전달받고 그 값에 따라서 하단에 각각의 화면을 구성하는 모양을 만들면 됩니다. 


 


이 적용을 통해서 구현을 잘해 보도록 하겠습니다.


 


이 구현은 다음의 링크에서 참조했음을 밝혀 둡니다.


https://www.geeksforgeeks.org/tab-layout-in-android-using-jetpack-compose/



 


Tab Layout in Android using Jetpack Compose - GeeksforGeeks


A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.


www.geeksforgeeks.org




 





오늘의 이야기


#스하리1000명프로젝트,
Perso in Corea? Anche se non parli coreano, questa app ti aiuta a muoverti facilmente.
Basta parlare la tua lingua: traduce, cerca e mostra i risultati nella tua lingua.
Ottimo per i viaggiatori! Supporta oltre 10 lingue tra cui inglese, giapponese, cinese, vietnamita e altre.
Provalo adesso!
https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/03/10

오늘의 이야기

 


네이버 지식인 프로필



아주 오래전에 네이버 지식인에 등록을 했었습니다.  이게 뭔가 하고... 그렇게 잊혀 지나가길 10여 년이 지났을 언제가 같이 근무하는 지인의 친구가 네이버 지식인 활동을 통해서 수입이 생긴다는 말을 들었던 시절쯤, 다시 지식인 활동을 시작했습니다. 그러다가 뜨문뜨문 하게 되어 시간이 많이 흘렀습니다. 


 


등급이 올라가는 속도는 갈 수록 느려지는 것 같아요. 처음 몇 단계는 쉽게 올라가더니... 이제 지존 다음 단계인 초인으로 가기 위해서는 답변 채택이 200개가 더 있어야 한다고 하네요. 답변 채택률이 87% 수준이면 잘하는 건가는 모르겠지만,  비율로 치면 220개가량은 답을 달아야 한다는 결론이 나오네요.


 


그것도 시간으로 때워야 할 것 같은 생각이 들기는 합니다. 다만, expert 활동을 할 수 있는 조건이 완화 되었다는 소식이 있네요. 그래서 조만간 export 활동을 해 볼 수 있을 것 같습니다. 


 


그날을 기다리면서... 오늘도 수고 했으니 잘 쉬세요. 





오늘의 이야기

지난 포스팅에 연속해서



https://billcorea.tistory.com/267







개발일기 #5 PAYAPP 연동을 위한 준비


이번 개발을 시작하면서 준비해야 할 것 중에 하나가 결제처리를 지원하는 PG(Payment GateWay) 연동 이었습니다. 이전 글에서도 적었던 것처럼 일반적인 PG 연동 API 들은 하나 같이 쇼핑몰 앱을 기반(


billcorea.tistory.com





구동되는 이야기는 지난 포스팅에 적었습니다. 참고하시면 될 것 같고요. 오늘은 그것들을 구현하기 위해 했던 코드 구현에 대해서 이야기해 보겠습니다.


HTTP 통신은


일반적으로 API 통신은 HTTP 을 이용해서 호출하라고 합니다. 이번에 사용했던 PAYAPP의 경우에도 동일합니다. 이런 경우 안드로이드에서는 통신과 관련된 몇 가지 해야 할 부분들이 있습니다.

먼저 manifest 에서의 권한 설정 부분이 필요합니다.


<uses-permission android:name="android.permission.INTERNET" />

인터넷 사용에 대한 권한을 등록합니다. 다음은 통신의 하는 경우 네트워크와 관련해서는


<application
...
android:usesCleartextTraffic="true"
... >

<activity
android:name=".MainActivity"
android:exported="true"

...

안드로이드 가이드 발췌


개발자 가이드에서 알려주고 있는 것과 같이 네트워크 트래픽에 대한 설정을 true로 해 주어야 합니다.

그다음 요구되는 사항은 http connect을 맺거나 하는 경우 비동기 설정을 해 주어야 하는 부분이 있습니다. 그래서 구글링을 해보면 여러 가지 방법들이 설명이 되어 있습니다. thread을 이용하여 하거나 그 외 다른 비동기 통신 방법을 구현하고 설명합니다.

https://ktor.io/







Ktor: Build Asynchronous Servers and Clients in Kotlin


Kotlin Server and Client Framework for microservices, HTTP APIs, and RESTful services


ktor.io




이번에는 Ktor 방식을 이용한 비동기 통신을 구현해 보기로 했습니다.



gradle 파일 설정


gradle 파일에는 아래와 같이 ktor을 사용하기 위해서 implementaion을 설정했습니다. 2022.10.20 쯤에는 2.1.2 버전이 최신 버전이라고 되어 있습니다.


//ktor
implementation "io.ktor:ktor-client-core:2.1.2"
implementation "io.ktor:ktor-client-cio:2.1.2"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'


Helper 구현하기


먼저 통신을 위한 helper 을 구현해 봅니다.


import android.util.Log
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.util.date.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class HttpRequestHelper {

companion object {
val TAG: String = HttpRequestHelper::class.java.name
}

private val client: HttpClient = HttpClient(CIO)

/**
* https://api.payapp.kr/oapi/apiLoad.html
*
* cmd=payrequest&userid=payapptest&goodname=testGood&price=1000&recvphone=01055559999&smsuse=n
*
*/
suspend fun requestKtorIoInDetail(): String =
withContext(Dispatchers.IO) {
// set HttpRequestBuilder
val response: HttpResponse = client.request("https://api.payapp.kr/oapi/apiLoad.html") {
method = HttpMethod.Post
headers {
append("Content-Type", "application/x-www-form-urlencoded")
}
parameter("cmd","payrequest")
parameter("userid","payapptest")
parameter("goodname","testGood")
parameter("price","1000")
parameter("recvphone","01055559999")
parameter("smsuse","n")
}
val responseStatus = response.status
Log.d(TAG, "requestKtorIo: $responseStatus")

if (responseStatus == HttpStatusCode.OK) {
response.bodyAsText()
} else {
"error: $responseStatus"
}
}
}

개발자 가이드에서 말하는 것처럼 thread을 지원하여 사용자는 앱이 멈춤을 느끼지 않도록 하고 비동기 통신을 이용하여 목적에 필요한 자료를 전송하고 결과를 수집할 수 있습니다.

https://developer.android.com/kotlin/coroutines-adv?hl=ko







Kotlin 코루틴으로 앱 성능 향상  |  Android 개발자  |  Android Developers


Kotlin 코루틴으로 앱 성능 향상 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Kotlin 코루틴을 사용하면 네트워크 호출이나 디스크 작업과 같은 장기 실행 작


developer.android.com




payapp 결제 연동


payapp api 가이드에서 설명하는 결제 연동 페이지로의 호출 부분은 위 예시된 코드와 같이 url을 호출하면 됩니다. 이번에 구현하고자 하는 앱의 경우는 결제 연동만 일단 구현해 볼 요량이므로 위 코드와 같이 구현하고, 관련된 정보를 추가로 파라미터로 전송하여 결제 연동을 위한 QRcode 이미지를 webView에 보여주는 방식으로 진행하고 있습니다.

































파라미터 전달 값
cmdpayrequest (고정값 : 결제 요청시 사용)
useridpayapp 에 판매 회원으로 가입한 id
goodname판매하는 상품명칭
price가격
recvphone결과를 수신받을 휴대전화번호
smsusesms 사용여부

위 정도는 필수값이고 그 외에도 다른 항목들이 있지만 그것은 API 문서를 참조하여 보시기 바랍니다. 이번 앱 구현에서는 이 정도만 있어도 됩니다.


MainActivity에서 사용


class MainActivity : ComponentActivity() , CoroutineScope {

.....
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job

...

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

sp = getSharedPreferences(packageName, MODE_PRIVATE)
job = Job() // CoroutineScope를 위해 job을 할당

...

}

.....

private fun doPunched(destinationsNavigator: DestinationsNavigator) {
var errno = ""
var qrUrl = ""
launch(Dispatchers.Main) {
val result = HttpRequestHelper().requestKtorIoInDetail()
val decoded = URLDecoder.decode(result, "UTF-8")
var lineItems = decoded?.split("&")
if (lineItems != null) {
for (line in lineItems) {
Log.e("", "${line}")
if (line.indexOf("errno") > -1) {
errno = line.split("=")[1]
}
if (line.indexOf("qrurl") > -1) {
qrUrl = line.split("=")[1]
}
}
}
Log.e(TAG, "${qrUrl} ${errno}")
if (!"".equals(qrUrl)) {
doWebView(qrUrl, destinationsNavigator)
}
}
}

.....

fun doFinish() {
job.cancel() // 종료 되게...
finish()
}

mainActivity에서 다른 구현이 많이 있기는 하겠지만, 코루틴 사용을 위해서 Job을 선언하는 부분 등 필요한 부분만 나열을 하였으니 코드 구현 시 참고하셔야 합니다. 위 예시 코드와 같이 launch 구문을 이용해서 위에서 작성한 helper을 호출하면 결과 값이 string으로 돌아오기 때문에 그 값을 파싱 해서 qrurl 부분만 값으로 받아오고 그 값을 전달해서 webview에 표시하는 것으로 구현은 마무리가 됩니다.


@Composable
fun Url2WebView(
qrUrl : String,
doBackQRCode:() -> Unit
){

val fontFamily = FontFamily(Font(R.font.poorstory_regular, FontWeight.Normal))
Column(
modifier = Modifier
.fillMaxSize()
.padding(20.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Row(
modifier = Modifier.padding(2.dp),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = {
doBackQRCode()
}) {
Icon(
imageVector = Icons.Outlined.ArrowBack,
contentDescription = "ArrowBack",
tint = softBlue
)
}
Text(text = stringResource(id = R.string.msgPunchedQRCode), style = TextStyle(
fontWeight = FontWeight.Bold, color = softBlue, fontSize = 24.sp,
fontFamily = fontFamily
))
}
// Adding a WebView inside AndroidView
// with layout as full screen
AndroidView(factory = {
WebView(it).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
webViewClient = WebViewClient()
loadUrl(qrUrl)
}
}, update = {
it.loadUrl(qrUrl)
})
}
}


이제 앱이 잘 구현 되기를 바라면 글을 정리해 보겠습니다.





오늘의 이야기



#스치니1000프로젝트 #재미 #행운기원 #Compose #Firebase

🎯 야 너 토요일마다 로또 확인하냐?
나도 맨날 "혹시나~" 하면서 봤거든 ㅋㅋ

근데 이제는 그냥 안 해
AI한테 맡겼어 🤖✨

그것도 구글 Gemini로다가!

그래서 앱 하나 만들었지
👉 "로또 예상번호 by Gemini" 🎱

AI가 분석해서 번호 딱! 뽑아줌
그냥 보고 참고만 하면 됨

재미로 해도 좋고…
혹시 모르는 거잖아? 😏


https://play.google.com/store/apps/details?id=com.billcorea.gptlotto1127




오늘의 이야기

이번 개발을 시작하면서 준비해야 할 것 중에 하나가 결제처리를 지원하는 PG(Payment GateWay) 연동 이었습니다. 이전 글에서도 적었던 것처럼 일반적인 PG 연동 API 들은 하나 같이 쇼핑몰 앱을 기반(?)으로 구동하는 것을 전제로 구현됩니다.

하지만, 이번에 구현해 보고 싶었던 앱은 결제를 중개해 주는 기능을 구현해 보고자 했습니다. 그래서 찾다 찾은 것은 PAYAPP 이라는 앱입니다.
https://payapp.kr/homepage/about/about.html







페이앱 공식 홈페이지


페이앱 본사, 블로그마켓 카드결제, 수기결제, 블로그결제, SMS결제, 블로그페이, 본사 고객센터 1800-3772


www.payapp.kr




* 아직은 이 회사와 아무런 관계가 없음을 미리 말해 둡니다.

단지, 구현해 보고자 했던 방향과 맞는 것 같아서 찾은 것일 뿐입니다

결제를 위한 QRCode


구현해 가는 방향은 이렇게 QRCode 을 보여 주면 고객은 휴대폰의 QRcode 스캐너, 카메라 앱을 이용해서 해당 링크로 넘어갑니다. 그러면 고객의 휴대폰에 다음과 같이 결제을 유도하는 창이 나타납니다.

결제요청페이지


이 페이지를 이용해서 결제는 고객의 휴대폰에서 진행됩니다. 결제가 완료되면 주문이 전달되는 그런 형태의 앱을 구현해 보고 있는 중입니다.





오늘의 이야기


#스하리1000명프로젝트

스치니들!
내가 만든 이 앱은, 내 폰에 오는 알림 중에서 중요한 키워드가 있는 경우
등록해둔 친구에게 자동으로 전달해주는 앱이야 📲

예를 들어, 카드 결제 알림을 와이프나 자녀에게 보내주거나
이번 달 지출을 달력처럼 확인할 수도 있어!

앱을 함께 쓰려면 친구도 설치 & 로그인해줘야 해.
그래야 친구 목록에서 서로 선택할 수 있으니까~
서로 써보고 불편한 점 있으면 알려줘 🙏

👉 https://play.google.com/store/apps/details?id=com.nari.notify2kakao





오늘의 이야기

바탕화면 이미지


이 꽃은 국화꽃이 형상화된 것 같습니다. 어느 날 퇴근 후에 노트북을 열었더니, 보였습니다.

이미지만 으로도 슬픔과 또 다른 어떤 느낌이 와닿았습니다.

어느 토요일 카카오의 데이터 센터 화재로 인해 몇일이 어떻게 지났는지 모르게 지났습니다

현장에서 대응하시는 분들의 속이 타 들어 가는 것을 다 알지는 못하지만, 나름 같은 IT업으로 먹고살고 있는 지라, 혹시 우리 센터에서도 저런 일이 벌어지면 대응이 잘 될까 하는 생각이 드는 일이기에, 연일 뉴스에 나오는 것처럼 말을 할 수는 없었습니다.

아무튼 오늘도 수고 하였으니, 편안한 밤이 되시길 바라며...





오늘의 이야기

https://github.com/afollestad/material-dialogs



 


GitHub - afollestad/material-dialogs: 😍 A beautiful, fluid, and extensible dialogs API for Kotlin & Android.


😍 A beautiful, fluid, and extensible dialogs API for Kotlin & Android. - GitHub - afollestad/material-dialogs: 😍 A beautiful, fluid, and extensible dialogs API for Kotlin & Android.


github.com




오늘은 앱을 구현하는 동안 간혹 사용하여야 하는 dialog box 구현에 대한 이야기를 해 보겠습니다.  위 링크에서 가져온 자료를 참고하여 구현하는 이야기를 해 볼 예정입니다. 


 


일반적인 dialog 구현해 보기


gradle 설정


먼저 gradle 설정을 해 보겠습니다.  먼저 봐야할 부분은 위 github의 게시글에서 보는 것처럼 dialog box의 여러 가지 형태 중에 어떤 것을 구현할 것인가를 정해야 할 것 같습니다. 


 


일반적인 diaglog box 예시



이런 모양의 일반적인 dialog box의 구현 부터 보겠습니다. 


 


// 다이얼로그
implementation 'com.afollestad.material-dialogs:core:3.3.0'
implementation 'com.afollestad.material-dialogs:lifecycle:3.3.0'

gradle 파일의 설정은 이 2줄만 가져 오면 됩니다.


 


Activity 구현


 


다음은 버튼을 표시하는 MainActivity 의 함수 하나를 보겠습니다. 


override fun onBackPressed() {
MaterialDialog(this@MainActivity).show {
icon(R.drawable.ic_bespeak_foreground)
title(R.string.titleFinish)
message(R.string.mesgFinish)
positiveButton(R.string.OK) { doFinish() }
negativeButton(R.string.Cancel) { this.dismiss() }
}
}

MaterialDialog를 구현한 것인데요. icon 은 말 그대로 알림 창에 icon 이 나옵니다  title 은 제목을 쓸 내용을 정리하면 되고요 message 에는 알림 표시용 글을 표시하면 되고, positiveButton 에는 확인 버튼을 구현하기 위한 메시지 내용과 버튼 클릭 시 동작할 action을 구현합니다. negativeButton 에는 취소 버튼을 구현하기 위한 메시지 내용과 action을 구현합니다. 


 


입력이 있는 Dialog 구현해 보기


gradle 설정


이번에는 입력이 있는 dialog 을 구현해 보겠습니다. 먼저 gradle 설정에 추가 하여야 합니다.


// 입력 받는 다이얼로그
implementation 'com.afollestad.material-dialogs:input:3.3.0'
implementation 'com.google.android.material:material:1.6.1'

저 2줄중에 위에 꺼는 원작자 링크에서 도 찾을 수 있었지만, 아래 줄은 없었습니다. 저 한 줄 때문에 에러가 나와서 찾는 데 애를 쫌 먹었습니다. 아무튼... 그리고 이번에는 style도 잘 정리가 되어야 하는 데, 결론적으로는 아래와 같이 theme.xml 파일을 정리했습니다.  원인은 Theme.AppCompat 이 아닐 경우 위에서 implementation 된 material layout이 동작하지 않는 것으로 보입니다.


 


Theme


그래서 꼭 theme 도 정리를 하고 시작 하시길 바랄게요.


<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">

<style name="Theme.bespeak1003" parent="Theme.AppCompat.DayNight">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/softBlue</item>
<!-- Customize your theme here. -->
<item name="colorAccent">@color/softBlue_30</item>
<item name="android:textColor">@color/softBlue</item>
<item name="android:fontFamily">@font/poorstory_regular</item>
<item name="android:textSize">20sp</item>
<item name="android:windowBackground">@color/softYellow</item>
<item name="android:colorBackground">@color/softGreen</item>
<item name="android:background">@color/rime200</item>
<item name="background">@color/softBlue</item>
</style>

</resources>

 


Activity 구현


입력 줄이 있는 dialog는 아래처럼 구현을 하였는 데, 일단 간결하기는 합니다. 다만, layout 이용해서 하기 때문에 위에서 처럼 theme 설정을 해야 하고, 입력받는 항목이 1개만 지원이 되고 있어서 코드 구현을 다채롭게 할 수는 없었습니다.


private fun doLoginAuth() {
val typeEmail = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
val typePassword = InputType.TYPE_TEXT_VARIATION_PASSWORD
var userEmail = ""
var userPassword = ""
MaterialDialog(this@MainActivity).show {
icon(R.mipmap.ic_bespeak)
title(R.string.titleLogin)
message(R.string.msgEnterEmail)
input(inputType = typeEmail) { diaglog, text ->
userEmail = text.toString()
}
positiveButton(R.string.OK) {
toAction()
}
negativeButton(R.string.Cancel) {
it.dismiss()
}

}
}

입력을 한 개만 받는 부분은 개선(?) 요구를 해 볼까 하는 생각입니다.


입력이 있는 dialog 예시



배색을 잘하지 못해서 구분이 좀 어렵기는 하지만 위 그림처럼 파란 줄에 입력을 하나 받습니다. 그 입력받는 내용을 위 구현에서 보면 input { dialog , text ->  }처럼 구현해서 text로 그 값을 받아 와서 사용할 수 있습니다.  


 


이렇게 dialog 구현을 해 보았습니다. 더 쉬운 방법을 알게 되면 다시 구현해 보겠습니다.


 


 





오늘의 이야기


#스하리1000명프로젝트,
A volte è difficile parlare con i lavoratori stranieri, vero?
Ho realizzato una semplice app che aiuta! Scrivi nella tua lingua e gli altri lo vedono nella loro.
Si traduce automaticamente in base alle impostazioni.
Super pratico per chat facili. Dai un'occhiata quando ne hai la possibilità!
https://play.google.com/store/apps/details?id=com.billcoreatech.multichat416




오늘의 이야기

Cloud Function 서버를 보유 하지(Serverless) 않고 서버가 있는 것처럼 업무 구현을 하고 싶습니다. 개발을 하면서 데이터 베이스와 스토리지를  firebase을 활용하고 있다면 cloud function 도 배워서 준비를 해야 할 ...