热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

frame越过另一个frame_SwiftUI从零开始做一个少数派客户端

在学习Swift2.0正式来临之前,我决心先体验一下使用SwiftUI写个小软件。本文基于目前的SwiftUI开发并没有使用任何2.0的新特性。熟悉基本操作首先多出来
在学习Swift 2.0 正式来临之前,我决心先体验一下使用 SwiftUI 写个小软件。本文基于目前的 SwiftUI 开发并没有使用任何2.0的新特性。

熟悉基本操作

4816f82dfed02c711fa2720c6ebbb5be.png

首先多出来这个界面叫做 Canvas 不小心关掉的话可以在 Editor > Canvas 打开

左下角的 可以在切换文件固定这个界面,很方便的功能

右下角是很普通的缩放功能 右侧有两个按钮▶️可以让 preview 运行起来, 可以让 preview 之间在设备上运行

效果图

3af7ca9dce1cf6ec0b5acdec0e00c42c.png

App 整体上就是一个文章列表,每个文章点进去就是一个 web view,所以组件就三个:

  • List 文章列表
  • Cell 列表元素显示-图片,标题和副标题
  • WebView 网页-文章内容

数据模型

根据 API 接口 https://sspai.com/api/v1/article/index/page/get 返回的数据创建数据模型

struct NetworkResponse : Codable {let msg: Stringlet error: Intlet data: T
}
struct ItemBean: Codable, Identifiable {let id: Intlet title: Stringlet summary: Stringlet banner: String//... more
}

List组件需要 item 满足 Identifiable 协议

List

创建文件ItemList.swift

struct ItemList: View {@State var items: [ItemBean] = []var body: some View {List(0 ...self, from: data).data else {// Errorreturn}DispatchQueue.main.async {self.items = items}}.resume()}
}

@State修饰符可以关联View的状态,当item变化会重新创建视图 self.items = items这行代码会刷新界面需要放到DispatchQueue.main

Cell

Cell就很普通,后面在加图片。

struct ItemCell: View {let item: ItemBeanvar body: some View {VStack {Text("https://cdn.sspai.com/" + item.banner)Text(item.title).font(.headline)Spacer().frame(height: 8)Text(item.summary).font(.subheadline).foregroundColor(Color.secondary)}}
}

WebView

SwiftUI的组件中是没有WebView的,但是提供了UIViewRepresentable来使用UIKit中的组件,只需要实现协议即可。

struct WebView: UIViewRepresentable {let urlString: Stringfunc makeUIView(context: Context) -> WKWebView {guard let url = URL(string: self.urlString) else {return WKWebView()}let requeset = URLRequest(url: url)let wk = WKWebView()wk.isOpaque = falsewk.load(requeset)return wk}func updateUIView(_ uiView: WKWebView, context: Context) {}
}

导航

把列表放到 NavigationView 中,Cell 放到 NavigationLink 中。

如果要改导航栏,在NavigationView里面的view改 直接使用NavigationLink会有一个箭头,可以放到ZStack中 导航出来的有SafeArea,如果想要全屏显示可以用edgesIgnoringSafeArea(Edge.Set.all)

NavigationView {List(0 ..}

网络图片

SwiftUI 目前还没有支持简单网络图片加载,不过有特别好用的第三方库,也可以自己写一个简单的用。不过还是建议使用成熟的第三方解决方案。

struct NetWorkImage: View {init(url: URL) {self.imageLoader = Loader(url)}@ObservedObject private var imageLoader: Loadervar image: UIImage? {imageLoader.data.flatMap(UIImage.init)}var body: some View {VStack {if image != nil {Image(uiImage: image!).resizable()} else {EmptyView()}}}}final class Loader: ObservableObject {var task: URLSessionDataTask!@Published var data: Data? = nilinit(_ url: URL) {task = URLSession.shared.dataTask(with: url, completionHandler: { data, _, _ inDispatchQueue.main.async {self.data = data}})task.resume()}deinit {task.cancel()}
}

改造之前的 Cell,让它显示图片

struct ItemCell: View {let item: ItemBeanvar body: some View {VStack {GeometryReader { geometry inNetWorkImage(url:URL(string: "https://cdn.sspai.com/(self.item.banner)")!).scaledToFill().frame(width: geometry.size.width, height: geometry.size.width/2).clipShape(RoundedRectangle(cornerRadius: 16))}.aspectRatio(2, contentMode: .fit).clipped()Text(item.title).font(.headline)Spacer().frame(height: 8)Text(item.summary).font(.subheadline).foregroundColor(Color.secondary)}}
}

刷新 加载更多

下拉刷新暂时没有比较简单的方案,我就直接导航上加一个刷新按钮。 加载更多就比较简单,给 Cell 加onAppear {self.fetchMoreItemsIfNeed(current: index)}根据index判断是否加载更多。ItemList最终代码就设这样的:

struct ItemList: View {&#64;State var items: [ItemBean] &#61; []var body: some View {NavigationView {List(0 ...self, from: data).data else {// Errorreturn}DispatchQueue.main.async {self.items &#61; items}}.resume()}func fetchMoreItemsIfNeed(current: Int) {guard current &#61;&#61; self.items.count - 1 else {return}let url &#61; URL(string: "https://sspai.com/api/v1/article/index/page/get?limit&#61;10&offset&#61;(items.count)")!URLSession.shared.dataTask(with: url) { (data, response, error) inDispatchQueue.main.async {guard let data &#61; data else {// Errorreturn}guard let items &#61; try? JSONDecoder().decode(NetworkResponse<[ItemBean]>.self, from: data).data else {// Errorreturn}self.items.append(contentsOf: items)}}.resume()}
}

总结

这是我第一个使用 SwiftUI 完成的 App&#xff0c;支持 iOS 和 Mac。熟悉 Flutter 的我用 SwiftUI 刚开始的感到很难受&#xff0c;Apple 的工具链还非常不完善&#xff0c;不过熟悉的之后会好一些&#xff0c;不过还是希望下个版本有所改进吧。

  • 缺点
    • 在布局的时候不要妄图让Xcode告诉你改怎么写&#xff0c;代码提示真的真的真的会让人崩溃。
    • 调试的时候要不要太在意错误提示的信息&#xff0c;真的没用。
    • 文档很简陋&#xff0c;也没有示例代码&#xff0c;全靠 Google
  • 优点
    • 调试界面不用运行整个项目&#xff0c;改了界面也能马上生效&#xff0c;我觉得比 Flutter 还好用
    • SwiftUI 代码很直观
Github​github.com


推荐阅读
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
author-avatar
CHANBunCHAI
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有