本文主要内容
一.Border & 拼写查看 & 主动大写
二.Gradient
三.searchable
四.badge & TabView
五.OnOpenURL
六.interactiveDismissDisab
七.animation
一.Border & 拼写查看 & 主动大写
1.1 Border
- 边框
TextField("首字母默许大写", text: $str).frame(width: 200, height: 56)
// 直接设置border和cornerRadius显现会有问题
// 处理:绘制圆形放到此控件上
.overlay {
RoundedRectangle(cornerRadius: 20)
.stroke(.red, lineWidth: 10)
.padding(-10)
}
1.2 拼写查看
- 主动纠错
TextField("首字母默许大写", text: $str).frame(width: 200, height: 56)
// 主动纠错:输入是什么便是什么,不进行智能纠错
.disableAutocorrection(true)
1.3 主动大写
- 句子首字母大写
- 单词首字母大写
- 每个字母都默许大写
- 不默许大写
TextField("首字母默许大写", text: $str).frame(width: 200, height: 56)
// sentences:每一句文字首字母大写
// words:每个独自首字母大写
// characters:每个字母大写
// never:不默许大写
.textInputAutocapitalization(.sentences)
二.Gradient
突变作用
2.1 角度突变Angular Gradient
AngularGradient(colors: [Color.red, Color.blue, Color.green, Color.pink, Color.white, Color.red], center: .center)
2.2 椭圆突变Elliptical Gradient
EllipticalGradient(colors:[Color.blue, Color.green], center: .center, startRadiusFraction: 0.0, endRadiusFraction: 0.5)
2.3 线性突变Linear Gradient
LinearGradient(colors: [Color.red, Color.blue], startPoint: .leading, endPoint: .trailing)
2.4 放射突变Radial Gradient
RadialGradient(colors: [Color.red, Color.blue], center: .center, startRadius: 5, endRadius: 500)
三.searchable
查找框
- .searchable(text: $test),必须调配NavigationView运用
- 能够增加历史记录
示例:查找筛选名字
struct DetailView: View, Identifiable {
var id = UUID()
var detail: String
@State var text = ""
var body: some View {
Text(detail).font(.largeTitle).foregroundColor(.gray).bold()
.searchable(text: $text) {
// 增加历史记录
Text("苹果").searchCompletion("apple")
Text("香蕉").searchCompletion("banana")
Text("梨").searchCompletion("pear")
}
Spacer()
}
}
struct ItemModel: Identifiable {
var id = UUID()
var name: String
var detailView: DetailView
}
let datas: [ItemModel] = [
ItemModel(name: "Hank", detailView: DetailView(detail: "Hank教师,拿手逆向和跨平台")),
ItemModel(name: "Lina", detailView: DetailView(detail: "最可爱的客服教师")),
ItemModel(name: "Cocci", detailView: DetailView(detail: "Cocci教师,拿手底层和塞班")),
ItemModel(name: "Cat", detailView: DetailView(detail: "Cat教师,非常有责任心的大汉")),
ItemModel(name: "Zions", detailView: DetailView(detail: "这是我")),
ItemModel(name: "Kody", detailView: DetailView(detail: "Kody教师,拿手Swift底层"))
]
class ViewModel: ObservableObject {
@Published var allItem: [ItemModel] = datas
@Published var searchedItem: String = ""
var filtedItem: [ItemModel] {
searchedItem.isEmpty ? allItem : allItem.filter({ str in
str.name.lowercased().contains(searchedItem.lowercased())
})
}
}
struct Searchable: View {
@ObservedObject var vm = ViewModel()
var body: some View {
NavigationView {
List {
ForEach(vm.filtedItem) { item in
NavigationLink(item.name, destination: item.detailView)
}
}
.navigationTitle(Text("查找页面"))
.searchable(text: $vm.searchedItem, prompt: "输入您想要查找的内容")
}
}
}
四.badge & TabView
4.1 badge
Text的badge
只支持List-Rows和Tabbars
- 只能设置简单的特点,如font、foregroundColor等,较杂乱的特点不起作用
List(0..<50) { i in
Text("Hello,SwiftUI!")
.badge(Text("badge").font(.subheadline).bold().foregroundColor(.orange))
}
4.2 TabView
-
底部栏
,相似UIKit中的TabBar 其中只能增加Text和Image
通过设置tabViewStyle特点为page,实现翻滚界面(轮播图作用)
TabView {
Text("The First Tab")
// 增加角标
.badge(10) // 方位1
.tabItem {
Image(systemName: "1.square.fill")
Text("First")
}.tag(1)
Text("Another Tab")
.tabItem {
Image(systemName: "2.square.fill")
Text("Second")
}.tag(2).badge(3) // 方位2
Text("The Last Tab")
// badge其中的Text无法修正特点
.badge(Text("News"))
.tabItem {
Image(systemName: "3.square.fill")
Text("Third")
}.tag(3)
}.tabViewStyle(.page).background(.orange) // 轮播图作用
.font(.headline)
五.OnOpenURL
- 1.配置工程的Info中URL Types,填写URL Schemes(比方Tonly)
- 2.代码如下:
@State var show = false
@State var tabSelection = 1
TabView {
Text("The First Tab")
// 增加角标
.badge(10) // 方位1
.tabItem {
Image(systemName: "1.square.fill")
Text("First")
}.tag(1)
Text("Another Tab")
.tabItem {
Image(systemName: "2.square.fill")
Text("Second")
}.tag(2).badge(3) // 方位2
}.onOpenURL { url in
switch url.host {
case "Tab1":
tabSelection = 1
case "Tab2":
tabSelection = 2
default:
show.toggle()
}
}
.sheet(isPresented: $show) {
Text("URL参数过错")
}
- 3.运行工程,打开浏览器,输入“Tonly://tab1”则能够拉起APP并跳转到对应界面。
- 当URL过错时,显现过错文案!
六.interactiveDismissDisab
- 禁止下滑关闭弹出界面
@State var show = false
Button("Open Sheet") {
show.toggle()
}
.sheet(isPresented: $show) {
Button("Close") {
show.toggle()
}.interactiveDismissDisabled()
}
- 场景:当时界面有作业还没做完就不小心关闭,当时界面使命已完成,需求关闭但是无法下滑关闭。
struct SetSheetDelegate: UIViewRepresentable {
let delegate: SheetDelegate
init(isDisable:Bool, attempToDismiss: Binding<UUID>) {
self.delegate = SheetDelegate(isDisable, attempToDismiss: attempToDismiss)
}
func makeUIView(context: Context) -> some UIView {
return UIView()
}
func updateUIView(_ uiView: UIViewType, context: Context) {
DispatchQueue.main.async {
uiView.parentViewController?.presentationController?.delegate = delegate
}
}
}
class SheetDelegate: NSObject, UIAdaptivePresentationControllerDelegate {
var isDisable: Bool
@Binding var attempToDismiss: UUID
init(_ isDisable: Bool, attempToDismiss: Binding<UUID> = .constant(UUID())) {
self.isDisable = isDisable
_attempToDismiss = attempToDismiss
}
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
!isDisable
}
func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
attempToDismiss = UUID()
}
}
extension View {
func interactiveDismissDisabled(_ isDisable: Bool, attempToDismiss: Binding<UUID>) -> some View {
background(SetSheetDelegate(isDisable: isDisable, attempToDismiss: attempToDismiss))
}
}
extension UIView {
var parentViewController: UIViewController? {
var parentResponder: UIResponder? = self.next
while parentResponder != nil {
if let viewController = parentResponder as? UIViewController {
return viewController
}
parentResponder = parentResponder?.next
}
return nil
}
}
struct ContentView: View {
@State var sheet = false
@State var showingAlert = false
@State var disable = true
@State var attempToDismiss = UUID()
var body: some View {
VStack {
Button("去干大事") {
sheet.toggle()
}.font(.title)
}.frame(maxWidth: .infinity, maxHeight: .infinity).background(.yellow)
.sheet(isPresented: $sheet) {
VStack {
Button(action: {
disable.toggle()
}, label: {
VStack {
Text("页面事件完成了?\n(数据上传、信息保存等)").padding(.bottom, 40)
Text("\(disable ? "没完成" : "完成了")").bold().foregroundColor(disable ? .red : .green)
}
}).font(.title)
.interactiveDismissDisabled(disable, attempToDismiss: $attempToDismiss)
.alert(isPresented: $showingAlert) {
Alert(title: Text("温馨提示"), message: Text("您还有事件没完成,是否丢掉?"), primaryButton: .default(Text("继续干")), secondaryButton: .destructive(Text("丢掉"), action: {
sheet.toggle()
}))
}
}.frame(maxWidth: .infinity, maxHeight: .infinity).background(.gray.opacity(0.3))
.onChange(of: attempToDismiss) { _ in
print("try to dismiss sheet")
showingAlert.toggle()
}
}
}
}
七.animation
山人动画
7.1 animation润饰View
相似心跳动画作用
@State var scaleAmount: CGFloat = 1
Button("Animation") {
scaleAmount += scaleAmount<=1 ? 1 : -1
}
.font(.title).padding().background(.orange).cornerRadius(20)
// 心跳动画
.scaleEffect(scaleAmount).animation(Animation.easeInOut(duration: 3).delay(1).repeatForever(), value: scaleAmount)
凸出内容的动画作用
@State var scaleAmount: CGFloat = 1
Button("Animation") {
scaleAmount += scaleAmount<=1 ? 1 : -1
}
.font(.title).padding().background(.orange).cornerRadius(20)
.overlay {
RoundedRectangle(cornerRadius: 20)
.stroke(Color.red)
.scaleEffect(scaleAmount)
// 透明度改变
.opacity(Double(2 - scaleAmount))
.animation(Animation.easeOut(duration: 1).repeatForever(autoreverses: false), value: scaleAmount)
}
7.2 animation润饰变量
- 用到此变量的View都会产生动画
@State var scaleAmount: CGFloat = 1
VStack {
Button("Animation") {
scaleAmount += scaleAmount<=1 ? 1 : -1
}.font(.title).padding().background(.orange).cornerRadius(20).scaleEffect(scaleAmount)
Stepper("Stepper", value: $scaleAmount.animation(
Animation.easeOut(duration: 1)
.repeatCount(3, autoreverses: true)
), in: 1...10)
Button("Animation") {
}.rotationEffect(.degrees(30 * scaleAmount))
}