SwiftUI - 一起來仿寫微信APP之一首頁列表視圖

来源:https://www.cnblogs.com/GarveyCalvin/archive/2020/05/12/swiftui-fake-wechat-list.html
-Advertisement-
Play Games

最近在學習 SwiftUI ,我一般都是先去學習界面佈局,所以就想著仿寫一下經常使用的軟體的界面,所以先拿微信開刀。因為不想一次性發太多的內容,所以只好將主題分解,一部分一部分地去講,接下來我們一起來學習吧。 ...


簡介

最近在學習 SwiftUI ,我一般都是先去學習界面佈局,所以就想著仿寫一下經常使用的軟體的界面,所以先拿微信開刀。因為不想一次性發太多的內容,所以只好將主題分解,一部分一部分地去講,接下來我們一起來學習吧。

如果你嘗試過使用 SwiftUI 編寫界面,你會發現是如此地舒心,我已深深地愛上了它。當然它的坑並不少,畢竟才剛出來,最低支持系統是 iOS13,估計還得等個幾年才會慢慢在公司里使用上吧。但是這並不妨礙我們的學習。

在這篇文章里,我會一步一步編寫微信的首頁列表視圖,一步一步將代碼呈現上來,並仔細地講解,我相信你們都可以看懂的,先來看看效果圖。

很簡單吧?是很簡單,但是在編寫的時候還是有些技巧在裡面,畢竟,簡單才不容易勸退嘛。在開始前先講一下這篇文章將會用到的一些佈局與組件,先給大家一個印象,方便後面的閱讀理解。

HStack - 水平佈局

VStack - 垂直佈局

Text - 文本控制項

Spacer - 擴展空間,使容器填滿佈局空間

Image - 圖像控制項

List - 列表控制項

Divider - 分隔線控制項

工作環境

Xcode - Version 11.3.1 (11C504)

Swift - version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)

開始編寫代碼

編寫列表行

我們來先把頭像添加進來。

Image("1")
    .resizable() // 1
    .frame(width: 46, height: 46) // 2
    .cornerRadius(6)// 3

1 - 在 SwiftUI 中,如果需要控製圖像的大小,則必須先調用resizable修飾

2- 設置圖像大小

3 - 設置圓角大小,四個角的大小都相同

因為佈局是橫向的,所以我們在外層使用HStack包裹起來,然後添加聯繫人名字和最後發消息時間。

HStack {
    // 頭像

    HStack {
        Text("女神")
            .font(.body) // 1

        Spacer()

        Text("下午 2:55")
            .font(.caption)
            .foregroundColor(Color.gray.opacity(0.5)) // 2
    }
}

1 - 使用 font 修飾字體,這裡使用了蘋果提供的標準字體,蘋果還提供了 largeTitle, title, headline, subheadline, body, callout, footnote, caption。

2 - 使用 foregroundColor 修飾字體顏色,因為 gray 的灰色還是太黑了,所以這裡又使用了 opacity 去修飾透明度為50%,使它顯得更淡一點。

名字下方顯示的是是最後發送或接收的消息內容,因此我們在外層使用 VStack 包裹起來。

VStack(alignment: .leading, spacing: 6) { // 1
    // 名稱和時間

    Text("對不起,你是個好人")
        .font(.callout)
        .foregroundColor(Color.gray)
}

// 1 - 設定VStack裡子控制項居左對齊,預設是居中對齊。再設定子控制項的間隙為 6 個像素,這樣比較符合微信上面的設計。

現在樣子已經出來了,我們先預覽下效果。

我們給最外層的HStack增加padding,使它更美觀一些,參數填寫.all代表四周都需要邊框。經過我的眼力觀察,它的預設是 16px 的樣子。

HStack {
    // 頭像、名稱、時間、消息內容
}
.padding(.all)

有了間距,好看多了。

接下來創建一個視圖,它負責裝載行視圖,起名為GCMainRow

