UIViewRepresentable и его содержание свойственно c размер - PullRequest
0 голосов
/ 01 мая 2020

Я создал UIViewRepresentable для UIVisualEffectView, чтобы сделать некоторые компоненты живыми. Это работает, однако кажется, что время от времени сокращает элементы управления по вертикали или просто произвольно изменяет их границы во время выполнения. Я не могу заставить его работать надежно. Мне это нужно для работы с любым содержимым SwiftUI или даже с другим UIViewRepresentable, используемым вместо содержимого. Обертывание UIVisualEffectView внутри UIView и использование автоматического макета, похоже, помогают, но другие элементы управления (такие как пользовательский 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», тогда как я хотел бы, чтобы это обнимало содержимое. VStack не предполагает полную естественную высоту общего вида.

Использование fixedSize() не работает и дает еще более странные результаты при использовании с другими элементами управления.

Ответы [ 2 ]

0 голосов
/ 02 мая 2020

Попробовав различные приемы и приемы - я просто не смог заставить контейнер UIKit (т.е. VibrantView) надежно обнять содержимое SwiftUI, не добавив модификатор .frame(...) фиксированного размера сверху - что затрудняет его использование с динамическим размером Text.

То, что сработало для меня, было чем-то вроде хака и, вероятно, не сработает для каждого общего вида c (и, вероятно, не будет хорошо масштабироваться для десятков просмотров), но хорошо работает для простые варианты использования, особенно если вы размещаете это внутри динамически изменяемого размера UITableViewCell.

. Идея состоит в том, чтобы использовать фиктивную версию того же представления и установить VibrantView в .overlay( ... ) , Это заставит оверлей принять тот же общий размер родительского SwitfUI View. Поскольку применяемое представление модификатор является копией того же представления, которое переносит VibrantView, вы получите правильный динамический размер c во время выполнения и в предварительном просмотре Xcode.

Итак, что-то вроде этого:

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

Я могу себе представить, что могу превратить это в модификатор, чтобы обернуть вышеупомянутое в один вызов, но в моем случае, чтобы убедиться, что он остается производительным для изображений, я делаю что-то вроде этого:

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

Создание Circle возможно более легкий вес по сравнению с реальным изображением. Я создаю прозрачный круг, устанавливаю фактический размер изображения и помещаю контейнер VibrantView в overlay.

0 голосов
/ 01 мая 2020

почему так сложно?

попробуйте это:

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 -> size будет определяться родительским представлением, таким как Text в этом примере или VStack, который дает правильный размер для размытия. Обычно размытие не само по себе, но типичным является размытый фон, потому что вы хотите нанести на него текст, чтобы лучше его прочитать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...