Swift UI 完全开发(3-4)Image图片控件与布局

Swift UI 完全开发(3-4)

对应《Swift UI 完全开发》原书第3章至第4章

P.S. 文章内容为个人阅读后认为的重点,顺序与原书存在不一致,有任何疑问欢迎评论。

3 Image图片使用

3.1 展示本地图片

  1. 新建SwiftUI View文件,命名为“SwiftUIImage”。

    image-20240501135533519

  2. 在左侧菜单选中“Assets”资源库文件,可以查看资源库文件内容。

    Assets资源库作为项目的图片资源、颜色资源等存储的文件,同时也可以快捷使用通用的颜色和应用图标

    使用Assets的一个好处是,我们可以很容易地在应用的不同视图之间重复使用同样的图片,使整个项目的用户体验一致,而且可以很大程度减少重复代码和资源的量。

    image-20240501135711132

  3. 点击点不的“+”号或者拖入的方式倒入图片等资源:

    image-20240501140507951

  4. 为了提高图片素材的使用便捷性,双击图片修改其名称,改名为”DemoImage“,建议使用英文名称:

    在Assets素材库倒入文件并修改其文件名,不会对真实导入的文件名有影响,只是对导入的文件在项目中规定命名,以文件名称建立索引达到快速访问的效果。

    image-20240501140852192

  5. 回到项目中,选中SwiftUIImage视图文件,使用Image图片控件展示图片

Image("DemoImage")

image-20240501141636851

3.2 修饰符格式化图片

3.2.1 .resizable().scaledToFit()
        Image("DemoImage")
            .resizable()
            .scaledToFit()

image-20240501143654887

  • .resizable()调整图片大小修饰符,允许我们对图片进行大小调整,即原有的图片文件是固定的静态视图,不允许用户调整大小,因此首先要允许图片进行拉伸等操作。

  • .scaledToFit()保持横纵比修饰符,运行在保持图片原有的宽高比的基础上,等比例缩放图片直至在展示区域内。而且,在后续调整图片大小时,图片将自动保持原有的宽高比。(比如,我们只需要设置图片宽度,系统自动计算调整图片的高度)

3.2.2 .frame().cornerRadius()
        Image("DemoImage")
            .resizable()
            .scaledToFit()
            .frame(width: 200)
            .cornerRadius(10)

image-20240501144233943

  • .frame()尺寸修饰符,可以快速设置视图的宽、高,或者设置最大的宽、高。这只设置了图片的width(宽度)。
  • .cornerRadius()圆角修饰符可以给展示的视图设置自定义的圆角度数,这里设置的圆角的度数是10。
Text文字和Image图片组合

image-20240501144706399

  ZStack{
            Image("DemoImage")
                .resizable()
                .scaledToFit()
                .frame(width: 280)
                .cornerRadius(16)
            
            Text("美丽风景")
                .font(.custom("slideyouran-Regular", size: 35))
                .foregroundColor(.white)
                .fontWeight(/*@START_MENU_TOKEN@*/.bold/*@END_MENU_TOKEN@*/)
        }

ZStack层叠布局容器,HStack横向布局容器,VStack纵向布局容器,三者共同构成了SwiftUI基础的布局容器,容器部分详见后面章节

ZStack层叠布局容器,是将内部元素堆叠在一起,简单来说就是控件覆盖控件,而且严格按照内部空间代码的编写顺序,我们使用了Image图片控件,再使用了Text文字控件,则图片在底层,文字再上层。

3.2.3 .clipShape()
        Image("DemoImage")
            .resizable()
            .scaledToFit()
            .frame(width: 280)
            .clipShape(Circle())

image-20240501145137105

  • .clipShape()裁剪修饰符可以把图片裁剪为想要的形状,例如Circle()

  • 比如,在App的“我的”页面,在用户登陆后需要展示用户头像,那么我们在获得用户头像的图片后,可以将其裁剪为圆形进行展示。

3.2.4 .opacity()
  Image("DemoImage")
            .resizable()
            .scaledToFit()
            .frame(width: 280)
            .cornerRadius(16)
            .opacity(0.6)

image-20240501151038163

  • opacity()透明度修饰符的范围为0~1,作用在视图上可以调整视图的透明度,这时如果使用ZStack层叠视图将文字“藏”在图片后面,则会展示出来。
3.2.4 .blendMode()
  1. 再倒入一张图片素材到资源库中,命名为“DemoImage2“

image-20240501151503867

  1. 然后使用ZStack层叠视图将两张图片堆叠在一起,其中顶部的图片我们使用.blendMode()混合模式修饰符