struct GCMainRow: View {
    var body: some View {
        HStack {
            Image("1")
                .resizable()
                .frame(width: 46, height: 46)
                .cornerRadius(6)
            
            VStack(alignment: .leading, spacing: 6) {
                HStack {
                    Text("女神")
                        .font(.body)

                    Spacer()

                    Text("下午 2:55")
                        .font(.caption)
                        .foregroundColor(Color.gray.opacity(0.5))
                }
                Text("對不起,你是個好人")
                    .font(.callout)
                    .foregroundColor(Color.gray)
            }
        }
        .padding(.all)
    }
}

然後在ContentView改為調用GCMainRow(),這樣代碼就好看很多了。

struct ContentView: View {
    var body: some View {
        GCMainRow()
    }
}

編寫列表 List

好了,現在讓我們來編寫列表視圖吧。我們在最外層使用List包裹GCMainRow,迴圈 20 個視圖,數據多點才可以讓我們滾動。

List(0 ..< 20) { _ in // 1
    GCMainRow()
}

1 - 因為我們不需要用到迴圈的一些數據,所以我們使用 _ 去忽略它。

List控制項預設的都會有邊距,下圖黃色是GCMainRow的大小,可以看得出來旁邊有空白的填充,這對我們當前的設計來說不太友好,因此我們需要想辦法去掉這些邊距填充。

List提供了listRowInsets來控制行的邊距(上下左右),我們來試著使用一下。

List(0 ..< 20) { item in
    GCMainRow()
        .listRowInsets(EdgeInsets())
}

我們發現,這樣寫是沒有作用的,listRowInsets的生效條件是“不能直接在List中使用,需要配合For Each語句才能生效”,我們再修改一下代碼。

List {
    ForEach(0 ..< 20) { item in
        GCMainRow()
            .listRowInsets(EdgeInsets())
    }
}

好了,這次生效了,這就是我們要的結果。

自定義分隔線

我們仔細觀察一下分隔線,在微信里分隔線是左對齊在名稱和消息內容的,所以我們需要把現有的分隔線隱藏掉,然後再實現它。

在這裡講解一下,List是基於UITableView去實現的,這意味著我們可以通過appearance全局修改它的所有屬性,正如我們現在需要取消它預設的分隔線,將separatorStyle設置為.none即可。

init() {
    UITableView.appearance().separatorStyle = .none
}

因為分隔線是貼著右邊緣的,所以我們需要在包裹著名稱、時間、消息內容的VStack外層再包裹一層VStack,在其中再添加分隔線Divider,並將裡層的VStack設定右邊距,最後將最外層的HStackpadding改為上和左邊距。是不是聽得有點懵?沒關係,看看代碼就很容易理解了。

HStack(alignment: .top) { // edit
    // 頭像
    VStack { // new
        VStack(alignment: .leading, spacing: 6) {
            // 名稱、時間、消息內容
        }
        .padding(.trailing) // new
        Divider() // new
    }
}
.padding(.top) // edit
.padding(.leading) // edit

我們現在來看一下效果。

未讀消息小紅點

未讀消息在頭像的右上方,小紅點的中心點是位於頭像的右上頂端。我們可以使用overlay疊加一個視圖,來製作小紅點吧。

Image("1")
		// ...
    .overlay(
        Color.red // 1
            .frame(width: 16, height: 16)
            .cornerRadius(8)
            .offset(x: 23, y: -23) // 2
)

// 1 - Color 本身也是一個視圖組件,這是官方的定義 @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) extension Color : View { }

// 2 - 設定視圖的偏移量,那麼23是怎樣得出來的呢?很簡單,因為預設的overlay視圖是位於父視圖的中心,那麼我們要將它放置在右上角,那麼只需要寬高都除以2就可以了,那麼這裡的結果就是,x軸增加23px,y軸減少23px

接下來是未讀數量,和上面的相似,在Color視圖上利用overlay疊加Text視圖就可以了。

Color.red
    .overlay( // 1
        Text("1")
            .font(.caption)
            .foregroundColor(.white)
)
    .frame(width: 16, height: 16)
    .cornerRadius(8)
    .offset(x: 23, y: -23)

// 1- 值得註意的是,因為文本也是需要偏移到右上角的,所以必須放在前面,不然它預設就是居中的

至此,代碼演示結束,預覽一下靜態圖,文章開頭有 gif 動態圖效果。

總結

