使用 UIViewControllerRepresentable 时 UIViewController 子视图的大小/布局不正确(没有情节提要)
Posted
技术标签:
【中文标题】使用 UIViewControllerRepresentable 时 UIViewController 子视图的大小/布局不正确(没有情节提要)【英文标题】:UIViewController subview incorrect size/layout when using UIViewControllerRepresentable (without storyboard) 【发布时间】:2021-09-06 22:22:39 【问题描述】:我正在尝试使用 tapRecognizer 和 UITextView 构建并集成到自定义 UIViewController。
我面临的问题是 UITextView 将部分文本显示在屏幕外,我不知道是什么原因造成的!我期待一些简单的东西,或者可能包括更多的课程,但我还没有找到任何指向我正确方向的东西。
UITextView 的大小/位置在使用 UIViewRepresentable 和 UITextView 时运行良好,但由于某些原因不能在其中使用 UIViewController / UIViewControllerRepresentable 和 UITextView(参见下面的示例以进行比较)。
这是我拥有的测试应用程序的代码:
import SwiftUI
import UIKit
struct TestingView: View
var body: some View
VStack
WrappedUIViewController().padding()
Spacer()
WrappedUITextView(myText: "This is a long text to see if the word wrap work in this case better I hope so but I don't know. Is it? I hope it is, ! Do you? I do! Hope you do too, do you?").padding()
Spacer()
struct WrappedUITextView: UIViewRepresentable
let myText: String
func makeUIView(context: Context) -> UITextViewPlus
let view = UITextViewPlus()
view.isScrollEnabled = true
view.isEditable = false
view.isUserInteractionEnabled = true
view.font = UIFont(name: "Time New Roman", size: 20)
view.isOpaque = false
view.text = "WrappedUITextView \(myText)"
return view
func updateUIView(_ uiView: UITextViewPlus, context: Context)
struct WrappedUIViewController: UIViewControllerRepresentable
typealias UIViewControllerType = CustomUIViewController
func makeUIViewController(context: Context) -> CustomUIViewController
return CustomUIViewController()
func updateUIViewController(_ uiViewController: CustomUIViewController, context: Context)
class CustomUIViewController: UIViewController
var textView: UITextView = UITextView()
var tapGesture: UITapGestureRecognizer!
override func viewDidLoad()
super.viewDidLoad()
tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(recognizer:)))
self.textView.addGestureRecognizer(tapGesture)
self.textView.isEditable = false
self.textView.isSelectable = false
self.textView.clipsToBounds = true
self.textView.text = """
This is some text that will need to be displayed on multiple lines as it's longer than the screen size, will it wrapp correctly?
This is a great testing app
This is the end of this textView content
Here is a Potato
"""
self.textView.backgroundColor = UIColor.green
self.textView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.textView.textContainer.lineBreakMode = .byWordWrapping
view.addSubview(self.textView)
@objc func handleTap(recognizer: UITapGestureRecognizer)
let location: CGPoint = recognizer.location(in: textView)
let position: CGPoint = CGPoint(x: location.x, y: location.y)
let tapPosition: UITextPosition = textView.closestPosition(to: position)!
guard let textRange: UITextRange = textView.tokenizer.rangeEnclosingPosition(tapPosition, with: UITextGranularity.word, inDirection: UITextDirection(rawValue: 1)) else return
let tappedWord: String = textView.text(in: textRange) ?? ""
print("tapped word -> \(tappedWord)")
override func viewWillLayoutSubviews()
textView.sizeThatFits(self.view.bounds.size)
textView.sizeToFit()
由于某些原因,绿色 textView 没有正确包裹文本或尺寸超出屏幕:
我是 swift 和 ios 的新手,所以如果我做错了什么,我不会感到惊讶,欢迎任何帮助!
编辑:如果其他文件的代码有助于解决这个问题(我对此表示怀疑):
import SwiftUI
@main
struct testAppApp: App
var body: some Scene
WindowGroup
Text("Test App")
TestingView()
【问题讨论】:
这快把我逼疯了!除了给我的 UITextView 提供一个固定框架以确保它不会超出屏幕之外,没有其他方法吗? 我认为这是因为在 UIViewController 中您需要添加约束以正确对齐您的 UITextView,无论是编程方式还是在情节提要上 你给了我一些有趣的东西,可悲的是,添加约束似乎会导致更多问题。我与现有约束发生冲突。我用这篇文章添加了约束:***.com/questions/33072969/… 我已对您的代码进行了更改并将其发布为答案,希望这能解决您的问题。 【参考方案1】:我已对您的 CustomViewController 类进行了更改,并为您的 textview 添加了约束以使其正确对齐。我添加的方法和代码行已注释
你必须告诉自动布局你希望你的视图如何对齐和定位,否则一切都会混乱。
class CustomUIViewController: UIViewController
var textView: UITextView = UITextView()
var tapGesture: UITapGestureRecognizer!
override func viewDidLoad()
super.viewDidLoad()
tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(recognizer:)))
self.textView.addGestureRecognizer(tapGesture)
self.textView.isEditable = false
self.textView.isSelectable = false
self.textView.clipsToBounds = true
self.textView.text = """
This is some text that will need to be displayed on multiple lines as it's longer than the screen size, will it wrapp correctly?
This is a great testing app
This is the end of this textView content
Here is a Potato
"""
self.textView.backgroundColor = UIColor.green
self.textView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.textView.textContainer.lineBreakMode = .byWordWrapping
self.textView.translatesAutoresizingMaskIntoConstraints = false //ADDED: allows view to obey Auto Layout constraints.
view.addSubview(self.textView)
addConstraints() //ADDED: method for invoking constraints
func addConstraints()
let margins = view.layoutMarginsGuide //safe area layout - esp for devices with notch
NSLayoutConstraint.activate([
textView.topAnchor.constraint(equalTo: margins.topAnchor), //textview's top anchor = that of parent view
textView.leadingAnchor.constraint(equalTo: margins.leadingAnchor),
textView.heightAnchor.constraint(equalToConstant: 200), //gave textview a constant height
textView.trailingAnchor.constraint(equalTo: margins.trailingAnchor)
])
@objc func handleTap(recognizer: UITapGestureRecognizer)
let location: CGPoint = recognizer.location(in: textView)
let position: CGPoint = CGPoint(x: location.x, y: location.y)
let tapPosition: UITextPosition = textView.closestPosition(to: position)!
guard let textRange: UITextRange = textView.tokenizer.rangeEnclosingPosition(tapPosition, with: UITextGranularity.word, inDirection: UITextDirection(rawValue: 1)) else return
let tappedWord: String = textView.text(in: textRange) ?? ""
print("tapped word -> \(tappedWord)")
override func viewWillLayoutSubviews()
textView.sizeThatFits(self.view.bounds.size)
textView.sizeToFit()
【讨论】:
感谢您提供此代码。来自 swiftUI 我发现很难将我的头脑围绕在“旧的做事方式”上。我会玩弄你给我的东西,看看我是否可以让视图只包裹文本,仅此而已! 很高兴我可以帮助@Slamit,如果以上解决了您的问题,请考虑将其标记为答案 我没有设法让视图环绕文本,同时保持在屏幕上的约束:(。我会继续玩跳跃我可能会管理它:-)【参考方案2】:经过多次迭代,我设法得到了一些可行的方法,实际上有 2 个选项可以解决这个问题:
-
在 viewDidLoad 中将“view.addSubview(self.textView)”更改为“view.= self.textView”。我不确定这个变化是什么,但有了这个我有 UITextview 由系统调整。
override func viewDidLoad()
super.viewDidLoad()
...
view = self.textView
-
第二个也是最有可能“更好”的解决方案:在 viewDidLoad 中为我的 UITextView 设置一个框架。当“textView.sizeToFit()”时,高度会被添加,而宽度会保持在我想要的范围内:
override func viewDidLoad()
super.viewDidLoad()
...
self.textView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 10000)
...
view.addSubview(self.textView)
【讨论】:
以上是关于使用 UIViewControllerRepresentable 时 UIViewController 子视图的大小/布局不正确(没有情节提要)的主要内容,如果未能解决你的问题,请参考以下文章
在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?
Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)