本文主要内容

一.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)

SwiftUI技术探究之常用View&Modifiers(下)

2.2 椭圆突变Elliptical Gradient

EllipticalGradient(colors:[Color.blue, Color.green], center: .center, startRadiusFraction: 0.0, endRadiusFraction: 0.5)

SwiftUI技术探究之常用View&Modifiers(下)

2.3 线性突变Linear Gradient

LinearGradient(colors: [Color.red, Color.blue], startPoint: .leading, endPoint: .trailing)

SwiftUI技术探究之常用View&Modifiers(下)

2.4 放射突变Radial Gradient

RadialGradient(colors: [Color.red, Color.blue], center: .center, startRadius: 5, endRadius: 500)

SwiftUI技术探究之常用View&Modifiers(下)

三.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)

SwiftUI技术探究之常用View&Modifiers(下)

SwiftUI技术探究之常用View&Modifiers(下)

五.OnOpenURL

  • 1.配置工程的Info中URL Types,填写URL Schemes(比方Tonly)

SwiftUI技术探究之常用View&Modifiers(下)

  • 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并跳转到对应界面。

SwiftUI技术探究之常用View&Modifiers(下)

  • 当URL过错时,显现过错文案!

SwiftUI技术探究之常用View&Modifiers(下)

六.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)
 }

SwiftUI技术探究之常用View&Modifiers(下)

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))
}