xamarin 活动UITextView在UIScrollView中移动

svgewumm  于 2023-06-03  发布在  其他
关注(0)|答案(1)|浏览(193)

我有一个2000像素宽的大型滚动画布,长度不受限制,其中有一个大型UIView。
您可以与UIView交互以添加对象(线条,形状,文本框,图像,PDF等)。
当您添加一个文本框时,我创建了UITextView的一个子类,它被配置为随文本自动增长--宽度限制为600 px,长度不受限制(您可以强制它变宽)。关键点- UITextViews从不在内部滚动。
我遇到的问题是移动UIscrollview(即大画布)以保持活动文本框的光标可见。当你在一个有限宽度的显示器上(比如iPhone),你应该能够点击一个文本框并开始打字。滚动视图应该四处移动以保持当前光标(文本输入点)在屏幕上,即使UITextView非常宽。
这并不太难-我有一个UITextViewDelegate,它有一个“DidChangeSelection:“函数。当选择移动并且委托方法被调用时-我找到当前光标(SelectedTextRange),将其转换为rect(GetFirstForRange),然后从UITextView坐标转换为UIView坐标(ConvertToView),然后请求UIScrollView作为该rect进入视图(ScrollToVisible)。
奇怪的是,即使我的rect是正确的-UITextView总是对齐,所以最右边的边缘是可见的。因此,如果UITextView的宽度为1000 px,而UIScrollView的可见部分仅为500 px,则只能看到UITextView的½部分。无论光标在哪里,UIScrollView都会滚动,以便UITextView的右侧始终可见。
当UITextView是活动控件时,它似乎试图使自己可见,但它似乎总是试图“ScrollToRect”到其全宽,如果UITextView比可见区域宽,则UIScrollView似乎总是显示右侧。我之所以知道这一点,是因为我可以关闭我的代理,并且UITextView确实会滚动到视图中,但只是在右侧。
这是标准行为吗?理想情况下,我希望关闭自动将活动UITextView滚动到视图中的任何机制,以便使用正确的ScrollToRect调用。
谢谢你能给予我的任何建议。干杯

sz81bmfz

sz81bmfz1#

有几个选择可以尝试…
首先,子类UIScrollView

class MyScrollView: UIScrollView {
    override func scrollRectToVisible(_ rect: CGRect, animated: Bool) {
        // don't do anything
    }
}

这将防止内置的“自动滚动”时,文本视图是活跃的。
第二种选择:

  • 在“容器滚动视图”中嵌入文本视图
  • 禁用 that 滚动视图的滚动
  • 将文本视图约束为滚动视图的.frameLayoutGuide,以便文本视图控制容器滚动视图的大小
  • 将容器滚动视图添加为“内容”视图的子视图

现在,当文本视图处于“活动”状态时,它的“容器”滚动视图将接收自动滚动消息,而不是“主”滚动视图。
当然,在任何一种情况下,您的代码都将负责管理保持插入点可见所需的任何水平/垂直滚动。

编辑

第二个选项的快速示例:

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let tv = UITextView()
        let tvsv = UIScrollView()
        let cv = UIView()
        let sv = UIScrollView()
        
        [tv, tvsv, cv, sv].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
        }
        tvsv.addSubview(tv)
        cv.addSubview(tvsv)
        sv.addSubview(cv)
        view.addSubview(sv)
        
        let g = view.safeAreaLayoutGuide
        let cg = sv.contentLayoutGuide
        let fg = sv.frameLayoutGuide
        
        let tsfg = tvsv.frameLayoutGuide
        
        NSLayoutConstraint.activate([
            
            tv.topAnchor.constraint(equalTo: tsfg.topAnchor, constant: 0.0),
            tv.leadingAnchor.constraint(equalTo: tsfg.leadingAnchor, constant: 0.0),
            tv.trailingAnchor.constraint(equalTo: tsfg.trailingAnchor, constant: 0.0),
            tv.bottomAnchor.constraint(lessThanOrEqualTo: tsfg.bottomAnchor, constant: 0.0),
            
            tv.widthAnchor.constraint(equalToConstant: 600.0),

            tvsv.topAnchor.constraint(equalTo: cv.topAnchor, constant: 20.0),
            tvsv.leadingAnchor.constraint(equalTo: cv.leadingAnchor, constant: 20.0),
            tvsv.bottomAnchor.constraint(lessThanOrEqualTo: cv.bottomAnchor, constant: -20.0),
            
            tv.widthAnchor.constraint(equalToConstant: 600.0),
            

            cv.topAnchor.constraint(equalTo: cg.topAnchor, constant: 20.0),
            cv.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 20.0),
            cv.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: -20.0),
            cv.bottomAnchor.constraint(equalTo: cg.bottomAnchor, constant: -20.0),
            
            cv.widthAnchor.constraint(equalToConstant: 1000.0),
            
            sv.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            sv.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            sv.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            sv.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
            
        ])
        
        tv.isScrollEnabled = false
        tvsv.isScrollEnabled = false

        // so we can see the framing
        tv.backgroundColor = .yellow
        cv.backgroundColor = .systemBlue
        sv.backgroundColor = .systemRed
        view.backgroundColor = .systemYellow
        
    }
    
}

注意:我没有实现任何手动处理滚动视图内容偏移量的代码,这是保持插入点可见所必需的。然而,这将证明“自动滚动”不再有效。

相关问题