• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • SwiftUI自動換行HStack

    標簽: ios  swift  swiftUI

    有時候,我們會遇到類似這樣的需求在這里插入圖片描述,其中一種實現方式就是對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()
        }
    }
    
    
    版權聲明:本文為qq_42568693原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/qq_42568693/article/details/105569293

    智能推薦

    WPF Textbox自動換行

    最近用WPF開發應用時,想將從云端傳回來的數據顯示在一個Textbox中,但是發現當數據較長時,Textbox顯示不全的問題,就像下圖這樣: 解決方法 搜了一些解決方法,涉及到要寫style,感覺有點麻煩,最后綜合了幾篇博客的回答,發現只需要添加兩個屬性,問題就可以迎刃而解: 設置MaxWidth和TextWrapping屬性即可。 效果圖是這樣的:...

    TextView 判斷自動換行

    先看 需求: 布局中有四種樣式 (標簽必須在一起 不能截斷) 因為沒辦法用字段區分這四種類型, 所以只能用一個item布局實現效果 原理是這樣的, 主要是中間的內容 跟后面的標簽 會出現這樣的問題, 項目中解決的方案是 用兩個TextView : content 和 label , content動態計算, 計算換行邏輯: content +label 一行 或者 label不截斷的情況下兩行 或...

    ul自動換行

    未設置換行時,頁面變窄會被遮住部分 設置后,頁面變窄會自動換到下一行...

    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...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    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壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...

    精品国产乱码久久久久久蜜桃不卡