首页 > 解决方案 > SwiftUI 视图大小(父/子关系)

问题描述

我正在通过一些示例来熟悉 SwiftUI,但我遇到了大小问题。

我已经习惯了 UIKit 处理调整视图大小的方式,使用 AutoLayout 你基本上可以为其子级设置父级大小。SwiftUI 似乎并非如此。

我读过的所有内容都显示了如何在孩子身上使用 GeometryReader 来获取其父母的大小,这表明孩子可以选择自己的大小,但我还没有看到如何从父母那里获得孩子的大小.

假设我有以下代码:

struct ContentView: View {
    var body: some View {
        Text("This is Text").ripple(rippleColor: .lightGray, rippleOpacity: 0.5)
    }
}

ripple()是一个扩展函数,它添加了一个自定义ViewModifier,将内容覆盖到UIViewRepresentable视图上,以便在点击时创建材质波纹效果。

struct RippleModifier: ViewModifier {
    let rippleColor: UIColor
    let rippleOpacity: Float

    func body(content: Content) -> some View {
        RippleView(
            rippleColor: rippleColor,
            rippleOpacity: rippleOpacity
        )
        .overlay(content)
    }
}

extension View {
    func ripple(rippleColor: UIColor, rippleOpacity: Float) -> some View {
        modifier(
            RippleModifier(
                rippleColor: rippleColor,
                rippleOpacity: rippleOpacity
            )
        )
    }
}

我遇到的问题是,当我只有 时Text,它会将其框架设置为适合其内容(字符串)。当我向它添加.ripple()修改器时,框架就变成了整个屏幕。

使用 UIKit,我只需添加一些约束来将 UILabel 固定到父级,我会让它决定父级的大小。

有没有办法使用 SwiftUI?

奖金问题:

相关但不相关,我如何让点击进入Text它覆盖的视图?当点击视图框架内的任何位置时,波纹将激活并正确动画,但直接点击文本本身除外。

编辑:

这是 UIViewRepresentable 视图的部分代码。

struct RippleView: UIViewRepresentable {
    var rippleColor: UIColor = .systemGray
    var rippleOpacity: Float = 0.5

    func makeUIView(context: Context) -> UIRippleView {
        UIRippleView()
    }

    func updateUIView(
        _ uiView: UIRippleView,
        context: UIViewRepresentableContext<RippleView>
    ) {
        uiView.rippleColor = rippleColor
        uiView.rippleOpacity = rippleOpacity
    }
}

open class UIRippleView: UIView {
    open var rippleColor: UIColor = .systemGray {
        didSet {
            rippleLayer.fillColor = rippleColor.cgColor
        }
    }

    open var rippleOpacity: Float = 0.5 {
        didSet {
            rippleLayer.opacity = rippleOpacity
        }
    }

    private lazy var rippleLayer: CAShapeLayer = {
        let layer = CAShapeLayer()
        layer.opacity = 0.0

        self.layer.insertSublayer(layer, at: 0)

        return layer
    }()

    public override init(frame: CGRect) {
        super.init(frame: frame)
        clipsToBounds = true
    }

    public required init?(coder: NSCoder) {
        super.init(coder: coder)
        clipsToBounds = true
    }
}

该视图有一个扩展,它覆盖了触摸函数来计算点击发生的位置并执行动画,但这只是修改pathrippleLayer.

标签: iosswiftxcodeswiftui

解决方案


你可以改成overlay这样background

struct RippleModifier: ViewModifier {
    let rippleColor: UIColor
    let rippleOpacity: Float

    func body(content: Content) -> some View {
        content.background(
            RippleView(
                rippleColor: rippleColor,
                rippleOpacity: rippleOpacity
        ))
    }
}

因此,从而不是相反的方式RippleView获取大小约束。content


推荐阅读