image-20240501151527877

        ZStack{
            Image("DemoImage")
                .resizable()
                .scaledToFit()
                .frame(width: 280)
                .cornerRadius(16)

            Image("DemoImage2")
                .resizable()
                .scaledToFit()
                .blendMode(.color)
            
        }
  • 使用.blendMode()混合模式修饰符可以将我们准备好的两张图片混合在一起,这里使用的模式是.color颜色混合,即设置.blendMode()修饰符的图片作为颜色部分,混合到底部视图中与之混合,有点像像Photoshop当中的“正片叠底”效果。

3.2 使用SF Symbols图标库

SF Symbols图标库是苹果公司规划的统一的图标库供开发者直接使用。

SF Symbols图标库内置在SwiftUI中,使用方法很简单,使用Image图片控件可以直接展示图标。

image-20240501152246047

        Image(systemName: "square.and.arrow.up")
            .font(.system(size: 120))

和常规展示导入的图片素材不同,我们需要在Image图片控件中告知我们使用的是系统自带的图标素材,素材名称需要指定为systemName

而使用SF Symbols图标后的图片又和标准的图片使用有所区别,比如设置图标素材的尺寸,可以直接像Text文字控件一样,使用.font()字体修饰符。

设置SF符号图标的填充色也和Text文字控件的方法一致,直接使用.foregroundColor()前景色修饰符:

image-20240501152727613

        Image(systemName: "square.and.arrow.up")
            .font(.system(size: 120))
            .foregroundColor(/*@START_MENU_TOKEN@*/.blue/*@END_MENU_TOKEN@*/)

如果想要SF符号图标更像一张图片,也可以通过其他修饰符进行美化,如图:

image-20240501152943347

        Image(systemName: "square.and.arrow.up")
            .font(.system(size: 40))
            .foregroundColor(.blue)
            .padding(20)
            .background(Color(.systemGray5))
            .clipShape(Circle())

如此便完成了一个圆形的按钮样式

3.3 从互联网上获得一张图片

  • AsyncImage异步图片控件通过异步请求的方式,从URL异步显示图片,且在使用过程中也不会阻塞主线进程的活动
  1. 我们现声明一个网络的图片链接
let imageURL = "https://pic2.zhimg.com/v2-bf1a927f037a79f4d57d9ae543430a0d_r.jpg"  //图片url来自互联网,若有侵权,请联系我及时删除。
  1. 使用AsyncImage异步图片控件请求访问图片链接地址imageURL,如图

    image-20240501154000811

struct SwiftUIImage: View {
    let imageURL = "https://pic2.zhimg.com/v2-bf1a927f037a79f4d57d9ae543430a0d_r.jpg"  //图片url来自互联网,若有侵权,请联系我及时删除。
    
    var body: some View {
       
        AsyncImage(url: URL(string:imageURL)){ image in
            image
                .resizable()
                .scaledToFit()
                .frame(width:280)
                .cornerRadius(16)
        }placeholder: {
            ProgressView()
        }
    }
}

AsyncImage异步图片控件,需要在stirng中指定图片的URL连接地址,然后直接访问链接展示图片。我们通过AsyncImage异步图片控件访问URL地址,URL地址为之前声明好的imageURL,在获得图片之后返回图片image。对于image图片的格式化和前文学习的Image图片控件一致。

AsyncImage异步图片控件还可以设置在异步请求过程中的placeholder缺省图片,如果请求的图片尺寸和分辨率过大,则可以展示一个“ProgressView()加载中“基础控件作为过渡;也可以自定义样式,比如构建一张默认的缺省图片,如图:

image-20240501154621494

 Text("图片加载中")
                .font(.system(size: 24))
                .foregroundColor(.gray)
                .padding()
                .frame(width: 280, height: 140)
                .background(Color(.systemGray6))
                .cornerRadius(16)

4 Stack布局容器使用

  • VStack纵向布局容器中的控件或元素按照代码从上至下的优先顺序垂直展示
  • HStack横向布局容器中的控件或元素按照代码从左到右的优先顺序水平展示
  • ZStack 基于z轴实现从底层到外层的排布方式

4.1 实战案例:启动页

设计目标

