SwiftUI自動換行HStack
有時候,我們會遇到類似這樣的需求,其中一種實現方式就是對alignmentGuide的靈活運用,如果您不太清楚剛剛這個名字的意思,我推薦您先看看我的這篇文章,算是alignmentGuide的基礎
博客地址:alignmentGuide基礎
寫在前面
代碼來自https://stackoom.com/question/3ytbp/帶包裝的SwiftUI-HStack
如侵權請聯系我刪除。
我添加了一些關鍵的打印語句和大量注釋來探索這份代碼。
正文
先貼出源碼,如果看著比較費勁可以跳過這部分,直接看我加了一些注釋的版本
import SwiftUI
struct TestWrappedLayout: View {
@State var platforms = ["Ninetendo", "XBox", "PlayStation", "PlayStation 2", "PlayStation 3", "PlayStation 4"]
var body: some View {
GeometryReader { geometry in
self.generateContent(in: geometry)
}
}
private func generateContent(in g: GeometryProxy) -> some View {
var width = CGFloat.zero
var height = CGFloat.zero
return ZStack(alignment: .topLeading) {
ForEach(self.platforms, id: \.self) { platform in
self.item(for: platform)
.padding([.horizontal, .vertical], 4)
.alignmentGuide(.leading, computeValue: { d in
if (abs(width - d.width) > g.size.width)
{
width = 0
height -= d.height
}
let result = width
if platform == self.platforms.last! {
width = 0 //last item
} else {
width -= d.width
}
return result
})
.alignmentGuide(.top, computeValue: {d in
let result = height
if platform == self.platforms.last! {
height = 0 // last item
}
return result
})
}
}
}
func item(for text: String) -> some View {
Text(text)
.padding(.all, 5)
.font(.body)
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(5)
}
}
struct TestWrappedLayout_Previews: PreviewProvider {
static var previews: some View {
TestWrappedLayout()
}
}
我們一起來閱讀這份源碼(加了注釋的版本)
import SwiftUI
struct TestWrappedLayout: View {
//@State標明 當這個platforms發生變化的時候視圖進行自動的更新,這個不懂不影響我們閱讀代碼
@State var platforms = ["Ninetendo", "XBox", "PlayStation", "PlayStation 2", "PlayStation 3", "PlayStation 4"]
//幾何閱讀器GeometryReader:捕獲了一個滿足GeometryProxy協議的變量,該協議提供安全區插圖和View的size(簡單點說就是這個東西能捕獲當前Container的一些參數,這個Container一般指的是HStack,VStack,ZStack等等)
var body: some View {
GeometryReader { geometry in
self.generateContent(in: geometry)//將捕獲到的Container傳遞給generateContent函數返回一個View:這個函數在下面定義
}
}
/// - Parameter g: 一個滿足GeometryProxy協議的變量:這個變量就是Container本身
/// - Returns: 一個View
private func generateContent(in g: GeometryProxy) -> some View {
var width = CGFloat.zero//width初始值為0
var height = CGFloat.zero//height初始值為0
return ZStack(alignment: .topLeading) {//ZStack滿足.topLeadingalignment
//實現思路:每個視圖寬度+本視圖的原定起點如果大于g的寬度則換行,否則按照原定起點進行放置
//具體:對齊引導1: width = 0,height = 0,第一個View的左邊就緊挨著Container左邊框,然后width = width + View1的寬度;第二個View的左邊就向右偏移width個單位,然后width = width + View2;然后第三個。。。。。。以此類推可以得到一行內的全部正確約束
//對齊引導2: height = 0, 在進行對齊引導1的時候如果某個View的寬度+原定偏移量超出了Container的寬度那么height = height + View的高度。。。。。。以此類推可以得到每行的約束
//注意?:由于alignmentGuide中的代碼會被調用多次,所以當最后一個元素被成功約束之后需要將width,height清0以保證下一輪的約束正確
//注意?:偏移量取負值,也就是computeValue的返回值取負值表示向右偏移,取負值表示向下偏移
//
ForEach(self.platforms, id: \.self) { platform in
self.item(for: platform)/*item方法將一個個數據轉成一個個View*/
.padding([.horizontal, .vertical], 4)
.alignmentGuide(.leading, computeValue: { d in/*這里的d指的是每一個文本視圖(子視圖)*/
if (abs(width - d.width) > g.size.width)/*這里的g指的是Container視圖(父視圖)*/
{
width = 0
height -= d.height
}
//您可以取消這里的注釋來自己看看這些參數的值大概是多少,實體運行才能看到哦,右邊的預覽是看不到打印值的
// print("當前width",width)
// print("當前d.width",d.width)
// print("當前g.size.widht",g.size.width)
// print("\n")
let result = width
if platform == self.platforms.last! {
width = 0 //最后一個元素:由于Swift的‘=’是值傳遞,所以這里width被置為0,但最后一個元素的返回值依然是正常的而不是0
// print("正在約束的是",platform)
} else {
width -= d.width
}
print("正在約束的是",platform)
return result
})
.alignmentGuide(.top, computeValue: {d in
let result = height
if platform == self.platforms.last! {
height = 0 // last item
}
return result
})
}
}
}
func item(for text: String) -> some View {
Text(text)
.padding(.all, 5)
.font(.body)
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(5)
}
}
struct TestWrappedLayout_Previews: PreviewProvider {
static var previews: some View {
TestWrappedLayout()
}
}
智能推薦
WPF Textbox自動換行
最近用WPF開發應用時,想將從云端傳回來的數據顯示在一個Textbox中,但是發現當數據較長時,Textbox顯示不全的問題,就像下圖這樣: 解決方法 搜了一些解決方法,涉及到要寫style,感覺有點麻煩,最后綜合了幾篇博客的回答,發現只需要添加兩個屬性,問題就可以迎刃而解: 設置MaxWidth和TextWrapping屬性即可。 效果圖是這樣的:...
TextView 判斷自動換行
先看 需求: 布局中有四種樣式 (標簽必須在一起 不能截斷) 因為沒辦法用字段區分這四種類型, 所以只能用一個item布局實現效果 原理是這樣的, 主要是中間的內容 跟后面的標簽 會出現這樣的問題, 項目中解決的方案是 用兩個TextView : content 和 label , content動態計算, 計算換行邏輯: content +label 一行 或者 label不截斷的情況下兩行 或...
ios 自動換行flowLayout
android 自動換行flowLayout 最近產品需要實現自動換行功能,在gitHub看了一下,雖然有不少,但都有那么一點不滿足需求的,或者感覺用著不方便的。所以干脆自己寫了一份,順便在有時間時寫了一份ios的版本,有興趣想看android版的的可點擊上面鏈接。 在這里先提供下載地址:https://github.com/lanqi-x/ios_FlowLayout 然后來個圖先: 實現概要思...
android 自動換行FlowLayout
ios 自動換行FlowLayout 最近產品需要實現自動換行功能,在gitHub看了一下,雖然有不少,但都有那么一點不滿足需求的,或者感覺用著不方便的。所以干脆自己寫了一份,順便有時間寫了一份ios的版本,有興趣的可點擊上面鏈接。 在這里先提供下載地址:https://github.com/lanqi-x/flowLayout 然后來個圖先: 實現概要思路為1、繼承ViewGroup,...
猜你喜歡
Eclipse的自動換行
一,情況描述 今天打開代碼,發現變成了這樣: 原來是這樣的: 搜索了一番,才知道我是不小心用了 [代碼自動對齊] / [自動排版] 功能. 二.應用 [自動排版] 功能 快捷鍵“Ctrl+shift+f” 三.取消 [自動排版] 功能 在網站上查的解決方法是:window-&g...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...