SwiftUI之日期控件、列表、自定义PickerView控件、本地通知

今天要说一下需求,我们需要自定义个像日期一样的PickerView,但是在SwiftUI上好像只有一个单列的,没有多列的控件,不过也可以借助UIPickerView来实现,另外我们还可以通过组合来实现这种控件。我们通过一个记录体重的Demo来实现。

首先我们来创建一个工程WeighApp,然后我们在ContentView.swift这个文件里添加一个体重的列表。如下:

var body: some View {
        NavigationView {
            List {
                ForEach(model.dataList) { (item: DataJson)  in
                    Button(action: { 
                        self.currentJson = item;
                        self.writeDown.toggle()
                    }) { 
                        DataItemView(json: item)
                        
                    }
                }.onDelete { (set) in
                    self.currentSet = set
                    if self.getCurrentJson() != nil {
                        self.isAlert.toggle()
                    }
                }.alert(isPresented: self.$isAlert) { () -> Alert in
                    let item = getCurrentJson()!
                   return Alert(title: Text("提示"), message: Text("是否删除【\(item.date)】记录"), primaryButton: .cancel(), secondaryButton: .default(Text("确定"), action: { 
                        self.model.dataList.removeAll { (remveItem) -> Bool in
                            remveItem.id == item.id
                        }
                    }))
                }
                
                
            }.navigationBarTitle(Text("体重记录"), displayMode: .inline).navigationBarItems(leading: Button(action: { 
                self.showSeting.toggle()
            }, label: {
                Text("设置")
            }), trailing: Button(action: { 
                self.writeDown.toggle()
            }, label: { 
                Text("记录")
            })).sheet(isPresented: $showSeting) { 
                SettingView { 
                    self.showSeting.toggle()
                }
            }
        }.sheet(isPresented: $writeDown) {
            DatePickerView { 
                (value: String) in
                self.writeDown.toggle()
                self.addDateItemToList(value: value);
                
            }
        }
    }

在这个列表里我们看到一个DatePickerView视图,这个就是我们自定义的一个Picker控件,使用的是SwiftUI控件实现的。来看看下面的代码:

 


struct DatePickerView: View {
    
    @State var intIndex = UserConfig.weightIndex
    @State var decimalIndex = 3
    
    @State var finishedBlock: ((_ value: String)->Void)?
    
    
    var body: some View {
        NavigationView {
            VStack(alignment: .center) {
                Text("当前体重:\(intIndex).\(decimalIndex)kg").padding().font(Font.system(size: 20)).foregroundColor(Color.rgbColor(r: 255, g: 147, b: 89))
                pickerItemsView
                Spacer()
                
            }.navigationBarTitle(Text("选择体重"), displayMode: .inline)
                .navigationBarItems(trailing: Button(action: { 
                    UserConfig.weightIndex = self.intIndex
                    self.finishedBlock?(self.intIndex.description + "." + self.decimalIndex.description)
                }, label: { 
                    Text("确定")
                }))
        }
    }
    

    
    var pickerItemsView: some View {
        
        GeometryReader { (geo: GeometryProxy) in
            HStack(alignment: .center, spacing: 0.0) {
                Picker("kg", selection: self.$intIndex) {
                    ForEach(0..<80) { (idx: Int) in
                        Text(idx.description).font(Font.system(size: 20))
                    }
                    }.pickerStyle(WheelPickerStyle()).frame(width: geo.size.width/2, height: geo.size.height/2 , alignment: .center).clipped().padding(0)
                
                Picker("", selection: self.$decimalIndex) {
                    ForEach(0..<10) { (idx: Int) in
                        Text(idx.description).font(Font.system(size: 20))
                    }
                    }.pickerStyle(WheelPickerStyle()).frame(width: geo.size.width/2, height: geo.size.height/2, alignment: .center).clipped()
                Spacer()
            }.offset(x: 4, y: -90)
        }
    }
}

在这里需要说明一下,由于目前Picker只支持单列的滑动,所以我们可以利用这个特性也可以创建多个单列的滚动视图。这样看起来就是多列的一个视图了。还有 一个是需要我们去设置通知的,也就是本地的重复提醒:


struct SettingView: View {
    
    @State var isOpen = UserConfig.isOpenNotifiy
    @State var date = Date()
    @State var dayIndex = UserConfig.dayIndex - 1
    @State var finishedBlock: (() -> Void)?
    
    var body: some View {
        NavigationView {
            List {
                Toggle(isOn: $isOpen) { 
                    Text("打开通知")
                }
                if isOpen {
                    dateOfDay
                    datePicker
                    
                }
                
            }.navigationBarTitle(Text("通知设置"), displayMode: .inline).navigationBarItems(trailing: Button(action: { 
                self.finishedBlock?()
            }, label: { 
                Text("确定")
            }))
        }.onDisappear { 
            UserConfig.isOpenNotifiy = self.isOpen
            if self.isOpen {
                UserConfig.dayIndex = self.dayIndex + 1;
                NotificationManger.addNotification()
            }else {
                NotificationManger.removeNotifiation()
            }
        }
    }
    
    var dateOfDay: some View {
        HStack {
            Text("重复提醒")
            Spacer()
            Text("每月\(dayIndex + 1)日20:00")
        }
    }
    
    var datePicker: some View {
        HStack {
            Picker("picker", selection: $dayIndex) {
                ForEach(1..<30) { (index: Int) in
                    Text(index.description)
                }
            }.labelsHidden()
        }
    }
}

这个是一个设置提醒的具体时间的,那么我们接下来看看,在本地通知下提醒的代码:


struct NotificationManger {
    
    
    static func addNotification()  {
        let content = UNMutableNotificationContent()
        content.badge = 1;
        content.title = "今天改称体重了哦"
        content.subtitle = ""
        if let first = UserModel.init().dataList.first {
            content.body = "上次称重时间:\(first.date)\n\(first.kgValue)";
        }else {
            content.body = "每次记录都会直接保存的哦";
        }
        content.sound = UNNotificationSound.default;
        
        var resultComponts = DateComponents();
        resultComponts.calendar = .init(identifier: .gregorian)
        resultComponts.hour = 20;
        resultComponts.minute = 0;
        resultComponts.second = 0;
        resultComponts.day = UserConfig.dayIndex;
        
        let trigger = UNCalendarNotificationTrigger(dateMatching: resultComponts, repeats: true);
        let request = UNNotificationRequest.init(identifier: "id", content: content, trigger: trigger)
        
        
        
        UNUserNotificationCenter.current().add(request) { (error) in
        }
        
        let open = UNNotificationAction(identifier: "open", title: "打开", options: .destructive);
        let catorgy = UNNotificationCategory(identifier: "openBack", actions: [open], intentIdentifiers: [], options: .customDismissAction);
        UNUserNotificationCenter.current().setNotificationCategories(Set([catorgy]))
        
    }
    static func removeNotifiation() {
        UNUserNotificationCenter.current().removeAllPendingNotificationRequests();
        UNUserNotificationCenter.current().removeAllDeliveredNotifications();
    }
 
}

 重复提醒使用UNCalendarNotificationTrigger,是按照日历的设置提醒的,每天提醒只需要设置时间即可,如果每周提醒需要设置时间和第几周提醒,每月提醒需要设置第几日和时间。

结语:对于这个练习可以说是一个很好地练习,我们可以多多做些简单的项目熟悉SwiftUI的数据绑定开发模式,我们以后一定可以事半功倍的。最后献上Demo猛戳这里链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值