SwiftUI 框架

利用 ScrollViewReader 輕鬆讓滾動視圖滾動到特定位置

在新版 SwiftUI 中,其中一個我最喜歡的新功能就是 ScrollViewReader。有了 ScrollViewReader 之後,我們只需要幾行程式碼,就可以使滾動視圖滾動到特定位置。
利用 ScrollViewReader 輕鬆讓滾動視圖滾動到特定位置
利用 ScrollViewReader 輕鬆讓滾動視圖滾動到特定位置
In: SwiftUI 框架

在新版 SwiftUI 中,其中一個我最喜歡的新功能就是 ScrollViewReader。在 iOS 14 推出之前,要控制內置 ScrollView 的滾動位置並不容易。如果想要滾動視圖滾動到特定位置,就需要自己想出解決方案。

有了 ScrollViewReader 之後,我們只需要幾行程式碼,就可以使滾動視圖滾動到特定位置。在這篇教學文章中,我們會探索這個新視圖元件,讓大家了解如何把它應用在 App 上。

創建一個水平的 ScrollView

現在,讓我們從一個簡單的範例看看 ScrollViewReader 的用法。先看看以下的程式碼:

struct ContentView: View {

    let photos = [ "bigben", "bridge", "canal", "effieltower", "flatiron", "oia" ]

    var body: some View {
        GeometryReader { geometry in
            ScrollView(.horizontal) {
                HStack(alignment: .center) {
                    ForEach(photos.indices) { index in
                        Image(photos[index])
                            .resizable()
                            .scaledToFill()
                            .frame(width: geometry.size.width - 50)
                            .cornerRadius(25)
                            .padding(.horizontal, 25)
                    }
                }
            }
        }
    }
}

我們建立了一個水平滾動視圖,來顯示一組照片。如果你在模擬器或預覽面板中執行程式碼,就可以水平滑動以滾動瀏覽照片。

scrollviewreader-app-demo

如果我們現在想添加一些按鈕,讓使用者瀏覽不同的照片,應該怎樣做呢?或者這樣說,我們如何讓滾動視圖滾動到特定圖像?

使用 ScrollViewReader

ScrollViewReader 就是上面問題的解決方法!這個新視圖元件的用法非常簡單。首先,給滾動視圖中的每個元素一個獨特的 ID。在這個範例中,我們可以將 .id 修飾符加到 Image 視圖,並將其數值設置為照片的索引 (index):

Image(photos[index])
    .resizable()
    .scaledToFill()
    .frame(width: geometry.size.width - 50)
    .cornerRadius(25)
    .padding(.horizontal, 25)
    .id(index)

接下來,讓我們利用 ScrollViewReader 包裝滾動視圖。ScrollViewReader 的內容視圖建構器接收 ScrollViewProxy 實例:

GeometryReader { geometry in
    VStack {
        ScrollViewReader { scrollView in
            ScrollView(.horizontal) {
                HStack(alignment: .center) {
                    ForEach(photos.indices) { index in
                        Image(photos[index])
                            .resizable()
                            .scaledToFill()
                            .frame(width: geometry.size.width - 50)
                            .cornerRadius(25)
                            .padding(.horizontal, 25)
                            .id(index)
                    }
                }
            }

            // Navigation Buttons
            HStack {
                // To be complete
            }
            .frame(height: 70)
        }
    }
}

在我們得到 Proxy 後,可以呼叫 scrollTo 函式,以滾動到特定索引。以下面這行程式碼為例,我們要求滾動視圖滾動到最後一張照片:

scrollView.scrollTo(photos.count - 1)

最後,我們可以聲明一個狀態變數 (state variable),來追踪當前的照片索引:

@State private var currentIndex = 0

然後,你可以這樣在 HStack 中編寫程式碼:

