Grid布局

 LazyVGrid & LazyHGrid布局都需要[GridItem]数组来控制约束

GridItem有3种约束类型 

public enum Size { 
    // 固定Item大小,根据数组数量,显示每行个数
    case fixed(CGFloat)

    // flexible: 根据数组数量,显示每行个数可以固定size可变size放到一行。缺点是如果放不下,就会超出屏幕
    case flexible(minimum: CGFloat = 10, maximum: CGFloat = .infinity)

    // 根据设置参数一行能放下多少个就放多少case adaptive(minimum: CGFloat, maximum: CGFloat = .infinity)
}

1.  fixed

固定Item大小,根据数组数量,显示每行个数

struct ContentView: View {
    // fixed: 固定Item大小,根据数组数量,显示每行个数
    var columns: [GridItem] = [GridItem(.fixed(80)),GridItem(.fixed(80)),GridItem(.fixed(80))]
     
    var body: some View { 
        LazyVGrid(columns: columns, spacing: 10) {
             ForEach((0...11), id: .self) {index in
                 Text("(index)")
                     .frame( minWidth: 50, maxWidth: .infinity)
                     .background(.teal)
                     .cornerRadius(5)
                     .shadow(radius: 5)
             }
         }.font(.largeTitle)
          .padding()
    } 
}

2. adaptive

根据设置参数一行能放下多少个就放多少个 

struct ContentView: View {
    // adaptive: 根据设置参数一行能放下多少个就放多少var columns: [GridItem] = [GridItem(.adaptive(minimum: 50, maximum: 80))]
     
    var body: some View { 
        LazyVGrid(columns: columns, spacing: 10) {
             ForEach((0...11), id: .self) {index in
                 Text("(index)")
                     .frame( minWidth: 50, maxWidth: .infinity)
                     .background(.teal)
                     .cornerRadius(5)
                     .shadow(radius: 5)
             }
         }.font(.largeTitle)
          .padding()
    } 
}

3. flexible

根据数组数量,显示每行个数。  可以固定size和可变size放到一行。缺点是如果放不下,就会超出屏幕

struct ContentView: View {
    // flexible: 根据数组数量,显示每行个数可以固定size和可变size放到一行。缺点是如果放不下,就会超出屏幕
    var columns: [GridItem] = [GridItem(.flexible(minimum: 150)), GridItem(), GridItem(), GridItem()]
     
    var body: some View { 
        LazyVGrid(columns: columns, spacing: 10) {
             ForEach((0...11), id: .self) {index in
                 Text("(index)")
                     .frame( minWidth: 50, maxWidth: .infinity)
                     .background(.teal)
                     .cornerRadius(5)
                     .shadow(radius: 5)
             }
         }.font(.largeTitle)
          .padding()
    } 
}

LazyVGrid滑动

如果想让LazyVGrid能滑动需要外层套上 ScrollView() { }
 

ScrollView() {
    LazyVGrid(columns: columns, spacing: 10) {
        ForEach((0...11), id: .self) {index in
            Text("(index)")
                .frame( minWidth: 50, maxWidth: .infinity)
                .background(.teal)
                .cornerRadius(5)
                .shadow(radius: 5)
        }
    }.font(.largeTitle)
        .padding()
}

LazyVGrid的特殊布局

 

在[GridItem]数组做约束的情况下,每行样式都是相同
做成这样有不同约束的行,我用的是修改6的minWidth,在原本7的位置添加一个Spacer()来占位。这样看上去效果达到了

struct ContentView: View {
    var columns: [GridItem] = [GridItem(.flexible(minimum: 0, maximum: .infinity)), GridItem(), GridItem()]
     
    var body: some View { 
        LazyVGrid(columns: columns, alignment: .leading, spacing: 20) {
            ForEach((0...10), id: .self) {index in
                if index == 6 {
                    Text("(index)").frame(minWidth: 260, maxWidth: .infinity)
                        .background(.teal)
                        .cornerRadius(5)
                        .shadow(radius: 5)
                    Spacer()
                } else {
                    Text("(index)")
                        .frame( minWidth: 50, maxWidth: .infinity)
                        .background(.teal)
                        .cornerRadius(5)
                        .shadow(radius: 5)
                }
            }
        }.font(.largeTitle)
    } 
}

LazyVGrid实际应用

蜂窝布局

1. 使用Shape绘制六边形 

2. 单行和双行之间我们要错落一下,使用.offset来改变itme.x的位置

3. Slider用来更改LazyVGrid的spacing

点击item动画提示

实际应用我们可能选择某个item, 相应的代码逻辑我们可以放到.onTapGesture中去

​​​​​​​

Demo参考地址: Impossible Grids with SwiftUI – The SwiftUI Lab

struct ContentView: View {
    let cols: Int = 6
    @State var spacing: CGFloat = 10
    @State var animationAmount = [Int:Bool]()
    let imgsize = CGSize(width: 150, height: 150)
    var hexagonWidth: CGFloat { (imgsize.width / 2) * cos(.pi / 6) * 2 }
    
    var body: some View {
        let gridItems = Array(repeating: GridItem(.fixed(hexagonWidth), spacing: spacing), count: cols)
        VStack {
            ScrollView(.vertical) {
                LazyVGrid(columns: gridItems, spacing: spacing) {
                    ForEach(0..<150) { idx in
                        VStack(spacing: 0) {
                            Image("image-(idx % 15)")
                                .resizable()
                                .frame(width: imgsize.width, height: imgsize.height)
                                .clipShape(PolygonShape(sides: 6).rotation(Angle.degrees(90)))
                                .rotation3DEffect(Angle(degrees: animationAmount[idx] ?? true ? 360 : 0), axis: (x: 0.0, y: 1.0, z: 0.0))
                                .offset(x: (idx / cols) % 2 == 0 ? 0 : hexagonWidth / 2 + (spacing/2))
                                .onTapGesture {
                                    withAnimation(.interpolatingSpring(stiffness: 30, damping: 3)){
                                        self.animationAmount[idx] = !(self.animationAmount[idx] ?? true)
                                    }
                                }
                        }
                        .frame(width: hexagonWidth, height: imgsize.height * 0.75)
                    }
                }
                .frame(width: (hexagonWidth + spacing) * CGFloat(cols-1))
            }
            
            Slider(value: $spacing, in: 0...10)
        }
    }
    
    func isEvenRow(_ idx: Int) -> Bool { (idx / cols) % 2 == 0 }
}

struct PolygonShape: Shape {
    var sides: Int
    
    func path(in rect: CGRect) -> Path {
        let h = Double(min(rect.size.width, rect.size.height)) / 2.0
        let c = CGPoint(x: rect.size.width / 2.0, y: rect.size.height / 2.0)
        var path = Path()
        
        for i in 0..<sides {
            let angle = (Double(i) * (360.0 / Double(sides))) * Double.pi / 180
            
            let pt = CGPoint(x: c.x + CGFloat(cos(angle) * h), y: c.y + CGFloat(sin(angle) * h))
            
            if i == 0 {
                path.move(to: pt) // move to first vertex
            } else {
                path.addLine(to: pt) // draw line to next vertex
            }
        }
        
        path.closeSubpath()
        
        return path
    }
}

原文地址:https://blog.csdn.net/u010130947/article/details/128629807

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_45600.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注