本文主要讲述常见的View和Modifiers的认识和使用
主要内容:
- 常用View
- 常用Modifiers
SwiftUI通过View视图搭建界面,使用Modifiers修饰器来修饰视图。系统提供了大量的视图和修饰器,并且还可以让我们自定义修饰器。
既可以手动写,也可以直接拖出到代码区或者预览区。这三种方式的结果都是一样的。
示意图:
显示一行或多行的只读文本视图,可以类似于OC中的label
//1、Text
Text("我是一个Text,**Markdown语法加粗了**").foregroundColor(.red)
Label用户界面项的标准标签,包括图片和标题
//2、Label
VStack {
//用户界面项的标准标签,由带有标题的图标组成。
//labelStyle设置label样式
Label("Lightning", systemImage: "bolt.fill")
Label("Lightning", systemImage: "bolt.fill")
.labelStyle(.iconOnly)
Label("Lightning", systemImage: "bolt.fill")
.labelStyle(.titleOnly)
//自定义label样式
Label("Lightning", systemImage: "bolt.fill")
// .labelStyle(.makeBody(RedBorderedLabelStyle))
//多label统一样式
VStack {
Label("Rain", systemImage: "cloud.rain")
Label("Snow", systemImage: "snow")
Label("Sun", systemImage: "sun.max")
}
.labelStyle(.iconOnly)
//组合标签
Label {
Text("wenyi")
.font(.body)
.foregroundColor(.primary)
Text("ya")
.font(.subheadline)
.foregroundColor(.secondary)
} icon: {
Circle()
.fill(.orange)
.frame(width: 44, height: 44, alignment: .center)
.overlay(Text("圆")).foregroundColor(.white)
}
}
说明:
//Button,文字和响应
Button {
print("button点击响应")
} label: {
Text("我是按钮")
}
说明:
通过提供目标URL和标题来创建链接
//Link
Link(destination: URL(string:"https://www.baidu.com/")!) {
Text("Link")
}
Link("View Our Terms of Service",
destination: URL(string: "https://www.example.com/TOS.html")!)
//设置OpenURLAction
Link("Visit Our Site", destination: URL(string: "https://www.example.com")!)
.environment(\.openURL, OpenURLAction { url in
print("Open \(url)")
return .handled
})
说明:
//直接拿Assets中图片
Image("wy")
.resizable()
.aspectRatio(contentMode: .fit)
// UIImage.init(named: "wy.png")
//加载网络图片
// AsyncImage.
说明:
根据时间表更新的视图
//定义
struct TimelineView<Schedule, Content> where Schedule : TimelineSchedule
//TimelineView
TimelineView(.periodic(from: Date.now, by: 1.0)) {
context in
Text(context.date.description).font(.title)
}
说明:
绘制图形
//Canvas
Canvas { context, size in
context.stroke(Path(ellipseIn: CGRect(origin: .zero, size: size)),with: .color(.blue), lineWidth: 3)
}.frame(width: 100, height: 50, alignment: .center).border(.red,width: 2)
说明:
使用画布在SwiftUI视图中绘制丰富和动态的2D图形。画布将GraphicsContext传递给用于执行即时模式绘图操作的闭包。画布还传递一个CGSize值,您可以使用它来定制您绘制的内容。例如,你可以使用上下文的stroke(_:with:lineWidth:)命令来绘制一个Path实例:
显示可编辑文本界面的控件。相当于UITextView
//TextEditor
TextEditor(text:
.constant("Placeholder"))
.frame(width: 100, height: 30, alignment: .center)
说明:
文本输入框
//TextField,预览无法操作
TextField("首字母默认大写", text: $str).frame(width: 100, height: 56, alignment: .center)
.textInputAutocapitalization(.never)
//自动纠错
.disableAutocorrection(true)
// .border(.red, width: 1)
// .cornerRadius(20)
.overlay{
RoundedRectangle(cornerRadius: 20)
.stroke(.red, lineWidth: 10)
.padding(-10)
}
.onSubmit {
print("我点击了!")
}
...
.contentShape(Rectangle())//追加热区设置
.onTapGesture {
print("tap")
//热区
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
说明:
颜色选择器(UIKit没有)
@State var textColor = Color.red
//ColorPicker
//supportsOpacity是否设置透明度
ColorPicker("picker", selection: $textColor, supportsOpacity: false).font(.largeTitle).foregroundColor(textColor)
说明:
选择器
@State var selectedCity = city.xian
//Picker
Picker(selection: $selectedCity, label: Text("Picker").frame(width: 50, height: 10, alignment: .center)) {
Text("taiyuan").tag(city.taiyuan)
Text("xian").tag(city.xian)
Text("datong").tag(city.datong)
}.border(.orange)
Text("this city is : \(selectedCity.rawValue)")
说明:
//设置工具栏
NavigationView {
Text("Hello World!").navigationTitle("navigation")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("Edit") {}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button("back") {}
}
}
}
说明:
进度条视图
//ProgressView
// ProgressView(value: /*@START_MENU_TOKEN@*/0.5/*@END_MENU_TOKEN@*/)
ProgressView(value: progress, total: 10, label: {
Text("WY")
}, currentValueLabel: {
Text("start")
})
.progressViewStyle(.circular)
Button("加1") {
progress += 1
}
ProgressView().progressViewStyle(.linear)
}
说明:
滑动块
@State private var isEditing = false
Slider(
value: $speed,
in: 0...100,
step: 5
) {
Text("Speed")
} minimumValueLabel: {
Text("0")
} maximumValueLabel: {
Text("100")
} onEditingChanged: { editing in
isEditing = editing
}
Text("\(speed)")
.foregroundColor(isEditing ? .red : .blue)
说明:
切换按钮,相当于UISwitch
Toggle(isOn: $vibrateOnRing) {
Text("Vibrate on Ring")
}
Toggle("Vibrate on Ring", isOn: $vibrateOnRing)
当您希望用户在增加或减少值时进行粒度控制时,请使用Stepper控件
//Stepper
Stepper {
//左侧文本
Text("Value: \(value) Color: \(colors[value].description)")
} onIncrement: {//加操作
incrementStep()
} onDecrement: {//减操作
decrementStep()
}
.padding(5)
.background(colors[value])//设置颜色
//设置范围,且默认加减
Stepper(value: $value,
in: range,
step: step) {
Text("Current: \(value) in \(range.description) " +
"stepping by \(step)")
}
.padding(10)
图形渐变
代码:
//图形渐变
//角渐变
AngularGradient(gradient: Gradient(colors: [Color.red, Color.blue,.purple,.red]), center: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
//椭圆
EllipticalGradient(colors:/*@START_MENU_TOKEN@*/[Color.blue, Color.green]/*@END_MENU_TOKEN@*/, center: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/, startRadiusFraction: /*@START_MENU_TOKEN@*/0.0/*@END_MENU_TOKEN@*/, endRadiusFraction: /*@START_MENU_TOKEN@*/0.5/*@END_MENU_TOKEN@*/)
//线性
LinearGradient(gradient: /*@START_MENU_TOKEN@*/Gradient(colors: [Color.red, Color.blue])/*@END_MENU_TOKEN@*/, startPoint: /*@START_MENU_TOKEN@*/.leading/*@END_MENU_TOKEN@*/, endPoint: /*@START_MENU_TOKEN@*/.trailing/*@END_MENU_TOKEN@*/)
//辐射渐变
RadialGradient(gradient: /*@START_MENU_TOKEN@*/Gradient(colors: [Color.red, Color.blue])/*@END_MENU_TOKEN@*/, center: .bottomLeading, startRadius: 100, endRadius: 120)
//创建一个model项
struct ItemModel: Identifiable {
var id = UUID()
var name: String
var detailView: DetailView
}
//创建一个详情View
struct DetailView: View, Identifiable {
var id = UUID()
var detail: String
@State var text = ""
var body: some View {
VStack (alignment: .leading){
Text(detail).font(.largeTitle).foregroundColor(.gray).bold()
.searchable(text: $text){
Text("大同").searchCompletion("大同")
Text("太原").searchCompletion("太原")
Text("太原").searchCompletion("太原")
Text("太原").searchCompletion("太原")
Text("太原").searchCompletion("太原")
}
Spacer()
}
}
}
//定义一个数组
let datas: [ItemModel] = [
ItemModel(name: "太原", detailView: DetailView(detail: "山西省会")),
ItemModel(name: "西安", detailView: DetailView(detail: "陕西省会")),
ItemModel(name: "银川", detailView: DetailView(detail: "宁夏省会")),
ItemModel(name: "西宁", detailView: DetailView(detail: "青海省会")),
ItemModel(name: "呼和浩特", detailView: DetailView(detail: "内蒙省会")),
ItemModel(name: "郑州", detailView: DetailView(detail: "河南省会"))
]
//创建一个viewModel,提供了数组项
//并且还有一个filtedItems用来过滤每一项
class ViewModel: ObservableObject {
@Published var allItems: [ItemModel] = datas
@Published var searchedItem: String = ""
var filtedItems: [ItemModel] {
searchedItem.isEmpty ? allItems : allItems.filter({ str in
str.name.lowercased().contains(searchedItem.lowercased())
})
}
}
struct ContentView: View {
@ObservedObject var vm = ViewModel()
var body: some View {
NavigationView {
List {
ForEach(vm.filtedItems) {item in
NavigationLink(item.name, destination: item.detailView)
}
}
.navigationTitle(Text("搜索页面"))
.searchable(text: $vm.searchedItem, prompt: "输入您想要搜索的省会名称")
}
}
}
说明:
列表,就是OC中的TableView,是对UITableView的包装
List{
ForEach(todos, id:\.name){ (todo) in
Text("wenyi")
}
}
说明:
Tab的View,就是之前的tabbar
//TabView
TabView() {
Text("Tab Content 1").tabItem {
Image(systemName: "person")
Text("Tab Label 1")
}.tag(1).badge(Text("news"))
Text("Tab Content 2").tabItem {
Text("Tab Label 2")
}.tag(2)
}
说明:
设置动画效果:
TabView() {
Text("Tab Content 1").tabItem {
Image(systemName: "person")
Text("Tab Label 1")
}.tag(1).badge(Text("news"))
Text("Tab Content 2").tabItem {
Text("Tab Label 2")
}.tag(2)
}.tabViewStyle(.page).background(.orange)
说明:
用来跳转页面,通过其他APP进行跳转到当前页面
//OnOpenURL
struct ContentView: View {
@State var show = true
@State var tabSelection = 1
var body: some View {
TabView(selection: $tabSelection) {
Text("Tab Content 1").tabItem {
Image(systemName: "person")
Text("Tab Label 1")
}.tag(1).badge(Text("news"))
Text("Tab Content 2").tabItem {
Image(systemName: "person")
Text("Tab Label 2")
}.tag(2)
}.onOpenURL { url in
switch url.host {
case "tab1":
tabSelection = 1
case "tab2":
tabSelection = 2
default:
show.toggle()
}
}
.sheet(isPresented: $show) {
Text("URL参数错误")
}
}
}
设置scheme
结果:
说明:
禁止手势滑动关闭界面,必须加在按钮的后面
Button("Open Sheet") {
show.toggle()
}
.sheet(isPresented: $show) {
Button("Close") {
show.toggle()
}
.interactiveDismissDisabled()
}
说明:
文本菜单
struct ContentView: View {
@State var backgroundColor = Color.red
@State var isShow = true
var body: some View {
Text("Hello world~").bold().font(.largeTitle).foregroundColor(.white).background(backgroundColor)
.contextMenu (isShow ? ContextMenu{
Button("Red") {
backgroundColor = .red
}
Button("Green") {
backgroundColor = .green
}
Button("Blue") {
backgroundColor = .blue
}
Button {
backgroundColor = .yellow
} label: {
Label("yellow", systemImage: "scribble")
}
} : nil )
}
}
说明:
菜单视图,可以嵌套
Menu("Menu") {
Text("Item1")
Text("Item2")
Text("Item3")
Button("Red") {
backgroundColor = .red
}
Button("Green") {
backgroundColor = .green
}
Button("Blue"){
backgroundColor = .blue
}
Button("Yellow"){
backgroundColor = .yellow
}
Menu("Menu") {
Text("Item1")
Text("Item2")
Text("Item3")
Button("Red") {
backgroundColor = .red
}
Menu("Menu") {
Text("Item1")
Text("Item2")
Text("Item3")
Button("Red") {
backgroundColor = .red
}
}
}
}
说明:
表单视图
Form和List在使用和现象是没有区别的,底层也是一样的,都是对UItableView的封装,可以看做是分组的List
用于分组数据输入的控件的容器,如在设置或检查器中。
Form {
Text("item1")
Text("item2")
Text("item3")
}
说明:
ScrollViewReader { proxy in
Button("gotoBottom"){
proxy.scrollTo(90)
}
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .center, spacing: 10) {
ForEach(0..<100) {
Text("cell \($0)").font(.title)
}
.frame(maxWidth:.infinity)
}
}
}
说明:
//Alert
Button("show Alert") {
show.toggle()
}
.alert(isPresented: $show) {
Alert.init(title: Text("title"), message: Text("message"), dismissButton: .cancel())
}
Button("show Dialog") {
show.toggle()
}.confirmationDialog("dialog", isPresented: $show) {
Button("btn1") {}
Button("btn2") {}
Button("btn3") {}
}
}
说明: