SwiftUI学习笔记

1,451 阅读9分钟

前言

三天时间学习一波IOS,应该能写出个页面....吧,本文可能时不时出现帅气的脸胖....请略过


提示:以下是本篇文章正文内容,下面案例可供参考

一、如何新建SwiftUI项目。

1.安装Xcode->新建项目:

   iOS->App->Next

在这里插入图片描述    选择interface为SwiftUI然后Next创建完成

在这里插入图片描述  左边就是我们需要学习的SwiftUI,右边点击Resume一会儿就出现界面了

在这里插入图片描述 在这里插入图片描述 我靠..kotlin?!,Flutter?!!,compose?!!!........平复一下心情毕竟第一次玩。

Text常用属性

属性意义
font设置文本默认字体
fontWeight设置字体粗细
foregroundColor设置文本前景色[字体颜色]
multilineTextAlignment设置多行文本的对其方式
padding设置文本距离内容的距离
frame设置文本所在矩形框的大小
blur设置文本模糊度
border设置文本矩形框边框的细线颜色
clipShape裁剪文本所在的画布样式
import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("hello wold")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

二、SwiftUI

SwiftUI is a modern way to declare user interfaces for any Apple platform. Create beautiful, dynamic apps faster than ever before. 这么牛🍺么,还算惊讶毕竟Flutter支持6端。

1.SwiftUI-Text

Text字体大小最小是.font(.thin)。字体不能再小了...姿势不对?...瞬间打脸拿去用吧font(.system(size:111))。[Android和Flutter里面TextView]

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("helloWold")
        .font(.title)//字体大小...字体大小都要规定死么【thin最小了么】
        .fontWeight(.bold)//字体样式
        .foregroundColor(Color.green)//字体颜色
        .multilineTextAlignment(.center)//文字多行对其方式
        .padding(11.0)//距离内容的距离
        .frame(width: 333.0, height: 222.0)//宽和高
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

在这里插入图片描述

这里提一下:Flutter和Compose写习惯了所以觉得手写代码比较方便。当然可以用inspector进行属性的设置。如果属性不熟悉。按住command鼠标左键点击试图中显示的文本选择Show SwiftUI inspector或者在代码界面ctrl+option+触摸板按下。其他View同样.不再提示。

在这里插入图片描述

2.SwiftUI-VStack&HStack&ZStack

垂直排列布局HStack 和 水平排列布局行VStack。[Android里面LineaLayout(v,h)和Flutter里面Row和Colum]

VStack:手写或者Xcode右上角点击+拖动到代码里边即可。

为什么不能像Flutter里面一次性设置padding呢?是我使用有问题么,不吝赐教.flutter里面 padding:EdgeInsets.only(left:10,right:111,top:100,bottom:10)即可,但是SwiftUI里面笔记尴尬。需要多次设置如下


import SwiftUI

