如图,自定义一个菜单栏,要求点击菜单按钮和滚动翻页步调统一。
首先有个分类模型
import Foundation struct CategoryModel: Hashable { var categoryID: Int = 0 var categoryName: String = "" }
基础实现代码如下,点击菜单和滚动页面进行翻页都能正常工作,见示意图。
import SwiftUI struct FlashcardView: View { @Environment(.presentationMode) var presentationMode @State private var listArr: [CategoryExModel] = [] @State private var selectedTab: Int = 0 var body: some View { VStack { // 自定义的水平滚动菜单 ScrollView(.horizontal, showsIndicators: false) { LazyHStack(spacing: 16) { ForEach(0..<listArr.count, id: .self) { index in Button(action: { withAnimation { selectedTab = index } }) { ZStack { if selectedTab == index { Image("icon-prectice-menu-bg") .frame(width: 16, height: 16) .offset(x: 10, y: 5) // 向下偏移5像素 } Text(listArr[index].categoryName) .frame(minWidth: 40, minHeight: 44) .font(selectedTab == index ? Font.medium(17) : Font.regular(17)) .foregroundColor(selectedTab == index ? Color.textAux33 : Color.textAux66) .padding(.horizontal, 8) } } .contentShape(Rectangle()) .cornerRadius(10) } } .frame(height: 44) .padding(.horizontal) } // 页面内容 TabView(selection: $selectedTab) { ForEach(0..<listArr.count, id: .self) { index in FlashcardContentView(categoryItem: listArr[index]) .tag(index) } } .tabViewStyle(.page(indexDisplayMode: .never)) // 隐藏系统的页码指示器 } .themeBackground() .navigationBarHidden(true) // 隐藏顶部的导航栏 .navigationBarBackButtonHidden(true) // 隐藏返回按钮 .edgesIgnoringSafeArea(.all) .onAppear { requestCategoryList() } } private func goBack() { presentationMode.wrappedValue.dismiss() } } extension FlashcardView { /// 获取二级分类 private func requestCategoryList() { DispatchQueue.global().async { QuestionDatabase.getDatabase().executeInDatabase { database in let categoryArr = database.loadSecondCategories() DispatchQueue.main.async { listArr = categoryArr } } } } }
示意图:
先从左到右点击菜单栏中的按钮,然后在从右到左滑动内容进行翻页。
上面的效果比较差,下面进一步优化,为菜单栏选中按钮添加跟随效果。
只需使用ScrollViewReader包裹ScrollView,然后在ScrollView添加onChange中指定元素居中。
// 使用 ScrollViewReader 包裹 ScrollView ScrollViewReader { proxy in ScrollView(.horizontal, showsIndicators: false) { 代码不变 } .onChange(of: selectedTab) { num in // 当 selectedTab 改变时,滚动到指定的元素让它居中 withAnimation { proxy.scrollTo(selectedTab, anchor: .center) } } }
示意图:
先从左到右点击菜单栏中的按钮,然后在从右到左滑动内容进行翻页。