swiftui学习笔记

swiftui 为灰色切图添加颜色

/// 核心代码:
Image("setting_right_bar_icon")
.renderingMode(.template)
.foregroundColor(Color.yellow)

swiftui 修改图片大小

/*
 如果想自定义Image大小,可以添加frame
 clipped()相当于UIKit里的clipsToBounds,
 与aspectRatio(contentMode: .fill)搭配使用。
 
 注意:frame 要放在resizable后面,否则报错,
 如果需求裁剪,需要放在aspectRatio后面,
 clipped()前面,否则frame失效 */
Image("icon_person")
.resizable()
/// 自己尝试一下.fill和.fit
.aspectRatio(contentMode: .fill)
.frame(width: 20, height: 20)
.clipped() /// 裁减
.cornerRadius(10)

pod init || pod install || pod update 报错

gem install cocoapods --pre --user

swift网络请求封装框架

pod 'Moya', '~> 15.0'
# handyjson 处理数据

pod 'HandyJSON',    '5.0.3-beta'

swiftui网络图片修改大小

AsyncImage(url: .init(string:"https://picsum.photos/400/200" ))
{ img in
    img.resizable()
        .frame(maxWidth: imageReader.size.width,
               maxHeight: imageReader.size.height)
        .aspectRatio(contentMode: .fill)
} placeholder: {
    // 占位符,加载图片的显示
    ProgressView()
        .frame(maxWidth: .infinity,
               maxHeight: .infinity, alignment: .center)
}

swiftUI 设置颜色的不透明度 && hexString设置颜色

#opacity 介于01之间
Color.init(UIColor(hexString:"#EDD44E")).opacity(0.1)

swiftUI 使用overlay设置圆角

Button("注册"){}
  .frame(width: 250, height: 40)
  .font(.caption)
  .foregroundColor(hexColor(hex: 0x1D5EF3))
  //    通过overlay设置圆角的大小及边框颜色
  .overlay(RoundedRectangle(cornerRadius: 20, style: .continuous)
    .stroke(hexColor(hex: 0x1D5EF3), lineWidth: 1)
    )
  .padding(.top, 8)
  
  Text("注册")
    .font(.system(size: 18))
    .frame(width: 100, height: 38)
    .foregroundColor(fontColor)
    .overlay(RoundedRectangle(cornerRadius: 8)
        .stroke(fontColor, lineWidth: 2)
        )
    .padding(.leading,64)
    .padding(.top,16)
    .padding(.bottom,23)

swiftUI 设置阴影


#背景周边会展示阴影
VStack {
    Image("turtlerock")
    
    Image("turtlerock")
        .shadow(radius: 15)
}

#背景阴影效果偏移
VStack {
    Image("turtlerock")
    
    Image("turtlerock")
        .shadow(color: .green, radius: 5, x: 5, y: 5)
}

swiftui 横向滚动

    ScrollView(.horizontal, showsIndicators: false) {
                HStack {
                    ForEach(boxes, id: \.id) { box in
                        BoxView(box: box)
                    }
                }.frame(maxWidth: .infinity,
                           maxHeight: 92,alignment: .leading)
            }

swiftui path 折线图

# 参考学习链接 https://juejin.cn/post/7033199647501844494
# 先扩展path
extension Path {
    
    // 背景渐变
    static func lineBkChart(points:[Double], step:CGPoint) -> Path {
        var path = Path()
        if (points.count < 2){
            return path
        }
        guard let offset = points.min() else { return path }
        path.move(to: .zero)

        var p1 = CGPoint(x: 0, y: CGFloat(points[0]-offset)*step.y)
        for pointIndex in 1..<points.count {
            let p2 = CGPoint(x: step.x * CGFloat(pointIndex), y: step.y*CGFloat(points[pointIndex]-offset))
//            path.addLine(to: p2)
            
            
            // 贝塞尔曲线
//            let midPoint = CGPoint.midPointForPoints(p1: p1, p2: p2)
            let conPoint1: CGPoint = CGPoint.init(x: CGFloat(p1.x + p2.x) / 2.0, y: p1.y)
            let conPoint2: CGPoint = CGPoint.init(x: CGFloat(p1.x + p2.x) / 2.0, y: p2.y)
            path.addCurve(to:p2,control1: conPoint1,control2: conPoint2)
            p1 = p2
        }
        path.addLine(to: CGPoint(x: p1.x, y: 0))
        path.closeSubpath()
        return path
    }
    
