iT邦幫忙

2024 iThome 鐵人賽

DAY 23
0

前言

這兩天我們製作了元件的動畫和APP的啟動動畫,今天我們來做點不一樣的東西,現在的APP很常看到一些元件能夠透過上下滑動來觸發事件,今天我們就要來實做這個功能。

上下滑動的手勢觸發事件

其實在Modifier中有一個用來處理手勢檢測的擴展函數.pointerInput()它接受一個 lambda 函數作為參數,並且允許我們定義手勢行為,例如觸控、滑動、長按等。
下面我們在原先預曆元件的位置加入一段程式碼

  • kotlin
  Box(
                    modifier = Modifier
                        .weight(1f)
                        .fillMaxHeight()
                        .padding(4.dp)
                        .background(MaterialTheme.colorScheme.background)
                        .pointerInput(Unit) {
                            detectVerticalDragGestures(
                                onVerticalDrag = { change, dragAmount ->
                                    if (dragAmount > 0) {
                                        Log.d("Gesture", "DOWN")
                                    } else {
                                        Log.d("Gesture", "UP")
                                   }
                                }
                            )
                        },
                    contentAlignment = Alignment.Center
                ) {
                    // 日曆內容
                    CalendarPager(
                        events = calendarEvents,
                        showDayView = showDayView,
                        selectedDate = selectedDate,
                        selectedEvents = selectedEvents,
                        onShowDayViewChanged = { showDayView = it },
                        onSelectedDateChanged = { selectedDate = it },
                        onSelectedEventsChanged = { selectedEvents = it }
                    )
                }

detectVerticalDragGestures是專門用來偵測垂直方向上的拖動手勢。在這個案例中,我們提供了一個 lambda onVerticalDrag函數來定義拖動時的行為而dragAmount是用來指示拖動的距離,正值表示向下拖動,負值表示向上拖動。這個 lambda 函數定義了當偵測到垂直拖動手勢時要執行的動作:
因此在月曆元件上下滑動時,可以在LOGCAT那邊看到相對應的LOG

///上滑
2024-10-07 21:21:38.619 12045-12045 Gesture   com.example.a2024ironman  D  UP
///下滑
2024-10-07 21:21:40.429 12045-12045 Gesture   com.example.a2024ironman  D  DOWN

現在知道如何用上下滑動的手勢觸發事件後,我們可以修改一下我們的月曆元件,來添加更多的功能
程式碼如下

  • kotlin
package com.example.a2024ironman

import android.util.Log
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import com.google.api.services.calendar.model.Event
import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.HorizontalPager
import androidx.compose.foundation.gestures.detectVerticalDragGestures
import androidx.compose.ui.input.pointer.pointerInput
import com.google.accompanist.pager.rememberPagerState
import java.util.Calendar

@OptIn(ExperimentalPagerApi::class)
@Composable
fun CalendarPager(
    events: List<Event>,
    showDayView: Boolean,
    selectedDate: String,
    selectedEvents: List<Event>,
    onShowDayViewChanged: (Boolean) -> Unit,
    onSelectedDateChanged: (String) -> Unit,
    onSelectedEventsChanged: (List<Event>) -> Unit
) {
    // 取得當前日期
    val today = Calendar.getInstance()
    val currentMonth = today.get(Calendar.MONTH) // 當前月份
    val currentYear = today.get(Calendar.YEAR)   // 當前年份

    // 初始頁設置為當前月份
    val initialPage = 6
    val pagerState = rememberPagerState(initialPage = initialPage)

    if (showDayView) {
        DayCalendar(
            selectedDate = selectedDate,
            events = selectedEvents,
            onBack = { onShowDayViewChanged(false) }
        )
    } else {
        LaunchedEffect(events) {
            if (events.isNotEmpty()) {
                Log.e("LaunchedEffect", "events loaded: ${events.size}")
            } else {
                Log.e("LaunchedEffect", "events still empty")
            }
        }
        HorizontalPager(
            count = 12, // 一年12個月
            state = pagerState,
            modifier = Modifier
                .fillMaxSize()
                .pointerInput(Unit) {
                    detectVerticalDragGestures(
                        onVerticalDrag = { change, dragAmount ->
                            if (dragAmount < 0) {
                                // 上滑手勢,觸發切換到日行事曆視圖
                                Log.d("Gesture", "UP")

                                // 取得今天的日期
                                val todayDate = "${today.get(Calendar.YEAR)}-${today.get(Calendar.MONTH) + 1}-${today.get(Calendar.DAY_OF_MONTH)}"

                                // 切換到日行事曆視圖並設置當前日期和事件
                                onShowDayViewChanged(true) // 顯示日行事曆
                                onSelectedDateChanged(todayDate) // 設置當天日期

                            }
                        }
                    )
                }
        ) { page ->
            // 計算顯示的月份與年份
            val monthOffset = page - initialPage
            val displayedMonth = (currentMonth + monthOffset) % 12
            val displayedYear = currentYear + (currentMonth + monthOffset) / 12

            // 判斷是否是當前月份
            val isCurrentMonth = (displayedMonth == today.get(Calendar.MONTH)
                    && displayedYear == today.get(Calendar.YEAR))

            // 今天的日期
            val todayDay = today.get(Calendar.DAY_OF_MONTH)
            Log.e("MonthlyCalendar events", events.toString())
            MonthlyCalendar(
                page = page,
                todayDay = todayDay,
                isCurrentMonth = isCurrentMonth,
                events = events,
                onDayClick = { date, dayEvents ->
                    // 點擊日期時的邏輯
                    onSelectedDateChanged(date)
                    onSelectedEventsChanged(dayEvents)
                    onShowDayViewChanged(true)
                }
            )
        }
    }
}

上面的程式碼可以實現透過上滑月曆元件的頁面跳轉到當日的日行事曆裡面
實際效果如下
https://ithelp.ithome.com.tw/upload/images/20241007/20162649lcxCtNTt0F.png
當我們項上滑動時
https://ithelp.ithome.com.tw/upload/images/20241007/20162649E1Cy7THDEc.png
他就會跳轉到當日行事曆了。

後話

今天我們透過手勢成功觸發切換畫面的是事件,本來因為APP已經有點滿了,不太好找地方加新要素,而這個東西可以很方便的拓展我們的APP,那今天的內容就到這邊了,讓我們明天再見。


上一篇
Day22:使用NavHost呈現啟動動畫
下一篇
Day24:多手勢偵測事件
系列文
github裡永遠有一個還沒做的SideProject :用Kotlin來開發點沒用的酷東西30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言