では前の記事、私たちはのSwiftUIについて学びText
コンポーネント、およびによりStack
部品のいくつかの簡単なレイアウトシリーズの内容。この記事では、我々は、新しい画像コンポーネントを知っているだろう、と簡単なサイトの詳細画面を実装するためにMapKitフレームワークでは、これら2つの記事の知識を利用しようとします。
独自の開発作業に、最初の記事を書いた後、突然、それがその「ネットワーク全体最初」と思える、緊張プレリリース段階に入って、ずっと前に書かれた第二の物品が完了し、ポリッシュリリースするそう長くかかっ作ら失われました...
カスタムビューの写真
まず、ランドマークに絵を入れAssets.xcassets行く、私はBaiduの広州タワーの写真が見つかりました:
その後、我々は新しいクラスを作成するために、新しい画像を表示したい、それが記事に置かれContentView.swiftウェルに隣接しています。新しい文書は、選択するとSwiftUIビュー:
私たちは広州塔にここになりますので、CircleImageと呼ばれる名前が円形にカット。新しいコードを見ることができ、我々は前の章と内容でText
変更しImage
、その後、画像の名前を渡し、我々はプレビューから直接キャンバスに私たちの写真を見ることができます。
次に、我々はそれにコード内の円形のカットを追加します。独創的なアプローチの多くは、最速の方法が動作する、がありますclipsToBounds
とcornerRadius
、絵の半分を加えた幅と同じ長さと絵を要求したフィレットの高さに良好な表示を実現するために、正方形です。
SwiftUI年間で、これは物事の言葉は次のとおりです。
.clipShape()
给图片加了个裁剪的形状,其中 Circle
类型是一个用来当作遮罩的图形,你也可以给它加上填充色或者描边来单独使用,类似于以往通过 CALayer
去实现的效果。
但这也太大了,我们的屏幕装不下,我们可以再加两行代码,把图片缩放到一个合适的大小:
讲道理,这里设置的宽高应该是一样的,毕竟是个圆嘛…但是我懒得重新截图了,各位童鞋自己调整一下数值就可以了
为了让图片本身在不同背景下都能凸显出来,我们再给它加个描边,这要通过 overlay()
方法去实现;也许再加个阴影吧,用到的是 shadow()
方法;最后出来的效果是这样的:
是不是醒目多啦?
每当做完一个新视图,我就想对比一下用老方法实现同样的效果有什么不同…
在 SwiftUI 里使用 UIKit
不知道大家发现了没有,我们在 SwiftUI 里用到的视图全部都是 struct
,这意味着它们跟我们原本熟悉的 UIKit 是两套不同的机制,那难道以前开发的视图就完全用不上了吗?
答案是可以的。
要在 SwiftUI 里使用 UIView 的子类,只需要把它用一个遵循 UIViewRepresentable
协议的 SwiftUI 视图包裹起来即可。
这里举的是 UIKit 的例子,但同样也适用于 AppKit 和 WatchKit。
我们再来创建一个新的 SwiftUI View 来做我们的地图界面,但这一次,我们要改一下内容视图的协议:
1 |
import SwiftUI |
然后你会发现 Xcode 在 UIViewRepresentable
这里报错了,因为这个协议下有两个必须实现的方法:
makeUIView(context:)
用来创建我们的MKMapView
updateUIView(_:context:)
用来进行视图的配置,并响应后续可能的变化
那下面我们就来实现一下。再加新代码之前,可以把已经用不上的 body
部分先删掉了。
对于 makeUIView(context:)
,只需要声明它返回的是 MKMapView
然后直接通过构造方法返回一个空对象就可以了:
1 |
func makeUIView(context: UIViewRepresentableContext<MapView>) -> MKMapView { |
updateUIView(_:context:)
要做的事情就比较多了,我们一步步说:
1 |
func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) { |
- 先把表示广州塔坐标的对象给构造出来(这是我在网上查的,等会预览的时候看看准不准)
- 构造一个用来标识地图的缩放等级的对象,数值越小地图拉得越近
- 构造坐标区域,并把这个区域设置到我们的地图视图上
赶紧预览一下看看效果吧!你会发现画布上空白一片…
那是因为预览默认是静态模式的,它只能完整渲染 SwiftUI 的视图。因为我们现在用到了 UIView 的子类,所以要把预览切换到实时模式(右下角红框里的按钮):
emmmm…塔呢?这定位看起来也不是很准啊。
把一切都组装起来吧!
先看看预期实现的效果图:
然后花一点时间思考一下怎么弄,我们这两篇文章的知识是完全足够了的。
好啦!公布答案!
我们会在上一篇文章实现的 ContentView
里直接进行组装,下面来看看分解动作:
1 |
struct ContentView: View { |
- 先用一个
VStack
把所有内容包裹起来,默认情况下VStack
的内容布局是居中的,所以我们不需要做修改 - 针对
MapView
我们要做两个修改edgesIgnoringSafeArea
可以让我们的视图把系统预留给刘海和状态栏的区域也用掉,这样看起来会更自然一点- 对于只设置了
height
的视图,它的宽度会默认占满所有父视图里的可用空间
- 我们的图片视图本身已经实现了所有效果了,现在只需要调整一下位置即可。需要注意的是,因为这里是通过
offset
移动的,所以为了保持与底部文字的间距,特意加上了一个负的padding
来抵消掉位移导致的差距 - 做完前三步的操作后,这个
VStack
整体是在竖直方向上居中的,所以加上一个Spacer
把整体有内容的部分顶到最上面(其实也可以通过HStack
的alignment
来实现,不过那样代码就没有现在的简单优雅了)
最终成果:
如果你发现照着实现出来之后,中间圆形部分特别大的话,别担心,你是对的!
因为文章前面的CircleImage
确实是为了展示而特意设置得比较大的,所以调整一下里面的宽高即可。
小结
到这里大家应该对 SwiftUI 的使用比较上手了,但目前为止涉及到的组件还比较少,SwiftUI 光是各种强大的组件就已经够玩很久了。不过我打算在第四篇文章里再集中讲各种有意思的组件使用方式,因为下一篇文章我们要先解决数据来源的问题。
既然我们的视图组件已经是通过声明式的写法来构建的了,那我们的数据是不是也该换一种方式绑定到视图上呢?在 JS 上我们可以用 react-redux 这样的数据绑定手段,那 SwiftUI 是不是该搭配 RxSwift 来使用了?
这些问题都将在下一篇文章里为大家解答!
参考链接
SwiftUI | Creating and Combining Views
SwiftUI Essentials - WWDC 2019 - Videos - Apple Developer
オリジナル:ビッグボックス チュートリアルのSwiftUIシリーズ(2) - UIKitのに連動してカスタムビュー