前提回忆

在上两章节中,咱们完结了想法笔记主页新建笔记页面的页面构建,以及两个页面之间的简略交互。独自从前端视点来看,静态项目已经建立结束,接下来咱们要进入到愈加深层次一点点的学习。

在本章中,咱们将完结持续完结想法笔记的新建一条笔记的交互。

新建笔记

咱们先来完结新建笔记的操作,在之前的章节里咱们创立了一个类NoteItem来作为Model数据用来遍历列表数据,而新建笔记的办法也很简略,咱们只需求在NoteItem数组插入一条数据,而且插入的数据信息是咱们标题输入框以及内容输入框输入的数据就行了。

首要需求在NewNoteView视图中,创立用于双向绑定的NoteItem类数组,如下代码所示:

@Binding var noteItems: [NoteItem]

由于运用@Binding进行双向绑定,在NewNoteView视图预览时需求加一个默认值,如下代码所示:

NewNoteView(title: "", content: "", showNewNoteView: .constant(true), noteItems:  .constant([]))

报错是由于咱们在ContentView主页视图中经过模态弹窗跳转到NewNoteView新建笔记视图,而NewNoteView刚刚运用@Binding绑定的参数在ContentView主页视图短少关联。

许多情况都是这样,只要运用了@Binding绑定了参数,就必须在其他与该页面关联的页面双向绑定,也是挺烦的。

咱们回到ContentView主页视图,做一下双向绑定,如下图所示:

新建笔记办法

新建笔记操作能够和创立View视图的办法一样,先创立一个办法,然后在需求的当地调用这个办法,新建笔记的办法如下代码所示:

// MARK: 新建笔记办法
func addNote(writeTime:String,title:String,content:String) {
    let note = NoteItem(writeTime: writeTime, title:title,content:content)
    noteItems.append(note)
}

上述代码中,咱们创立了一个新建笔记的办法addNote,传入三个String类型的参数:writeTime录入时刻、title标题、content内容。

然后将传入的参数的值赋予NoteItem模型类中,并赋值给note常量。

声明note常量是常用的编程办法,当代码太长的时分就会抽离出来赋值,后面再运用。

最终咱们noteItems数组运用append将note的内容插入到noteItems数组数组中。

运用addNote办法时,只需求在执行动作时调用而且赋值就行了。在NewNoteView新建笔记视图中,点击“完结”按钮时,创立将会创立一条新笔记,咱们在点击“完结”按钮时调用addNote办法。如下代码所示:

addNote(writeTime: "", title: title, content: content)

上述代码中,咱们在saveBtnView“完结按钮”视图点击时调用addNote办法,而且将3个参数赋值,但咱们看到writeTime参数是String字符串类型,咱们赋值了空值。

取得时刻办法

writeTime参数是录入时刻,咱们需求在新建笔记时需求取得当时体系的时刻,并存起来。这儿需求注意2点,一是时刻需求准确到“”,二是writeTime参数是String字符串类型,而时刻常常是Date类型,还有可能做格局转换。

咱们仍旧能够创立一个办法来取得当时的体系时刻,如下代码所示:

// MARK: 获取当时体系时刻
func getCurrentTime() -> String {
    let dateformatter = DateFormatter()
    dateformatter.dateFormat = "YYYY.MM.dd"
    return dateformatter.string(from: Date())
}

上述代码中,咱们创立一个取得当时时刻的办法getCurrentTime,取得时刻后返回 一个String类型的返回值。

运用DateFormatter格局化办法,时刻格局为“YYYY.MM.dd”,也便是XXXX年XX月XX日的展示格局,最终return当时时刻戳。

咱们将getCurrentTime办法赋予addNote添加笔记的办法中的writeTime参数,当咱们迫不及待地回到ContentView主页视图想尝试运用时,发现并没有完结新建笔记操作.

这是由于什么呢?

咱们看看原来NoteListView笔记列表视图的办法,发现这儿运用@State声明了NoteItem模型类数组,是的,这导致了在NewNoteView新建笔记视图的新建笔记参数没有能回传回来

是的,这儿埋了一个坑。

@Binding特点包装器

这儿科普下@State@Binding的用法,@State特点包装器常常用于声明变量的前缀,运用@State特点包装器声明的变量,能够存储当时参数的状况或许值,而@Binding特点包装器常常在其他页面反向绑定@State特点包装器声明的变量。

比如,在主页声明的翻开弹窗的参数showNewNoteView,在主页切换showNewNoteView状况用于翻开弹窗,因而需求存储其状况