好了,這篇文章就到這裡,篇幅有點長了。不過沒關係,我們來總結一下關鍵點:

  1. List預設是有行邊距的,要取消或修改它的行邊距,我們必須通過For Each再配合上listRowInsets才能實現。
  2. List是基於UITableView去實現的,這意味著我們可以通過appearance全局修改它的所有屬性。
  3. 使用overlay可以給視圖疊加一個視圖。

Demo 源碼下載

我已經把 Demo 上傳至 GitHub 上面,項目名字是 SwiftUI-Tutorials,目錄名為GCWechatList,有需要的朋友可以去下載運行一下,當然你也可以跟著文章去做一遍,這樣更有利於你掌握此方面的知識。

文章篇幅有點長,雖然教的東西也挺簡單,但概述得比較詳細。任何東西都是先從簡單入手的,才不會造成勸退不是嗎?哈哈,此文章針對於新手而言還是很友好的,對於已經會的人來講就可能廢話有點多了,如果必須要噴,請輕噴,我比較玻璃心。

如果本文章對你有幫助,請關註我,你的關註就是我後續寫文章的動力,下期會更精彩噢!

關於作者

博文作者:GarveyCalvin

微博:https://weibo.com/feiyueharia

博客園:https://www.cnblogs.com/GarveyCalvin

本文版權歸作者,歡迎轉載,但必須保留此段聲明,並給出原文鏈接,謝謝合作!

公眾號

作者第一次運營公眾號,請你們一定要關註我的公眾號,給我點動力,後期主要運營公眾號為主。這是第二篇發佈的文章,需要你們的支持,謝謝你們!

QQ群

一起討論 SwiftUI,群主喜歡看熱鬧,當吃瓜人員。進來時填寫你在哪裡看到此文章的,並介紹下自己,一句話就行。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.版本選取 訪問mongodb的鏡像倉庫地址:https://hub.docker.com/_/mongo?tab=tags&page=1 這裡選取最新版本進行安裝,如果想安裝其他的可用版本,可以使用命令“docker search mongo”來查看 2.拉取最新版本鏡像 這裡執行命令"sudo ...
  • https://www.cnblogs.com/aspirant/p/9214485.html 一步步分析為什麼B+樹適合作為索引的結構 以及索引原理 mysql的B+樹索引 查找使用了二分查找,redis 跳錶也使用了二分查找法,kafka查詢消息日誌也使用了二分查找法,二分查找法時間複雜度O(l ...
  • 表結構 student(StuId,StuName,StuAge,StuSex) 學生表 teacher(TId,Tname) 教師表 course(CId,Cname,C_TId) 課程表 sc(SId,S_CId,Score) 成績表 問題十:查詢沒有學全所有課的同學的學號、姓名 SELECT ...
  • Redis Cluster是Redis在3.0版本正式推出的專用集群方案,有效地解決了Redis分散式方面的需求,讓我們一起快速搭建出分散式高可用的Redis集群吧! ...
  • Redis的字典使用哈希表作為底層實現,一個哈希表中可以有多個哈希表節點,而每個哈希節點就保存在字典中的一個鍵值對。 redis字典所用的哈希表由disht結構定義。 typedef struct dictht{ dictEntry **table;//哈希表數組 unsigned long siz ...
  • 一、動態規劃界面的大小 1.我們在res的文件夾裡面創建一個新的文件夾large_fragment用來,然後寫一個界面,activity_main.xml文件,用於存儲平板電腦等一些解析度高的界面。也就是說小屏幕使用正常activity_main文件、大屏幕就使用large_fragment文件夾里 ...
  • 一、項目概述 flutter-chatroom是採用基於flutter+dart+chewie+image_picker+photo_view等技術跨端開發仿微信app界面聊天室項目。實現了消息發送/動態gif表情、彈窗、圖片預覽、紅包/朋友圈/小視頻號等功能。 二、技術框架 編碼/技術:Vscod ...
  • layer-list : 簡單來說layer-list就是圖層列表的意思,是用來創建LayerDrawable的,LayerDrawable是DrawableResource的一種,所以,layer-list創建出來的是"圖層列表",也就是一個drawable圖形``` ... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...