    static func lineChart(points:[Double], step:CGPoint) -> Path {
        var path = Path()
        if (points.count < 2){
            return path
        }
        guard let offset = points.min() else { return path }
        var p1 = CGPoint(x: 0, y: CGFloat(points[0]-offset)*step.y)
        path.move(to: p1)
        for pointIndex in 1..<points.count {
            let p2 = CGPoint(x: step.x * CGFloat(pointIndex), y: step.y*CGFloat(points[pointIndex]-offset))
        
            // 贝塞尔曲线
            let conPoint1: CGPoint = CGPoint.init(x: CGFloat(p1.x + p2.x) / 2.0, y: p1.y)
            let conPoint2: CGPoint = CGPoint.init(x: CGFloat(p1.x + p2.x) / 2.0, y: p2.y)
            path.addCurve(to:p2,control1: conPoint1,control2: conPoint2)
            p1 = p2
        }
//        path.addLine(to: CGPoint(x: 0, y: step.y))
//        path.closeSubpath()
        return path
    }
    
    static func quadCurvedPathWithPoints(points:[Double], step:CGPoint, globalOffset: Double? = nil) -> Path {
        var path = Path()
        if (points.count < 2){
            return path
        }
        
        let offset = globalOffset ?? points.min()!
        var p1 = CGPoint(x: 0, y: CGFloat(points[0]-offset)*step.y)
        path.move(to: p1)
        for pointIndex in 1..<points.count {
            let p2 = CGPoint(x: step.x * CGFloat(pointIndex), y: step.y*CGFloat(points[pointIndex]-offset))
            let midPoint = CGPoint.midPointForPoints(p1: p1, p2: p2)
            path.addQuadCurve(to: midPoint, control: CGPoint.controlPointForPoints(p1: midPoint, p2: p1))
            path.addQuadCurve(to: p2, control: CGPoint.controlPointForPoints(p1: midPoint, p2: p2))
            p1 = p2
        }
        return path
    }
    
    
}

extension CGPoint {
    
    static func midPointForPoints(p1:CGPoint, p2:CGPoint) -> CGPoint {
        return CGPoint(x:(p1.x + p2.x) / 2,y: (p1.y + p2.y) / 2)
    }
    
    static func controlPointForPoints(p1:CGPoint, p2:CGPoint) -> CGPoint {
        var controlPoint = CGPoint.midPointForPoints(p1:p1, p2:p2)
        let diffY = abs(p2.y - controlPoint.y)
        
        if (p1.y < p2.y){
            controlPoint.y += diffY
        } else if (p1.y > p2.y) {
            controlPoint.y -= diffY
        }
        return controlPoint
    }
}

# 自动计算高度和宽度
var stepWidth: CGFloat {
        if data.count < 2 {
            return 0
        }
        return frame.size.width / CGFloat(data.count-1)
    }
    var stepHeight: CGFloat {
        var min: Double?
        var max: Double?
        let points = self.data
        if let minPoint = points.min(), let maxPoint = points.max(), minPoint != maxPoint {
            min = minPoint
            max = maxPoint
        }else {
            return 0
        }
        if let min = min, let max = max, min != max {
            if (min <= 0){
                return (frame.size.height-padding) / CGFloat(max - min)
            }else{
                return (frame.size.height-padding) / CGFloat(max - min)
            }
        }
        
        return 0
    }
    
    // 背景渐变
    var pathBk: Path {
        let points = self.data
        return Path.lineBkChart(points: points, step: CGPoint(x: stepWidth, y: stepHeight))
    }
    // k线
    var pathLine: Path {
        let points = self.data
        return Path.lineChart(points: points, step: CGPoint(x: stepWidth, y: stepHeight))
    }
    
    #画图
    public var body: some View {
        ZStack {
            self.pathBk
                .fill(LinearGradient(gradient: Gradient(colors: [topUp ? greenFontColor : redFontColor ,endColor]), startPoint: .bottom, endPoint: .top))
                   .rotationEffect(.degrees(180), anchor: .center)
                   .rotation3DEffect(.degrees(180), axis: (x: 0, y: 1, z: 0))
                   .drawingGroup()
            self.pathLine
                .stroke(style: StrokeStyle(lineWidth: 1, lineJoin: .round))
                .foregroundColor(topUp ? greenFontColor : redFontColor)
               .rotationEffect(.degrees(180), anchor: .center)
               .rotation3DEffect(.degrees(180), axis: (x: 0, y: 1, z: 0))
               .drawingGroup()
        }
        
         
    }

渐变器

# 线性渐变
LinearGradient(gradient: Gradient(colors: [.green ,.red]), startPoint: .bottom, endPoint: .top)

按给定的尺寸和锚点,对视图进行缩放

public func scaleEffect(_ scale: CGSize, anchor: UnitPoint = .center) -> some View

自己写的进度条

struct TearmProgressView:View {
    var value:CGFloat
    var total:CGFloat
    var gradient = LinearGradient(gradient: Gradient(colors: [Color.init(UIColor(hexString: "#FFC745")),Color.init(UIColor(hexString: "#FF6F6F"))]), startPoint: .leading, endPoint: .trailing)
    var body: some View {
        ZStack {
            
            RoundedRectangle(cornerRadius: 8)
                .foregroundColor(Color.init(UIColor(hexString: "#D8D8D8")))
                .frame(width: 139, height: 4)
            HStack(spacing: 0) {
                RoundedRectangle(cornerRadius: 8)
                    .fill(gradient)
                    .frame(width: 139 * (value / total), height: 4,alignment: .leading)
                
            }
            .frame(width: 139, height: 20,alignment: .leading)
        }
        
        
    }
}