之前通过多个Text文字控件完成了一个简单的启动页,我们做的更加精致一些,利用常用布局容器、Text文字控件、Image图片控件,完成星空猫App的启动页。

  1. 新建SwiftUI View文件,命名为“SwiftUIStack”。

  2. 在Assets资源库中导入一张踊跃背景制作的图片,命名为“StartupPageImage”。由于图片尺寸>设备展示区域,使用修饰符对齐进行调整:

    • .resizable()调整图片大小修饰符,允许我们对图片素材大小进行调整;
    • .aspectRatio()指定横纵比修饰符的作用等同于.scaledToFit()保持横纵比修饰符,允许在保持原有图片的宽高比的基础上,等比例缩放图片。其中contentMode参数可以设置为不同的值,例如.fill或者.fit,根据设备展示区域自动调整图片的尺寸。
    • edgesIgnoringSafeArea()忽略安全区域修饰符。iPhone X之后的产品线中,为了保证底部菜单和顶部菜单不被遮挡,在iOS项目开发过程中会自动保留顶部和底部的安全区域。这里为了使图片素材铺满全屏,需要使用edgesIgnoringSafeArea()忽略安全区域修饰符`忽略所有的安全区域。

    image-20240501181123712

            Image("StartupPageImage")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .edgesIgnoringSafeArea(.all)
    
  3. 完成应用图标和应用名称的部分。应用图标采用Image图片控件,应用名称采用Text文字控件,它们之间的布局关系是横向布局;“应用图标和应用名称”这个组合与背景图片的关系时:背景图片在底层,“应用图标和应用名称”这个组合在顶层。根据上述关系使用ZStack堆叠布局容器和HStack横向布局容器进行布局和展示。在Assets资源库中导入应用图标的图片,将其命名为“ApplicarionIcon”,并拟定一个应用名称,将它们展示到HStack横向布局容器中:

    • 应用图标部分,我们使用Image图片控件展示”AppliconIcon“图片素材,并通过.resizable()调整图片大小修饰符、.aspectRatio()指定横纵比修饰符、.frame()尺寸修饰符、.cornerRadius()圆角修饰符,让应用图标最终呈现出一个圆角的60*60的正方形。
    • 应用名称部分,使用.font()字体修饰符、.foregroundColor()前景色修饰符、.bold()字体加粗修饰符,创建一个白色32号字号加粗显示的应用名称。
    • HStack(alignment:.center, spacing: 20)对于HStack横向布局容器设置了内部对齐方式为居中对齐,间距为20。
     ZStack {
                
                Image("StartupPageImage")
                    .resizable()
                    .aspectRatio(contentMode: /*@START_MENU_TOKEN@*/.fill/*@END_MENU_TOKEN@*/)
                    .edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
                
                HStack(alignment:.center, spacing: 20){
                    Image("ApplicationIcon")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: 60)
                        .cornerRadius(16)
                    
                    Text("星空猫")
                        .font(.system(size: 32))
                        .foregroundColor(.white)
                        .bold()
                }
                
            }
    

    image-20240501190213445

  4. 如何将组合元素置于底部靠上的位置?

    • 方法一:直接设置ZStack堆叠布局容器的参数
       ZStack(alignment: .bottom) 
    

    image-20240501190442421

    • 方法二:借助新容器——VStack纵向布局容器,将HStack横向布局容器中的内容放置在内部,这里使用了一个全新的空间Spacer()占位空间,是我们使用最频繁的基础控件,可以根据设备大小自由扩展。由于Spacer()占位空间具有自动扩展的特性,就把HStack横向布局容器“挤”到下面去了。
     VStack{
                    //占位空间
                    Spacer()
                    //应用图标和应用名称
                    HStack(alignment:.center, spacing: 20){
                        Image("ApplicationIcon")
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(width: 60)
                            .cornerRadius(16)
                        
                        Text("星空猫")
                            .font(.system(size: 32))
                            .foregroundColor(.white)
                            .bold()
                    }
                }
    

    image-20240501190732864

4.2 实战案例:缺省页

任务目标

当页面列表中没有内容时会呈现一个缺省的页面内容,指引用户进行下一步的操作,例如“还没有收到消息哦,先去社区逛逛吧”或者“暂无数据“等字样。

有了4.1经验,我们在Assets资源库中导入应用图标的图片,将其命名为"DefaultImage";然后使用图片和文字,以及VStack纵向布局容器来实现缺省页,如图:

 VStack(spacing: 40){
            //缺省页图片
            Image("DefaultImage")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 200)
            
            //文字指引
            VStack(spacing:10){
                
                Text("还没收到消息哦")
                    .font(.system(size: 20))
                    .foregroundColor(.gray)
                    .bold()
                
                Text("不如先去社区逛逛吧")
                    .font(.system(size: 17))
                    .foregroundColor(.gray)
                    .bold()
            }
        }

image-20240501192413407

4.3 实战案例:状态显示页

任务目标

我们再来完成一个页面——状态显示页,一般在设计上有两种方式,一种以页面的形式展示,类似于支付成功后的提示信息页面;另一种是使用“弹窗”的方式进行展示,如成就提醒、签到成功等。下面我们采用第二种方式实现。弹窗与主要显示页面之间有一“半透明”的类似“遮罩”的效果。

  1. 先完成弹窗部分的内容。创建新的视图文件"StatusPageView",向Assets资源库中导入弹窗的主要展示图片,将其命名为“PopoverImage”,与文字一同搭建主体内容。

    VStack(spacing: 20){
                //展示图片
                Image("PopoverImage")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 120)
                
                //文字指引
                VStack(spacing:10){
                    Text("签到成功")
                        .font(.system(size: 20))
                        .foregroundColor(.black)
                        .bold()
                    
                    Text("再签到2天可获得500积分")
                        .font(.system(size: 17))
                        .foregroundColor(.gray)
                }
                
                Text("知道了")
                    .font(.system(size: 17))
                    .foregroundColor(.white)
                    .bold()
                    .padding()
                    .frame(width: 180)
                    .background(Color.green)
                    .cornerRadius(32)
            }
    

    image-20240501195457687

    是不是有一种感觉,使用SwiftUI搭建页面时需要有“整体思维”,首先要分析页面中有哪些元素、需要使用什么样的控件,同时考虑这些控件之间的布局方式。有了这些思考过程,在代码编写过程中就可以很清晰地“描述”页面内容,这就是所谓的码感

  2. 页面形式已经搭建完成,接下来让他变成一个弹窗。先把整个视图的内容作为一个整体,设置该视图整体的大小。使用padding()填充修饰符、.frame()尺寸修饰符、.background()背景修饰符、.cornerRadius()圆角修饰符,将视图修饰为一个圆角矩形,由于背景色为白色,预览窗口无法识别。

    VStack(spacing: 20){
                //展示图片
                Image("PopoverImage")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 120)
                
                //文字指引
                VStack(spacing:10){
                    Text("签到成功")
                        .font(.system(size: 20))
                        .foregroundColor(.black)
                        .bold()
                    
                    Text("再签到2天可获得500积分")
                        .font(.system(size: 17))
                        .foregroundColor(.gray)
                }
                
                Text("知道了")
                    .font(.system(size: 17))
                    .foregroundColor(.white)
                    .bold()
                    .padding()
                    .frame(width: 180)
                    .background(Color.green)
                    .cornerRadius(32)
            }
            .padding()
            .frame(maxWidth: 320)
            .background(Color.white)
            .cornerRadius(16)
    

    image-20240501200846405

  3. “搭建”一个“半透明”的视图,使用ZStack堆叠布局容器将弹窗和遮罩呈现层级关系。在下方代码中,ZStack堆叠布局容器有两个视图:一个时遮罩视图;另一个是弹窗视图。遮罩视图我们采用的方法是使用VStack垂直布局容器,内部只有一个Spacer()占位空间的基础控件,它可以根据容器的大小自动填充空白的空间,那么我们只需要指定该容器的大小,就可以设计背景遮罩视图。

    使用.frame()尺修饰符、.background()背景修饰符、opacity()透明度修饰符、.edgesIgnoringSafeArea()忽略安全区域修饰符,将这招视图的大小变成自定义,然后填充黑色的背景颜色。为了凸显半透明效果,通过设置透明度的方式使其半透明,最后让视图忽略安全区域铺满全屏。便实现了背景遮罩视图的效果。

    .frame()尺寸修饰符使用中,我们使用的并不是固定设置宽度和高度,而是指定最大的宽度和高度,特别是最大宽度和高度为.infinity自适应。这么做的好处在于不同设备分辨率下,无需调整视图的尺寸,系统会自动适配。

      		ZStack{
                VStack{
                    Spacer()
                }
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
                .background(Color.black)
                .opacity(6)
                .edgesIgnoringSafeArea(.all)
                //弹窗
                VStack(spacing: 20){
                   //代码块
                    }
                    Text("知道了")
                        .font(.system(size: 17))
                        .foregroundColor(.white)
                        .bold()
                        .padding()
                        .frame(width: 180)
                        .background(Color.green)
                        .cornerRadius(32)
                }
                .padding()
                .frame(maxWidth: 320)
                .background(Color.white)
                .cornerRadius(16)
            }
    

    image-20240501202109433

4.4 小知识:如何收起代码块

开发中代码块,越来越多,如果快速收起展开代码块:

Xcode顶部的系统工具栏中点击“Xcode”,选择“Settings”,在“Text Editing”栏目中勾选“Code folding ribbon”

image-20240501201753259

  • 31
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值