You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何调用其他struct/view内的函数?FSCalendar切换范围示例

问题原因

  • 你无法直接在父视图调用CalendarRepresentable的实例方法:SwiftUI的视图是值类型,你定义的结构只是视图描述,不是实际渲染的运行时实例,调用方法修改的只是结构副本的属性,不会生效。
  • 你在CalendarRepresentable中直接存储FSCalendar实例的写法错误:UIViewRepresentable的UIKit视图实例由makeUIView方法生成、SwiftUI框架管理,你自行存储的实例和屏幕上实际渲染的实例不是同一个,修改它的属性不会有任何效果。

解决方案

通过状态变量绑定的方式同步父子视图的日历范围状态,由状态驱动UI更新,无需直接调用子视图方法。

第一步:修改HomeVC代码

新增控制日历范围的状态变量,绑定到子视图,点击按钮直接修改状态:

struct HomeVC: View {
    private let navbarcolor = UINavigationBarAppearance()
    
    init() {
        navbarcolor.configureWithOpaqueBackground()
        navbarcolor.backgroundColor = .systemGreen
        navbarcolor.titleTextAttributes = [.foregroundColor: UIColor.white]
        navbarcolor.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
        UINavigationBar.appearance().standardAppearance = navbarcolor
        UINavigationBar.appearance().scrollEdgeAppearance = navbarcolor
    }
    
    @State private var selectedDate = Date()
    // 新增控制日历范围的状态变量
    @State private var calendarScope: FSCalendarScope = .week
    
    var body: some View {
        NavigationView{
            VStack{
                CalendarRepresentable(selectedDate: $selectedDate, scope: $calendarScope)
                    // 高度根据范围动态调整
                    .frame(height: calendarScope == .week ? 150 : 300)
                    .padding(.top, 15)
                
                Spacer()
           
                ListView()
            }
            .navigationBarTitle("Calendar")
            .toolbar {
                Button(action: {
                    // 直接修改状态即可触发UI更新
                    calendarScope = calendarScope == .month ? .week : .month
                }) {
                    Text("Toggle")
                }
            }
        }
    }
}

第二步:修改CalendarRepresentable代码

新增范围绑定,在updateUIView方法中同步状态到FSCalendar实例:

struct CalendarRepresentable: UIViewRepresentable{
    typealias UIViewType = FSCalendar
    @Binding var selectedDate: Date
    // 新增范围绑定属性
    @Binding var scope: FSCalendarScope
    
    func updateUIView(_ uiView: FSCalendar, context: Context) {
        // 监听scope状态变化,同步更新FSCalendar的显示范围,加动画更顺滑
        if uiView.scope != scope {
            uiView.setScope(scope, animated: true)
        }
    }
    
    func makeUIView(context: Context) -> FSCalendar {
        // 在makeUIView里创建FSCalendar实例,不要存在结构的存储属性里
        let calendar = FSCalendar()
        calendar.delegate = context.coordinator
        calendar.dataSource = context.coordinator
        calendar.allowsMultipleSelection = true
        calendar.scrollDirection = .vertical
        // 初始值用绑定的scope
        calendar.scope = scope
        
        calendar.appearance.headerTitleFont =  UIFont.systemFont(ofSize: 25, weight: UIFont.Weight.heavy)
        calendar.appearance.weekdayFont = .boldSystemFont(ofSize: 15)
        calendar.appearance.weekdayTextColor = .black
        calendar.appearance.selectionColor = .systemGreen
        calendar.appearance.todayColor = .systemGreen
        calendar.appearance.caseOptions = [.headerUsesUpperCase, .weekdayUsesUpperCase]
        calendar.appearance.headerTitleColor = .black
        
        return calendar
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, FSCalendarDelegate, FSCalendarDataSource {
        var parent: CalendarRepresentable
        var formatter = DateFormatter()
        
        init(_ parent: CalendarRepresentable) {
            self.parent = parent
        }

        func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
            return 0
        }
        
        func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
            formatter.dateFormat = "dd-MM-YYYY"
            print("Did select == \(formatter.string(from: date))")
        }
        
        func calendar(_ calendar: FSCalendar, didDeselect date: Date, at monthPosition: FSCalendarMonthPosition) {
            formatter.dateFormat = "dd-MM-YYYY"
            print("Did de-select == \(formatter.string(from: date))")
        }
    }
}

内容的提问来源于stack exchange,提问作者razvan2003

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 15:57:04