HStack {
    Button(action: {
        withAnimation {
            scrollView.scrollTo(0)
        }
    }) {
        Image(systemName: "backward.end.fill")
            .font(.system(size: 50))
            .foregroundColor(.black)
    }

    Button(action: {
        withAnimation {
            currentIndex = (currentIndex == 0) ? currentIndex : currentIndex - 1
            scrollView.scrollTo(currentIndex)
        }
    }) {
        Image(systemName: "arrowtriangle.backward.circle")
            .font(.system(size: 50))
            .foregroundColor(.black)
    }

    Button(action: {
        withAnimation {
            currentIndex = (currentIndex == photos.count - 1) ? currentIndex : currentIndex + 1
            scrollView.scrollTo(currentIndex)
        }
    }) {
        Image(systemName: "arrowtriangle.forward.circle")
            .font(.system(size: 50))
            .foregroundColor(.black)
    }

    Button(action: {
        withAnimation {
            scrollView.scrollTo(photos.count - 1)
        }
    }) {
        Image(systemName: "forward.end.fill")
            .font(.system(size: 50))
            .foregroundColor(.black)
    }
}
.frame(height: 70)

對於每個按鈕,我們都會呼叫 scrollTo 函式來滾動到特定的照片。利用 withAnimation 包裝程式碼後,App 會呈現一個漂亮的滾動動畫。

scrollviewreader-perform-scrolling

在 List 上應用

ScrollViewReader 不僅可以用來包裝 ScrollView,在 List 上也可以應用。假設我們把 App 轉換為列表形式,而不是水平滾動視圖:

ScrollViewReader { scrollView in
    List {
        ForEach(photos.indices) { index in
            Image(photos[index])
                .resizable()
                .scaledToFill()
                .cornerRadius(25)
                .id(index)
        }
    }
 
    .
    .
    .
}

我們還是可以應用 scrollTo 函式,要求列表滾動到特定元素。

總結

ScrollViewReader 是 SwiftUI 框架中很好的新增功能。現在我們不再需要開發自己的解決方案,就可以輕鬆地指示任何滾動視圖滾動到特定位置。希望你喜歡這篇教學文章,並看到這個新元件的用處。如果想更深入學習 SwiftUI 框架,並了解其他技巧,可以閱讀我們《精通 SwiftUI》一書。

譯者簡介:Kelly Chan-AppCoda 編輯小姐。
原文How to Use ScrollViewReader to Perform Programmatic Scrolling

作者
Simon Ng
軟體工程師,AppCoda 創辦人。著有《iOS 17 App 程式設計實戰心法》、《iOS 17 App程式設計進階攻略》以及《精通SwiftUI》。曾任職於HSBC, FedEx等跨國企業,專責軟體開發、系統設計。2012年創立AppCoda技術部落格,定期發表iOS程式教學文章。現時專注發展AppCoda業務,致力於iOS程式教學、產品設計及開發。你可以到推特與我聯絡。
評論
更多來自 AppCoda 中文版
iOS 18 新API:使用 Navigation Transition 創建 Hero 動畫式過場
SwiftUI 框架

iOS 18 新API:使用 Navigation Transition 創建 Hero 動畫式過場

Apple 的工程師可能早已認識到,許多 iOS 開發者都希望能夠重現 App Store 應用程式中的優雅 Hero 動畫。由於從頭實現這種動畫通常需要耗費大量時間與精力,Apple 在 iOS 18 SDK 中納入了這項功能。 透過這次更新,你現在只需少量的程式碼就能在自己的應用程式中實現類似的動畫過渡效果。這項重大改進讓開發者能夠創造出更具視覺吸引力且流暢的過渡效果,
如何使用 Vision APIs 從圖像中辨識文字
AI

如何使用 Vision APIs 從圖像中辨識文字

Vision 框架長期以來一直包含文字識別功能。我們已經有詳細的教程,向你展示如何使用 Vision 框架掃描圖像並執行文字識別。之前,我們使用了 VNImageRequestHandler 和 VNRecognizeTextRequest 來從圖像中提取文字。 多年來,Vision 框架已經顯著演變。在 iOS 18 中,Vision
iOS 18更新:SwiftUI 新功能介紹
SwiftUI 框架

iOS 18更新:SwiftUI 新功能介紹

SwiftUI的技術不斷演進,每次更新都讓 iOS 應用程式開發變得更加便捷。隨著 iOS 18 Beta 的推出,SwiftUI 引入了多個令人興奮的新功能,使開發者僅需幾行程式碼即可實現出色的效果。 本教學文章旨在探索這個版本中的幾項主要改進,幫助你了解如何運用這些新功能。 浮動標籤列 (Floating Tab Bar)SwiftUI中的標籤視圖(Tab
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。