UIViewRepresentable及其内容的内在大小。

问题描述 投票:-1回答:1

我已经创建了一个 UIViewRepresentable 对于 UIVisualEffectView 以使某些组件充满活力。这很有效,但它似乎有时会垂直收缩控件,或者在运行时随机改变它们的边界。我似乎无法让它可靠地工作。我需要这个功能能在任何SwiftUI内容甚至是其他内容上工作。UIViewRepresentable 用来代替内容。包裹 UIVisualEffectViewUIView 并使用自动布局似乎有帮助,但其他控件(如自定义的 UILabel 裹挟 UIViewRepresnetable 被垂直剪切)。)

public struct VibrantView<Content: View>: UIViewRepresentable {
  private let content: UIView!

  private let vibrancyBlurEffectStyle: UIBlurEffect.Style

  init(vibrancyBlurEffectStyle: UIBlurEffect.Style, @ViewBuilder content: () -> Content) {
    self.content = UIHostingController(rootView: content()).view

    self.vibrancyBlurEffectStyle = vibrancyBlurEffectStyle
  }

  public func makeUIView(context: Context) -> UIView {
    let containerView = UIView()

    let blurEffect = UIBlurEffect(style: vibrancyBlurEffectStyle)
    let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
    let blurView = UIVisualEffectView(effect: vibrancyEffect)

    blurView.translatesAutoresizingMaskIntoConstraints = false
    containerView.addSubview(blurView)

    content.backgroundColor = .clear
    content.translatesAutoresizingMaskIntoConstraints = false
    blurView.contentView.addSubview(content)

    NSLayoutConstraint.activate([
      blurView.widthAnchor.constraint(equalTo: containerView.widthAnchor),
      blurView.heightAnchor.constraint(equalTo: containerView.heightAnchor),

      content.widthAnchor.constraint(equalTo: blurView.widthAnchor),
      content.heightAnchor.constraint(equalTo: blurView.heightAnchor),
    ])

    content.setContentHuggingPriority(.defaultLow, for: .vertical)
    content.setContentHuggingPriority(.defaultLow, for: .horizontal)
    content.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
    content.setContentCompressionResistancePriority(.defaultHigh, for: .vertical)

    blurView.setContentHuggingPriority(.defaultLow, for: .vertical)
    blurView.setContentHuggingPriority(.defaultLow, for: .horizontal)
    blurView.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
    blurView.setContentCompressionResistancePriority(.defaultHigh, for: .vertical)

    return containerView
  }

  public func updateUIView(_ uiView: UIView, context: Context) {
  }
}

用作。

  ...

  VibrantView(vibrancyBlurEffectStyle: .dark) {
    Text("Hello")
      .foregroundColor(Color.gray)
  }

当在设备上运行时,与其他视图一起运行在一个... VStack你会看到 "Hello "从底部被剪掉一部分。在预览中,你会看到 "Hello "周围有一个大得多的蓝色矩形(bounds),而我希望这个矩形能紧贴内容。该 VStack 不假定整体视图的全部自然高度。

使用 fixedSize() 不起作用,而且与其他控件一起使用时,会产生更奇怪的结果。

swift autolayout swiftui
1个回答
1
投票

在尝试了各种技术和黑客之后--我根本无法让UIKit容器(即. VibrantView)可靠地拥抱它的SwiftUI内容,而不添加一个固定大小的控件。.frame(...) 修饰符在上面--这使得它很难与动态大小的 Text.

对我来说,我的工作是一个有点黑客的工作,可能不会对每一个通用的视图工作(可能不会对几十个视图进行很好的扩展),但对简单的用例很好,特别是如果你在一个动态大小的 UITableViewCell.

我们的想法是使用相同视图的虚拟版本,并设置了 VibrantView 在...中 .overlay( ... ). 这将迫使覆盖层与父SwitfUI的整体大小相同。View. 由于所应用的视图是同一视图的副本,而该视图的 VibrantView 包裹,你最终在运行时和Xcode预览中得到正确的动态大小。

所以像这样。

  SomeView()
    .frame(minWidth: 0, maxWidth: .infinity)
    .overlay(
      VibrantView(vibrancyBlurEffectStyle: .dark) {
        SomeView()
         .frame(minWidth: 0, maxWidth: .infinity)
      }
  )

我可以想象把它变成一个修改器,这样它就能在一次调用中封装上面的内容,但在我的例子中,为了确保它对Images的性能,我正在做这样的事情。

  Circle()
    .foregroundColor(.clear)
    .frame(width: 33, height: 33)
    .overlay(
      VibrantView(vibrancyBlurEffectStyle: .systemMaterialDark) {
        Image("some image")
          .resizable()
      }
  )

创建一个 Circle 与实际图像相比,可以说是轻车熟路。我创建了一个透明的圆圈,在那里设置图像的实际大小,然后再把 VibrantView 容器中的 overlay.


0
投票

为什么这么复杂?

试试这个。

struct Blur: UIViewRepresentable {
    #if os(iOS)
    var style: UIBlurEffect.Style = .systemMaterial
    #else
    var style: UIBlurEffect.Style = .light
    #endif

    init(_ style: UIBlurEffect.Style = .dark) {
        self.style = style
    }

    func makeUIView(context: Context) -> UIVisualEffectView {
        return UIVisualEffectView(effect: UIBlurEffect(style: style))
    }
    func updateUIView(_ uiView: UIVisualEffectView, context: Context) {
        uiView.effect = UIBlurEffect(style: style)
    }
}

并使用:

 Text("Great text with prominent")
                    .font(.largeTitle)
                    .padding()
                    .background(Blur(.prominent))

一般来说,你不应该在UIViewRepresentable -&gt中使用约束条件;大小将由父视图定义,比如本例中的Text或VStack,他们会给模糊提供合适的大小。通常模糊不是独立存在的,但典型的是模糊的背景,因为你想把文字放在上面,这样你就可以更好的阅读文字。

© www.soinside.com 2019 - 2024. All rights reserved.