SwiftUI 系列教程(2)—— 与 UIKit 结合的自定义视图

在上一篇文章中,我们了解了 SwiftUI 的 Text 组件,并通过 Stack 系列的组件对内容进行了一些简单的布局。在这篇文章里,我们会认识一个全新的图片组件,并且会尝试利用这两篇文章的知识,结合 MapKit 框架,来实现一个简单的地点详情界面。

写完第一篇文章之后,本职的开发任务突然进入了紧张的预发布阶段,搞得早就写好的第二篇文章拖了这么久才完成润色和发布,看来“全网最早”要丢了…

自定义图片视图

首先把一张地标图片放到 Assets.xcassets 里去,我在百度找了张广州塔的照片:

然后,我们要为新的图片视图创建一个新的类,就放在上一篇文章的 ContentView.swift 旁边好了。新建文件的时候,选择 SwiftUI View

取个名字叫 CircleImage,因为我们将要在这里把广州塔裁剪成一个圆。新建的代码内容跟上一章看到的一样,我们把 Text 改成 Image,然后把图片的名字传进去,直接就可以通过预览在画布上看到我们的图片了:

接下来我们在代码里给它加上一个圆形的裁剪。原来的做法有很多了,最快速的做法应该是操作 clipsToBoundscornerRadius,给图片加上长度等于一半宽高的圆角,这还得要求图片是正方形的才能达到满意的显示效果。

而在 SwiftUI 里,这就是一句话的事情:

.clipShape() 给图片加了个裁剪的形状,其中 Circle 类型是一个用来当作遮罩的图形,你也可以给它加上填充色或者描边来单独使用,类似于以往通过 CALayer 去实现的效果。

但这也太大了,我们的屏幕装不下,我们可以再加两行代码,把图片缩放到一个合适的大小:

讲道理,这里设置的宽高应该是一样的,毕竟是个圆嘛…但是我懒得重新截图了,各位童鞋自己调整一下数值就可以了

为了让图片本身在不同背景下都能凸显出来,我们再给它加个描边,这要通过 overlay() 方法去实现;也许再加个阴影吧,用到的是 shadow() 方法;最后出来的效果是这样的:

是不是醒目多啦?

每当做完一个新视图,我就想对比一下用老方法实现同样的效果有什么不同…

在 SwiftUI 里使用 UIKit

不知道大家发现了没有,我们在 SwiftUI 里用到的视图全部都是 struct,这意味着它们跟我们原本熟悉的 UIKit 是两套不同的机制,那难道以前开发的视图就完全用不上了吗?

答案是可以的。

要在 SwiftUI 里使用 UIView 的子类,只需要把它用一个遵循 UIViewRepresentable 协议的 SwiftUI 视图包裹起来即可。

这里举的是 UIKit 的例子,但同样也适用于 AppKit 和 WatchKit。

我们再来创建一个新的 SwiftUI View 来做我们的地图界面,但这一次,我们要改一下内容视图的协议:

12345678
import SwiftUIimport MapKit 

struct  : UIViewRepresentable { // 把这里的协议改掉    var body: some View {        Text(“Hello World!”)    }}

然后你会发现 Xcode 在 UIViewRepresentable 这里报错了,因为这个协议下有两个必须实现的方法:

