이 앱은 카페 키오스크 앱으로 주문부터 결제까지 사용자에게 편리한 기능을 서비스하는 애플리케이션이다.
앱을 시작하면 맨 처음에 로고 화면이 포함된 로딩 화면이 2초간 나온 후 간단한 문구가 있는 홈 화면으로 이동
해당 화면 어디든지 터치하면 카페 메뉴가 있는 화면으로 이동
메뉴는 여러 카테고리별로 구성되어 있으며 정해진 시간 안에 원하는 메뉴와 해당 옵션을 선택하여 리스트에 담을 수 있다.
또한 메뉴 삭제는 물론 수량까지 변경이 가능하며 원하는 메뉴를 담았다면 결제하기 버튼을 통해 사용자가 선택한 전체 리스트들을 총 수량, 총금액과 함께 한눈에 볼 수 있는 화면이 보이며 사용자는 선택한 목록들을 확인한 후에 다음 화면으로 장소를 선택할 수 있는 화면이 나타난다.
원하는 장소 선택 후 카드 결제 창이 나타나는데 총 결제 금액을 확인한 후 승인 요청을 하면 된다.
결제가 승인되면 결제가 완료되었다는 화면이 나타나면서 5초 후에 자동으로 다시 메인 화면으로 되돌아가는 간단한 키오스크 애플리케이션이다.
홈 화면에서 화면을 터치하면 나오는 메인 화면으로 사용자가 원하는 카테고리에서 메뉴를 선택할 수 있는 화면
메뉴를 옆으로 슬라이드 하거나, 원하는 카테고리 탭 클릭으로 메뉴 선택 가능
총 300초가 주어지며 새로운 메뉴가 추가될 때마다 300초로 초기화
시간이 초과된다면 모든 리스트를 비우고 홈 화면으로 돌아가는 구조
<TabLayout>
사용하여 표시<com.google.android.material.tabs.TabLayout
android:id="@+id/lyj_tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable">
</com.google.android.material.tabs.TabLayout>
app:tabMode="scrollable"
를 통해 탭이 많은 경우 스크롤 가능하도록 설정
<FrameLayout>, <ViewPager2>
사용하여 표시<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="7">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/lyj_viewPager2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout>
안에 <ViewPager2>
를 포함하여 여러 페이지를 스와이프 하면서 해당 위치에 각 페이지의 콘텐츠를 표시
메뉴 표시
하는 코틀린 코드tabLayout = findViewById(R.id.lyj_tabLayout)
viewPager2 = findViewById(R.id.lyj_viewPager2)
val viewPager2Adapter = ViewPager2Adapter(this)
viewPager2.adapter = viewPager2Adapter
// 탭 메뉴 추가
val tabs = listOf(
"커피(HOT)",
"커피(ICE)",
"에이드&티",
"음료",
"디저트"
)
TabLayoutMediator(tabLayout, viewPager2) { tab, position ->
// 리스트 목록을 가져와 탭에 보여주기
tab.text = tabs[position]
}.attach()
ViewPager2Adapter
를 생성하여 어댑터 설정tabs
변수에 표시할 탭 목록 작성TabLayoutMediator
를 사용하여 tabLayout, viewPager2 연결시키기화면을 스와이프하거나 탭 선택하여 해당 페이지의 콘텐츠를 표시
tab.text
로 해당 position
에 있는 텍스트 전달받아 해당 탭에 표시<FrameLayout
tools:context=".hotCof_Fragment">
<ScrollView>
<LinearLayout>
<LinearLayout>
<LinearLayout
android:id="@+id/lyj_hot_ameri">
<ImageView
android:id="@+id/lyj_hot_ameri_img"
android:background="@drawable/hot_cof"/>
<TextView
android:id="@+id/lyj_hot_ameri_text"
android:text="(HOT) 아메리카노"/>
<LinearLayout
android:gravity="center">
<TextView
android:id="@+id/lyj_hot_ameri_price"
android:text="1500"/>
<TextView
android:text="원"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
</FrameLayout>
<FrameLayout>
안에 <ScrollView>
를 작성하여 메뉴 스크롤 가능하도록 구현<LinearLayout>
전체 구조 안에 한 줄 씩 <LinearLayout>
형태로 구성<LinearLayout>
안에 <ImageView>
, <TextView>
로 존재class ViewPager2Adapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
override fun getItemCount(): Int = 5
// Fragment 연결
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> hotCof_Fragment()
1 -> iceCof_Fragment()
2 -> adeTea_Fragment()
3 -> drink_Fragment()
4 -> dessert_Fragment()
else -> iceCof_Fragment()
}
}
}
createFragment
로 현재 position에 따라 해당하는 각각의 프래그먼트 화면을 반환override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_hotcof, container, false)
val linearLayouts = listOf<LinearLayout>(
view.findViewById(R.id.lyj_hot_ameri),
view.findViewById(R.id.lyj_hot_latte),
// 생략
)
for (linearLayout in linearLayouts) {
linearLayout.setOnClickListener {
handleLinearClick(linearLayout)
}
}
return view
}
<LinearLayout>
에 for 루프를 통해 클릭이벤트 부여val linearLayoutId = linearLayout.id
// 해당 리니어의 id_~ 값들 가져오기
val textId = linearLayout.resources.getIdentifier(
"${resources.getResourceEntryName(linearLayoutId)}_text",
"id",
requireActivity().packageName
)
// "_price", "_img" 코드 생략
linearLayout.id
를 통해 클릭한 해당 LinearLayout의 id를 가져옴resources.getIdentifier()
를 사용하여 리소스 id를 동적으로 가져옴<LinearLayout>
에서 메뉴 이름, 가격, 이미지를 가져오기var text: String? = null
var price: Int? = null
var imageDrawable: Drawable? = null
// 해당 리니어의 정보 가져오기
linearLayout.findViewById<TextView>(textId)?.let {
text = it.text.toString()
}
linearLayout.findViewById<TextView>(priceId)?.let {
price = it.text.toString().toInt()
}
linearLayout.findViewById<ImageView>(imageId)?.let { imageView ->
imageDrawable = imageView.background
}
if (text != null && price != null && imageDrawable != null) {
// 다이얼로그에 정보 전달
val dialog = optionDialog(
resources.getResourceEntryName(linearLayoutId), text!!, price!!, imageDrawable!!
)
dialog.show(activity?.supportFragmentManager!!, "CustomDialog")
}
private lateinit var countDownTimer: CountDownTimer
private var isCountDownRunning = false
private val COUNTDOWN_TIME = 300000 // 300초를 밀리초로 표현 300000
private val COUNTDOWN_INTERVAL = 1000 // 카운트다운 간격을 1초로 설정
private var initialCountDownTime: Long = COUNTDOWN_TIME.toLong()
private fun resetCountDown() {
stopCountDown()
startCountDown()
}
- 현재 카운트다운을 중지시키고 다시 초기화된 카운트다운 시작
override fun onResume() {
super.onResume()
if (!isCountDownRunning) {
startCountDown()
}
}
- 액티비티가 다시 활성화될 때 카운트다운 시작
- isCountDownRunning 값이 false인 경우에 카운트다운 시작
- 카운트다운 중복이 발생하는 경우 방지
override fun onPause() {
super.onPause()
isCountDownRunning = true
stopCountDown()
}
- 액티비티가 일시 중지되었을 때 호출
isCountDownRunning 를 true로 설정하여 일시적으로 중지 상태임을 표시하여
onResume()가 내부적으로 호출되어 카운트다운이 중복 시작되는 것을 방지
- stopCountDown()를 호출하여 현재 진행 중인 카운트다운 중지
🛎️ 시간 초과되어 홈 화면 이동하였는데 계속 일정 주기로 "시간 초과"의 토스트 메시지가 나타남
-> onPause()로 해결
- onPause()는 활동이 더 이상 전면에 표시되지 않고, 백그라운드로 이동할 때 호출
- MainActivity가 백그라운드에 있을 때 카운트다운을 정지
- onResume()로 액티비티가 다시 활성화될 때 카운트다운 시작
override fun onDestroy() {
super.onDestroy()
stopCountDown()
}
- 액티비티가 소멸되지 전에 호출하여 카운트다운 중지
private fun stopCountDown() {
if (isCountDownRunning) {
countDownTimer.cancel()
}
// 카운트다운 중지
isCountDownRunning = false
}
- 현재 카운트다운 실행 중일 경우 카운트다운 중지
- countDownTimer를 호출하여 중지하고 false로 설정하여 중지 되었음을 표시
private fun startCountDown() {
// 카운트다운 시간 초기화
initialCountDownTime = COUNTDOWN_TIME.toLong()
countDownTimer =
object : CountDownTimer(COUNTDOWN_TIME.toLong(), COUNTDOWN_INTERVAL.toLong()) {
override fun onTick(millisUntilFinished: Long) {
val second = millisUntilFinished / 1000
lyj_countDownTime.text = second.toString()
initialCountDownTime = millisUntilFinished // 카운트 시간 업데이트
}
// 카운트다운 종료
override fun onFinish() {
clearItemListAll()
val intent = Intent(this@MainActivity, HomeActivity::class.java)
startActivity(intent)
Toast.makeText(applicationContext, "주문 시간이 만료되었습니다.", Toast.LENGTH_SHORT).show()
}
}
countDownTimer.start()
isCountDownRunning = true
}
- 카운트다운 시작
- countDownTimer 객체 생성하여 카운트다운 시간과 간격 설정
- onTick() 함수는 정의한 COUNTDOWN_INTERVAL(1초) 마다 호출되는 로직 정의
- millisUntilFinished / 1000 로 나누어 "초" 단위 변환
- onFinish() 함수에 카운트다운이 종료될 경우 clearItemListAll() 함수 호출하여 리스트 모두 비운 후
토스트 메시지와 함께 홈 화면으로 이동