如图,自定义一个菜单栏,要求点击菜单按钮和滚动翻页步调统一。
首先有个分类模型
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)
}
}
}
示意图:
先从左到右点击菜单栏中的按钮,然后在从右到左滑动内容进行翻页。