  1. makeUIView(context:) 用来创建我们的 MKMapView
  2. updateUIView(_:context:) 用来进行视图的配置,并响应后续可能的变化

那下面我们就来实现一下。再加新代码之前,可以把已经用不上的 body 部分先删掉了。

对于 makeUIView(context:),只需要声明它返回的是 MKMapView 然后直接通过构造方法返回一个空对象就可以了:

123
func makeUIView(context: UIViewRepresentableContext<MapView>) -> MKMapView {    MKMapView(frame: .zero)}

updateUIView(_:context:) 要做的事情就比较多了,我们一步步说:

123456789
func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) {// 1    let coordinate = CLLocationCoordinate2D(latitude: 23.112223, longitude: 113.331084)// 2    let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)// 3    let region = MKCoordinateRegion(center: coordinate, span: span)    uiView.setRegion(region, animated: true)}
  1. 先把表示广州塔坐标的对象给构造出来(这是我在网上查的,等会预览的时候看看准不准)
  2. 构造一个用来标识地图的缩放等级的对象,数值越小地图拉得越近
  3. 构造坐标区域,并把这个区域设置到我们的地图视图上

赶紧预览一下看看效果吧!你会发现画布上空白一片…

那是因为预览默认是静态模式的,它只能完整渲染 SwiftUI 的视图。因为我们现在用到了 UIView 的子类,所以要把预览切换到实时模式(右下角红框里的按钮):

emmmm…塔呢?这定位看起来也不是很准啊。

把一切都组装起来吧!

先看看预期实现的效果图:

然后花一点时间思考一下怎么弄,我们这两篇文章的知识是完全足够了的。

好啦!公布答案!

我们会在上一篇文章实现的 ContentView 里直接进行组装,下面来看看分解动作:

12345678910111213141516171819202122232425262728
struct ContentView: View {    var body: some View {        VStack { // 1            MapView()                 .edgesIgnoringSafeArea(.top) // 2.1                .frame(height: 300) // 2.2

            CircleImage()                .offset(y: -100)                .padding(.bottom, -100) // 3

            VStack(alignment: .leading) {                Text(“Hello SwiftUI”)                    .font(.title)                HStack(alignment: .top) {                    Text(“First Description”)                        .font(.subheadline)                    Spacer()                    Text(“Second Description”)                        .font(.subheadline)                }            }            .padding()

            Spacer() // 4        }    }}
  1. 先用一个 VStack 把所有内容包裹起来,默认情况下 VStack 的内容布局是居中的,所以我们不需要做修改
  2. 针对 MapView 我们要做两个修改
    1. edgesIgnoringSafeArea 可以让我们的视图把系统预留给刘海和状态栏的区域也用掉,这样看起来会更自然一点
    2. 对于只设置了 height 的视图,它的宽度会默认占满所有父视图里的可用空间
  3. 我们的图片视图本身已经实现了所有效果了,现在只需要调整一下位置即可。需要注意的是,因为这里是通过 offset 移动的,所以为了保持与底部文字的间距,特意加上了一个负的 padding 来抵消掉位移导致的差距
  4. 做完前三步的操作后,这个 VStack 整体是在竖直方向上居中的,所以加上一个 Spacer 把整体有内容的部分顶到最上面(其实也可以通过 HStackalignment来实现,不过那样代码就没有现在的简单优雅了)

最终成果:

如果你发现照着实现出来之后,中间圆形部分特别大的话,别担心,你是对的!
因为文章前面的 CircleImage 确实是为了展示而特意设置得比较大的,所以调整一下里面的宽高即可。

小结

到这里大家应该对 SwiftUI 的使用比较上手了,但目前为止涉及到的组件还比较少,SwiftUI 光是各种强大的组件就已经够玩很久了。不过我打算在第四篇文章里再集中讲各种有意思的组件使用方式,因为下一篇文章我们要先解决数据来源的问题。

既然我们的视图组件已经是通过声明式的写法来构建的了,那我们的数据是不是也该换一种方式绑定到视图上呢?在 JS 上我们可以用 react-redux 这样的数据绑定手段,那 SwiftUI 是不是该搭配 RxSwift 来使用了?

这些问题都将在下一篇文章里为大家解答!

参考链接

SwiftUI | Creating and Combining Views
SwiftUI Essentials - WWDC 2019 - Videos - Apple Developer

原文:大专栏  SwiftUI 系列教程(2)—— 与 UIKit 结合的自定义视图

原文地址:https://www.cnblogs.com/petewell/p/11614945.html

时间: 2024-10-11 11:01:18

SwiftUI 系列教程(2)—— 与 UIKit 结合的自定义视图的相关文章

【原】iOSCoreAnimation动画系列教程(二):CAKeyFrameAnimation【包会】

======================================================= 转载请注明 编程小翁@博客园,邮件[email protected],欢迎各位与我在C/C++/Objective-C/机器视觉等领域展开交流! ======================================================= 在上一篇专题文章[原]iOSCoreAnimation动画系列教程(一):CABasicAnimation[包会]中我们学习了iO

SwiftUI 官方教程(五)

SwiftUI官方教程(五) 5. 同时使用 UIKit 和 SwiftUI 至此,我们已准备好创建 map view 了,接下来使用 MapKit 中的 MKMapView 类来渲染地图. 在 SwiftUI 中使用 UIView 子类,需要将其他 view 包装在遵循 UIViewRepresentable 协议的 SwiftUI view 中. SwiftUI 包含了和 WatchKit . AppKit view 类似的协议. 首先,我们创建一个可以呈现 MKMapView 的自定义 v

菜鸟窝React Native 视频系列教程

菜鸟窝React Native 视频系列教程 交流QQ群:576089067 Hi,我是RichardCao,现任新美大酒店旅游事业群的Android Developer.15年加入饿了么即时配送BU,后负责蜂鸟众包Android端,期间引入react-native技术,作为国内react-native 与 Android混合开发的早期商业项目,具有一定经验,同时也是react-native开源项目reading(https://github.com/attentiveness/reading)

菜鸟窝React Native 系列教程-1.移动端开发趋势与未来

菜鸟窝React Native 系列教程-1.移动端开发趋势与未来 课程持续更新中..... 我是RichardCao,现任新美大酒店旅游事业群的Android Developer.如果你也有兴趣录制RN视频,请加入下面QQ群找我. 下载地址:https://pan.baidu.com/s/1c1XmE56 密码:shhw 首发地址:菜鸟窝-ReactNative学习板块 交流QQ群:576089067 课程目录:菜鸟窝React Native 系列教程

Android视频录制从不入门到入门系列教程(三)————视频方向

运行Android视频录制从不入门到入门系列教程(二)————显示视频图像中的Demo后,我们应该能发现视频的方向是错误的. 由于Android中,Camera给我们的视频图片的原始方向是下图这个样子的: 就是说,即使你是竖着拿手机的,Camera提供给你的视频图像的方向还是上图那样横着的图片. 我们可以通过下述方向改变Camera提供的视频图像的方法: camera.setDisplayOrientation(90); 让图像顺时针旋转90度,视频图像的方向就正常的. 本篇文章DEMO下载.

MongoDB系列教程(八):GridFS存储详解

MongoDB系列教程(八):GridFS存储详解 GridFS简介 mongoDB的文档以BSON格式存储,支持二进制的数据类型,当我们把二进制格式的数据直接保存到mongoDB的文档中.但是当文件太大时,例如图片和视频等文件,每个文档的长度是有限的,于是mongoDb会提供了一种处理大文件的规范--GridFS. GridFS实现原理 在GridFS数据库中,默认使用fs.chunks 和fs.files来存储文件,其中fs.files集合存放文件的信息,fs.chunks存放文件的数据,一

Hyper-V 2016 系列教程39 在 Windows 10中使用 Hyper-V 和 Windows PowerShell

注:以下内容部分取自微软官网: 现在你已基本了解如何部署 Hyper-V.创建虚拟机和管理这些虚拟机,让我们研究一下如何使用 PowerShell 来自动执行其中大部分活动. 返回 Hyper-V 命令列表 单击 Windows"开始"按钮,键入"PowerShell". 运行以下命令以显示适用于 Hyper-V PowerShell 模块的 PowerShell 命令的可搜索列表. PowerShell Get-Command -Module hyper-v | 

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【开篇】【持续更新中。。。】

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http://bitoftech.net/2013/11/25/detailed-tutorial-building-asp-net-

自定义View系列教程01--常用工具介绍

在自定义View的时候,常常会用到一些Android系统提供的工具.这些工具封装了我们经常会用到的方法,比如拖拽View,计算滑动速度,View的滚动,手势处理等等.如果我们自己去实现这些方法会比较繁琐,而且容易出一些bug.所以,作为自定义View系列教程的开端,先介绍一下这些常用的工具,以便在后续的学习和工作中使用. Configuration ViewConfiguration GestureDetector VelocityTracker Scroller ViewDragHelper