而在新建笔记页面需求封闭弹窗,而敞开和封闭弹窗的参数在主页中,所以需求运用@Binding特点包装器进行两个页面之间的双向绑定。

所以运用@Binding声明的showNewNoteView参数在新建笔记切换其状况,在主页中@State声明绑定的同一个参数就能够实时监听更新其状况,就完结了封闭弹窗的交互。

好了,回归主题,咱们这儿需求修正的将NoteListView笔记列表视图的NoteItem模型类数组运用@Binding进行双向绑定,并在ContentView主页视图中进行绑定,如下代码所示:

@Binding var noteItems: [NoteItem]

运行预览作用如下图所示:

QQ20220920-211222-HD.gif

提示信息

新建笔记时,当“新建笔记”页面标题输入框为空,以及“内容输入框”为空时,点击“完结”按钮,应用会创立一条空白的笔记,如下图所示:

这不是咱们想要的结果。

新建笔记页面标题、内容输入框都必须输入内容,方可点击创立一条新笔记,当不满足此条件时,则需求提示用户相应的内容,告知用户需求填写和输入。

在移动端常见的办法是运用Toast冒泡提示,咱们能够运用ViewModifier协议创立一个Toast视图,首要创立一个新的Swift文件,命名为ToastView

然后录入下面的代码:

import SwiftUI
struct ToastViewModifier: ViewModifier {
    @Binding var present: Bool
    @Binding var message: String
    var alignment: Alignment = .center
    func body(content: Content) -> some View {
        ZStack {
            content
                .zIndex(0)
            VStack {
                Text(message)
                    .padding(Edge.Set.horizontal, 20)
                    .padding(Edge.Set.vertical, 10)
                    .multilineTextAlignment(.center)
                    .foregroundColor(.white)
                    .background(Color.black.opacity(0.7))
                    .cornerRadius(5)
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: alignment)
            .background(Color.gray.opacity(0.1))
            .opacity(present ? 1 : 0)
            .zIndex(1)
            .onChange(of: present) { value in
                if value {
                    // 推迟2秒消失
                    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                        present.toggle()
                    }
                }
            }
        }
    }
}
extension View {
    func toast(present: Binding<Bool>, message: Binding<String>, alignment: Alignment = .center) -> some View {
        modifier(ToastViewModifier(present: present, message: message, alignment: alignment))
    }
}

上述代码中,咱们完结了一个Toast冒泡提示的样式,具体说明见【Swift实用小册19:ExtenExtension扩展的运用】。

回到NewNoteView新建笔记视图,咱们先声明Toast需求的参数,如下代码所示:

@State var showToast = false
@State var showToastMessage: String = ""

上述代码中,showToast参数触发是否展示Toast,showToastMessage参数则显示Toast的内容。调用Toast的办法如下代码所示:

.toast(present: $showToast, message: $showToastMessage, alignment: .center)

回到逻辑部分,咱们需求判别输入的标题title、内容content是否为空,若为空,则展示相应的内容,咱们能够写一个办法判读输入内容是否为空,如下代码所示:

// MARK: 判别输入是否为空
func isNull(text: String) -> Bool {
    if text == "" {
        return true
    }
    return false
}

上述代码中,咱们创立了一个判别输入的文字是否为空的办法isNull,传入一个String类型的文字,经过判别是否为空,对应返回Bool

咱们在点击“完结”按钮时,调用判别办法,如下代码所示:

if isNull(text: title) {
	self.showToastMessage = "请输入标题"
	self.showToast = true
} else if isNull(text: content) {
	self.showToastMessage = "请输入内容"
	self.showToast = true
} else {
	addNote(writeTime: getCurrentTime(), title: title, content: content)
	self.showNewNoteView = false
}

本章项目预览

完结后,咱们回到ContentView主页,运行预览作用如下图所示:

QQ20220920-231325-HD.gif

本章小结

在本章中,咱们完结了新建笔记的办法,当然也传达了一个很重要的编程理念,也便是结构化编程

无论是View视图,仍是完结某种功能的办法,咱们编程的办法都是抽离出来独自构建。这样编程的好处是当咱们需求修正某块内容样式或许逻辑时,能够快速定位到相关的内容,而且尽量使得视图、办法松懈分离,变成一块一块的代码块,便于后期扩充

这也是我喜爱SwiftUI的当地,也是喜爱写代码的原因。

接下来的章节,咱们将持续完结交互逻辑部分,请保持等待吧~

版权声明

本文为稀土技能社区首发签约文章,14天内制止转载,14天后未获授权制止转载,侵权必究!