swiftui 字重


字体粗细的值
black
比 heavy 厚的字体。

bold
比默认值更粗的字体。

heavy
比 bold 厚的字体。

light
比默认字体稍细的字体。

medium
比默认值稍厚的字体。

regular
默认字体粗细。

semibold
比medium稍厚的字体。

thin
比默认字体更细的字体。

ultralight
一种字体粗细,颜色比默认值更细更浅。

笔记
从最薄到最厚的font-weight值为
ultralight, thin, light, regular, medium, semibold, bold, heavy, 和black。

swiftui 各种形状函数

Capsule()//胶囊型:是一种特殊的圆角矩形,其圆角的半径等于变长的一半
Circle()//圆形
Ellipse()//椭圆
Rectangle()//长方形
RoundedRectangle(cornerRadius: 25.0)//圆角矩形
RoundedRectangle(cornerSize: CGSize(width: 25, height: 50))//椭圆角矩形

//遵循Shape协议就可以画一个三角形
struct Triangle: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()//路径        
        path.move(to: CGPoint(x: rect.midX, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.midX, y: rect.minY))        
        return path
    }
}

Triangle()
    .fill(Color.red)
    .frame(width: 300, height: 300)
    
// 或者
ShapeWithLabel(shape: Triangle(), label: "三角形")
    

matchGeometry 打点,据说是做动画的

内容超出省略模式

    Text("MMMMMMMMM")
    .truncationMode(.middle) // .head(省略头部),.middle( 省略中间),.tail(省略尾部)

swiftui 页面的生命周期管理

.onAppear{
// 打开页面的操作
            marketStore.getMarketList()
        }
.onDisappear {
// 离开页面的操作
    // 关闭socket链接
    marketStore.stop()
}

swiftui tabview + scrollview + scrollviewreader 处理界面滑动

# scrollviewreader 定位到scrollview 的index
tabview使用滑动样式
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.animation(.spring())
            

swift 跳出多重循环

forItem: for item in itemList {
    for index in item {
        break forItem
    }
}

swiftui 选择器 Menu的用法

Menu(content: {
                    Text("直播")
                    Text("发帖")
                }, label: {
                     // 这里放自定义的点击按钮
                    CommunityPostBtnView()
                            .padding(.trailing,12)
                            .padding([.bottom,.top],10)
                })

swiftui text

    VStack {
            HStack {
                
                Text("我是Label\n第二行")
                    // 横线
                    .strikethrough(true, color: Color.black)
                    // 下划线
                    .underline()
                    // 每行底部偏移..也可以作为另一种行间距使用..
                    .baselineOffset(50)
                    // 斜体
                    .italic()
                    // 字体大小
                    .font(.largeTitle)
                    // 粗体
                    .fontWeight(.bold)
                    // 字间距
                    .kerning(10)
                    // 行间距
                    .lineSpacing(10)
                    // 字体颜色
                    .foregroundColor(Color.white)
                    // 最大行数, 如不设置, 则表示无限行
                    .lineLimit(2)
                    // 内间距
                    .padding()
                    // 背景颜色
                    .background(Color.red)
                    // 圆角
                    .cornerRadius(30)
                    // 添加点击手势
                    .onTapGesture {
                        print("点击1")
                }
                    // 添加长按手势
                    .onLongPressGesture(minimumDuration: 2, maximumDistance: 4, pressing: { (result) in
                        print("\(result ? "开始按压" : "按压结束")")
                    }) {
                        print("触发长按")
                }
                    // 添加其他手势
                    .gesture(
                        
                        
                        // 比如这里添加一个拖动手势
                        DragGesture()
                            // 拖动改变了
                            .onChanged({ (value) in
                                print(value)
                            })
                            // 拖动结束
                            .onEnded({ (value) in
                                print(value)
                            })
                )
            }
                // 如果要设置文字的背景阴影, 一般还是要包裹起来
                .shadow(color: Color.red, radius: 20)
                .padding(.bottom, 50)
            
            Text("我文字有阴影")
                .font(.largeTitle)
                .shadow(color: Color.black, radius: 10)
            
        }

swiftui scrollView 上拉加载数据

#UT 链接:https://www.youtube.com/watch?v=3S0dwmBJQOE
ScrollView {
    foreach(data,id:\.self) { i in 
        
        if i == data.count -1 {
            showView(data, islast: true)
        } else {
            showView(data, islast: true)
        }
    }
}

showView {
    if islast {
        Text()
        .onAppear {
            loadData()
        }
    } else {
        Text()
    }
}
上次更新:
贡献者: liutian