struct ContentView: View {
    var body: some View {
        //列
        VStack(alignment:.leading) {
            Text("Study VStack")
            .font(.title)
            
            Text("study VStack[Flutter,Android,H5]")
           .font(.subheadline)
        }.padding([.top, .trailing], 111).padding(.bottom,30.0)
        /**这里一次性设置只能设置距孩子同样的距离。所以想设
        置Flutter里面的(left:10,right:111,top:100,bottom:10)
        需要.padding(.left,10.0).padding(.trailing,111).padding(.top,100).padding(.bottom,10)
        **/
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

在这里插入图片描述

HStack:手写或者Xcode右上角点击+拖动到代码里边即可。
import SwiftUI

struct ContentView: View {
    var body: some View {
        //行
          HStack(alignment:.lastTextBaseline){
            Text("Study HStack")
                           .font(.title)
            Text("水平列")
                           .font(.subheadline)
            Text("结束").font(.footnote)
        }.padding(.all,10).frame(width:333).foregroundColor(.blue)
        
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

在这里插入图片描述

ZStack:手写或者Xcode右上角点击+拖动到代码里边即可。

相对布局Flutter里面Stack,Android里面RelatedLayout

import SwiftUI

struct ContentView: View {
    var body: some View {
     ZStack(alignment: Alignment(horizontal: .trailing, vertical: .top)){
            Text("hello").font(.title).frame(width:100,height:50).foregroundColor(.blue)
            Text("world").font(.footnote).foregroundColor(.red)
        }
        .padding([.top, .trailing], 111.0)
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

在这里插入图片描述

3.Image:同上可手写可拖动。后面不再提示。

import SwiftUI

struct CircleImage: View {
    var body: some View {
    Image("laopo").resizable().frame(minWidth: 0, idealWidth:  100, maxWidth: 300, minHeight: 0, idealHeight: 100, maxHeight:300, alignment:.center)}
}

struct CircleImage_Previews: PreviewProvider {
    static var previews: some View {
        CircleImage()
    }
}

在这里插入图片描述

阴影,边线限制大小等..帅气的脸请忽略!
import SwiftUI

struct CircleImage: View {
    var body: some View {
        
        Image("laopo").resizable()
        .clipShape(Circle())
        .overlay(Circle()
        .stroke(Color.white,lineWidth: 8), alignment:.center)
        .shadow(color:Color.orange,radius: 44)
        .frame(width: 344, height: 344, alignment: .center)
    
}

struct CircleImage_Previews: PreviewProvider {
    static var previews: some View {
        CircleImage()
    }
}
    
}

在这里插入图片描述

4.MKMapView:地图组建

import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {
    func makeUIView(context: Context) -> MKMapView {
           MKMapView(frame: .zero)
        }
    func updateUIView(_ uiView: MKMapView, context: Context) {
              let coordinate = CLLocationCoordinate2D(latitude: 34.011286, longitude:116.166868)
             let span = MKCoordinateSpan(latitudeDelta: 2.0,longitudeDelta: 2.0)
             let region = MKCoordinateRegion(center: coordinate, span: span)
             uiView.setRegion(region, animated: true)
    }
}

struct MapView_Previews: PreviewProvider {
    static var previews: some View {
        MapView()
    }
}

在这里插入图片描述 学任何前端移动端都一样。学完行,列,文字,图片就可以随意的造娃娃了。我已经迫不及待看B站。写个Item玩玩

三、B站列表练习。

在这里插入图片描述

任何事做之前都最好勾勒出框架。后面会相对顺利。当然一个布局构建不一定相同,最优最好。

VStack{//item容器
  ZStack[//顶部图片部分
     Image()
     HStack{
          HStack{
                Image()
               TextView()
          }
          HStack{
               Image()
               TextView()
               }
          HStack{
              Image()
              TextView()
          }
     }
  }
  TextView()//中间文字部分
  HStack{//底部点赞人数和操作按钮。
        TextView()
        Image()
        }
}

在这里插入图片描述

开始写代码....等等尼🐎这图片有圆角...上面学了clipShape搞圆。但是这个....我匆忙之下一顿疯狂操作...炸了!没有。以后来个⭐️,椭圆图,三角形....图片咋么办。由于职场cv技术操作熟练,时而久之也知道path,canvas,clip等裁剪。当然了裁剪是一个无比强大的东西,只要你画的好图片就可以裁剪多美。后面咋们会讲到自定义布局如下,这里我们实现图片裁剪即可。如下我自己的画画水平自觉好【别笑:大宝🔪都绘制出来了】。

在这里插入图片描述

在这里插入图片描述

废了大半天老费劲了没啥🐤8⃣️用,不废话来个能用的吧。你们也研究研究SwiftUI的绘制。幸好对于android和Flutter绘制相当了解。没错我们可以找到clipShape是它就是它点进去看看。


    /// Sets a clipping shape for this view.
    ///
    /// Use `clipShape(_:style:)` to clip the view to the provided shape. By
    /// applying a clipping shape to a view, you preserve the parts of the view
    /// covered by the shape, while eliminating other parts of the view. The
    /// clipping shape itself isn't visible.
    ///
    /// For example, this code applies a circular clipping shape to a `Text`
    /// view:
    ///
    ///     Text("Clipped text in a circle")
    ///         .frame(width: 175, height: 100)
    ///         .foregroundColor(Color.white)
    ///         .background(Color.black)
    ///         .clipShape(Circle())
    ///
    /// The resulting view shows only the portion of the text that lies within
    /// the bounds of the circle.
    ///
    /// ![A screenshot of text clipped to the shape of a
    /// circle.](SwiftUI-View-clipShape.png)
    ///
    /// - Parameters:
    ///   - shape: The clipping shape to use for this view. The `shape` fills
    ///     the view's frame, while maintaining its aspect ratio.
    ///   - style: The fill style to use when rasterizing `shape`.
    ///
    /// - Returns: A view that clips this view to `shape`, using `style` to
    ///   define the shape's rasterization.
    @inlinable public func clipShape<S>(_ shape: S, style: FillStyle = FillStyle()) -> some View where S : Shape

点进去一看解释的很明白还配有案例...等等我的翻译工具呢[阴雨不好的请保持安静]接下来一顿操作好像搞明白了干啥用的。“提供一个图形裁剪,裁剪掉形状之外的部分”。至于clipShape《S》(_shape: S这里S点不动就不说了。我Java,kt,Dart用惯了,是我的姿势不对么,不吝赐教。我只是想看看这个S具体是个啥玩意至少能让我实例化它。度娘在手....简单。实现Shape即可。没认真阅读源码。

struct RoundedCorner: Shape {
     func path(in rect: CGRect) -> Path {
        return Path()
    } 
}

我们看到实现Shape可以看到重写了path方法.....这个和android以及Flutter不像呀。没画布?rect:CGRect可能就是吧。点进去看了看Shape=按照已有矩形区域进行2维路径绘制来进行裁剪。

/// A 2D shape that you can use when drawing a view.
///
/// Shapes without an explicit fill or stroke get a default fill based on the
/// foreground color.
///
/// You can define shapes in relation to an implicit frame of reference, such as
/// the natural size of the view that contains it. Alternatively, you can define
/// shapes in terms of absolute coordinates.
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol Shape : Animatable, View {

    /// Describes this shape as a path within a rectangular frame of reference.
    ///
    /// - Parameter rect: The frame of reference for describing this shape.
    ///
    /// - Returns: A path that describes this shape.
    func path(in rect: CGRect) -> Path
}

最后找到了UIBezierPath绘制贝赛尔曲线。这个太不一样了吧和其他端。按照字面意思应该是以rect为矩形区域,corners[四角]为基准点,到延长线做切线进行绘制。

    //      这个是白塞尔曲线
    let path = UIBezierPath(roundedRect: rect, byRoundingCorners:corners, cornerRadii: CGSize(width:cornerRaduiWidth, height:cornerRaduiHeight))
        return Path(path.cgPath)
    }

最后实现效果 在这里插入图片描述


Image("iimage")
.resizable()
.frame(width:150, height: 125, alignment:.center )
.clipShape(RoundedCorner(corners:[UIRectCorner.topLeft], cornerRaduiWidth:22))
.shadow(color:.black , radius:10 , x:0.0 , y:0.0 )
.padding(EdgeInsets.init(top: 0, leading: 0, bottom: 11, trailing: 1))

Image("iimage")
.resizable()
.frame(width:150, height: 125, alignment:.center )
.clipShape(RoundedCorner(corners:[UIRectCorner.topRight], cornerRaduiWidth:33))
.shadow(color: .red, radius:10 , x: 3.0, y:0)
.padding(EdgeInsets.init(top: 0, leading: 0, bottom: 11, trailing: 1))

Image("iimage")
.resizable()
.frame(width:150, height: 125, alignment:.center )
.clipShape(RoundedCorner(corners:[UIRectCorner.topLeft,UIRectCorner.bottomRight,UIRectCorner.bottomRight], cornerRaduiWidth:22,cornerRaduiHeight: 22))
.shadow(color: .purple, radius:10 , x:0.0 , y:0.0 )
.padding(EdgeInsets.init(top: 0, leading: 0, bottom: 11, trailing: 1))
                
Image("iimage")
.resizable()
.frame(width:150, height: 125, alignment:.center )
.clipShape(RoundedCorner(corners:[UIRectCorner.topRight,UIRectCorner.bottomLeft,UIRectCorner.bottomRight], cornerRaduiWidth:22,cornerRaduiHeight: 22))
.shadow(color: .blue, radius:10 , x:0.0 , y:0.0 )
.padding(EdgeInsets.init(top: 0, leading: 0, bottom: 11, trailing: 1))
                
Image("iimage")
.resizable()
.frame(width:150, height: 125, alignment:.center )
.clipShape(RoundedCorner(corners:[UIRectCorner.topLeft,UIRectCorner.topRight,UIRectCorner.bottomLeft,UIRectCorner.bottomRight], cornerRaduiWidth:22,cornerRaduiHeight: 22))
.shadow(color: .gray, radius:10 , x:0.0 , y:0.0 )
.padding(EdgeInsets.init(top: 0, leading: 0, bottom: 11, trailing: 1))

到这里我们已经解决了最难的一个问题了开始写代码。

我们在骨骼框架基础上完成了上半部分。圆角图片和图片底部文字。 在这里插入图片描述 到这里我们基本完成了item的创建。

这里一些坑,🐂🍺度娘也不管用了。我本来想给整体加Shandow的结果导致内部布局有阴影。偌大的几个群没人知道,我想知道IOS还有人写么。最后才发现在添加Shadow之前需要clipShape才可以。最终效果出来了😄。

在这里插入图片描述 代码:

import SwiftUI

struct BilibliItemView: View {
    var body: some View {
        VStack{
        VStack(alignment:.leading, spacing: 1){
            ZStack(alignment:.bottom){
                Image("iimage").resizable().frame(width:190, height: 125, alignment:.center)
                HStack(){
                    HStack(){
                        Image("bofang").resizable().frame(minWidth: 15, idealWidth:7, maxWidth:7, minHeight: 15, idealHeight: 5, maxHeight:5, alignment: .center).padding(EdgeInsets(top: 5, leading: 1, bottom: 5, trailing:1))
                        Text("35.5万").font(.footnote).foregroundColor(.white)
                    }.frame(alignment: .center)
                    Spacer()
                    HStack(){
                        Image("pinglun").resizable().frame(minWidth: 15, idealWidth:5, maxWidth:5, minHeight: 15, idealHeight: 5, maxHeight:5, alignment: .center).padding(EdgeInsets(top: 5, leading: 1, bottom: 5, trailing:1))
                        Text("28.77").lineLimit(1).font(.footnote).foregroundColor(.white)
                    }
                    HStack(){
                        Text("14:45").font(.footnote).foregroundColor(.white)
                    }
                }.background(Color.black.opacity(0.6))
                //标题
                
            }.frame(width: 190, height:125, alignment: .center)
            Text("冰与火之歌").font(.system(size:22)).padding(EdgeInsets.init(top: 11.0, leading:11,bottom:0,trailing:26)).background(Color.white)
            HStack(alignment:.center) {
                Text("28万人点赞")
                Spacer()
                Image("ziyuan").resizable().frame(minWidth: 22, idealWidth:5, maxWidth:5, minHeight: 22, idealHeight: 5, maxHeight:5, alignment: .center).padding(EdgeInsets(top: 5, leading: 1, bottom: 5, trailing:0))
            }.frame(width: 170,height:50).background(Color.white).padding(EdgeInsets(top: 20, leading: 11, bottom: 11, trailing:1))
        
           
        }
            
        }.frame(width: 190, height:210, alignment: .center).background(Color.white).clipShape(RoundedCorner(corners:[UIRectCorner.topLeft,UIRectCorner.topRight], cornerRaduiWidth:22)).shadow(color: Color=.black.opacity(0.3), radius: 10, x: 11, y: 11)
    }
}

struct BilibliItemView_Previews: PreviewProvider {
    static var previews: some View {
        BilibliItemView()
    }
}

struct RoundedCorner: Shape {
   //    init(roundedRect rect: CGRect, byRoundingCorners corners: UIRectCorner, cornerRadii: CGSize)
    var corners: UIRectCorner = .allCorners
    var cornerRaduiWidth:CGFloat=0.0
    var cornerRaduiHeight:CGFloat=0.0
    func path(in rect: CGRect) -> Path {
    //      这个是白塞尔曲线
    let path = UIBezierPath(roundedRect: rect, byRoundingCorners:corners, cornerRadii: CGSize(width:cornerRaduiWidth, height:cornerRaduiHeight))
        return Path(path.cgPath)
    }
}

代码还在继续....没玩接着继续。搞个列表玩一玩 在这里插入图片描述

是不是太长了。咋们下一节继续。SwiftUI玩转所有的列表?就这样定了。对于里面的内容我会继续补充的。

总结

代码没玩继续...   提示:这里对文章进行总结: 这章我们完成了基本的【布局,部件,控件,View,UI学的太多了不知道叫啥了】摆放。以及Image圆角的裁剪等,下一章节搞一波列表,玩转各种列表。如果学习Flutter和IOS以及Android的小伙子Qq加群来一起进步 号:730772561