如何创建三个等宽的Button

我们之前有解释过,SwiftUI中,有public protocol Layout : Animatable,我们可以通过这个协议来自定义。

其实,我们在UIKit中如何定义三个拥有同等宽度的按钮呢?我们的思路会是:

  1. 获取每个Button中的文案
  2. 然后计算出这个字体下,这些文案的宽度
  3. 缓存最大的按钮宽度,然后赋予其他的按钮,并设定为他们的宽。

但是,到了SwiftUI的话,我们只需要自定义Layout,然后在里面去实现我们的规则。具体思路如下:

  1. 获取每个子视图的宽度,然后得到最宽的子视图的大小。
  2. 当然我们还需要获取每个子视图之间的spacing。
  3. 最后通过placeSubviews, 将所有的子视图的size都替换为最大的button。

代码如下:

struct MyEqualWidthHStack: Layout {
    
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
        let maxSize = self.maxSize(from: subviews)
        let totalSpacing = spacing(by: subviews).reduce(0) { $0 + $1 }
        return CGSize(
            width: maxSize.width * CGFloat(subviews.count) + totalSpacing,
            height: maxSize.height
        )
    }
    
    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
        let maxSize = self.maxSize(from: subviews)
        let spacings = self.spacing(by: subviews)
        
        let placementProposal = ProposedViewSize(width: maxSize.width, height: maxSize.height)
        var x: CGFloat = bounds.minX + maxSize.width / 2
        for index in subviews.indices {
            subviews[index].place(
                at: CGPoint(x: x, y: bounds.minY),
                anchor: .center,
                proposal: placementProposal
            )
            x += maxSize.width + spacings[index]
        }
    }
    
}
​
extension MyEqualWidthHStack {
​
    func maxSize(from subviews: Subviews) -> CGSize {
        let subViewSizes = subviews.map { $0.sizeThatFits(.unspecified) }
        return subViewSizes.reduce(CGSize.zero) { currentMax, subViewSize in
            return CGSize(
                width: max(currentMax.width, subViewSize.width),
                height: max(currentMax.height, subViewSize.height)
            )
        }
    }
    
    func spacing(by subviews: Subviews) -> [CGFloat] {
        subviews.indices.compactMap { index in
            guard index < subviews.count - 1 else { return 0 }
            return subviews[index].spacing.distance(to: subviews[index + 1].spacing, along: .horizontal)
        }
    }
    
}

值得一提的是,当我们调用如上的MyEqualWidthHStack的时候,会发现不生效,如下:

import SwiftUI
​
struct ButtonStack: View {
    
    let titles = ["Cat", "Goldfish", "Dog"]
    
    var body: some View {
        MyEqualWidthHStack {
            ForEach(titles.indices, id: .self) { index in
                Button {
                    
                } label: {
                    Text(titles[index])
                        // .frame(maxWidth: .infinity)
                }
                .buttonStyle(.bordered)
            }
        }
    }
}

当注释掉.frame(maxWidth: .infinity)modifier的时候,我们会发现button还是按照文本内容进行填充的。这个是因为,如果我们不设定frame的话,SwiftUI会进行默认布局,即按照内容进行填充。只有设定了frame之后,SwiftUI才会真的按照我们的自定义Layout进行布局。

如果有理解不到位的地方,欢迎解答。

阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=20230,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?