1. ScrollViewReader 定位滚动视图位置
1.1 实现
/// 定位滚动视图
struct ScrollViewReaderBootcamp: View {
@State var scrollToIndex: Int = 0
@State var textFiledText: String = ""
var body: some View {
VStack {
TextField("Enter a # here...", text: $textFiledText)
.padding(.horizontal)
.frame(height: 55)
.border(Color.gray)
.padding(.horizontal)
.keyboardType(.numberPad)
Button("Scroll now") {
// 添加动画
if let index = Int(textFiledText){
scrollToIndex = index
}
}
ScrollView {
ScrollViewReader { proxy in
/// 循环
ForEach(0..<50) { index in
Text("This is item #\(index)")
.font(.headline)
.frame(height: 200)
.frame(maxWidth: .infinity)
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 10)
.padding()
.id(index)
}
.onChange(of: scrollToIndex) { value in
withAnimation(.spring()){
// anchor 锚点 .top/.center
proxy.scrollTo(value, anchor: .top)
}
}
}
}
}
}
}
1.2 效果图:
2. GeometryReader 几何布局获取视图更新参数
2.1 实现
/// 几何布局
struct GeometryReaderBootcamp: View {
var body: some View {
//geometryReader1
geometryReader2
}
/// 获取百分比
func getPercentage(geometry: GeometryProxy) -> Double{
// 最大距离
let maxDistance = UIScreen.main.bounds.size.width / 2
print("maxDistance: \(maxDistance)")
// 当前 X 点 .global: 全局坐标的位置
let currentX = geometry.frame(in: .global).midX
return Double(1 - (currentX / maxDistance))
}
/// 示例二
var geometryReader2: some View{
ScrollView(.horizontal, showsIndicators: false) {
HStack{
ForEach(0..<20) { index in
GeometryReader { geometry in
RoundedRectangle(cornerRadius: 20)
.rotation3DEffect(
Angle(degrees: getPercentage(geometry: geometry) * 40),
axis: (x: 0.0, y: 1.0, z: 0.0))
}
.frame(width: 300, height: 250)
.padding()
}
}
}
}
/// 示例一
var geometryReader1: some View{
// 几何阅读器 解决横竖屏时,更新屏幕的宽度
GeometryReader { geometry in
HStack(spacing: 0) {
Rectangle().fill(Color.red)
//UIScreen.main.bounds.width
.frame(width: geometry.size.width * 0.66666)
Rectangle().fill(Color.blue)
}
.ignoresSafeArea()
}
}
}
2.2 效果图:
3. MultipleSheets 多个工作表单视图使用
3.1 实现
// 模型
struct RandomModel: Identifiable{
var id = UUID().uuidString
let title: String
}
// 1 - use a binding
// 2 - use multiple .sheets
// 3 - use $item
/// 多个工作表单视图传递 Model
struct MultipleSheetsBootcamp: View {
//@State var selectedModel: RandomModel = RandomModel(title: "Starting Title")
@State var selectedModel: RandomModel? = nil
@State var showSheet:Bool = false
@State var showSheet2: Bool = false
var body: some View {
//useBinding
//useMultipleSheets
useItem
}
/// 方式三 使用 Item
private var useItem: some View{
ScrollView {
VStack(spacing: 20){
ForEach(0..<50) { index in
Button(action: {
selectedModel = RandomModel(title: "\(index)")
}, label: {
Text("Button \(index)")
.frame(height: 150)
.frame(maxWidth: .infinity)
.background(Color.white.cornerRadius(10))
.padding(.horizontal)
.shadow(radius: 10)
.padding(.horizontal)
})
}
}
.sheet(item: $selectedModel) { model in
NextScreen(selectedModel: model)
}
}
}
// 方式二 使用多个表单视图
private var useMultipleSheets: some View{
VStack(spacing: 20){
Button("Button 1") {
showSheet.toggle()
}
.sheet(isPresented: $showSheet) {
NextScreen(selectedModel: RandomModel(title: "One1"))
}
Button("Button 2") {
showSheet2.toggle()
}
.sheet(isPresented: $showSheet2) {
NextScreen(selectedModel: RandomModel(title: "Two2"))
}
}
}
// 方式一 使用 @Binding
private var useBinding: some View{
VStack(spacing: 20){
Button("Button 1") {
selectedModel = RandomModel(title: "One")
showSheet.toggle()
}
Button("Button 2") {
selectedModel = RandomModel(title: "Two")
showSheet.toggle()
}
}
.sheet(isPresented: $showSheet) {
//NextScreen(selectedModel: $selectedModel)
}
}
}
// 下一个视图
struct NextScreen: View{
// 使用 Binding 简单修复传递值问题
// @Binding var selectedModel: RandomModel
@State var selectedModel: RandomModel
init(selectedModel: RandomModel) {
self.selectedModel = selectedModel
print(selectedModel.title)
}
var body: some View{
Text("\(selectedModel.title)")
.font(.largeTitle)
}
}
3.2 效果图:
4. Mask 制作五星评价视图
4.1 实现
// 五星评价制作遮盖修改器/蒙版组件
struct MaskBootcamp: View {
@State var rating: Int = 2
var body: some View {
ZStack{
satrtView
.overlay(overlayView.mask(satrtView))
}
}
// 覆盖 View
private var overlayView: some View{
// 使用几何读取器 获取宽度
GeometryReader{ geometryProxy in
ZStack(alignment: .leading) {
Rectangle()
//.foregroundColor(.yellow)
.fill(LinearGradient(gradient: Gradient(colors: [Color.red, Color.blue]), startPoint: .leading, endPoint: .trailing))
.frame(width: CGFloat(rating) / 5 * geometryProxy.size.width)
}
}
// 用户无法点击覆盖层/删除用户点击能力
.allowsHitTesting(false)
}
// 开始的View
private var satrtView : some View{
HStack{
ForEach(1 ..< 6) { index in
Image(systemName: "star.fill")
.font(.largeTitle)
.foregroundColor(Color.gray)
.onTapGesture {
withAnimation(.easeInOut){
rating = index
}
}
}
}
}
}