问题背景和描述
我制作了一个垂直 TextView ,用于蒙古文。它是一个自定义的 TextView ,由三层 View 组成: subview UITextView ,一个容器 View (旋转 90 度并翻转)来保存 UITextView ,和父 View 。 (有关更多背景信息,请参阅 here 和 here。)
View 根据底层 TextView 的内容大小增加其大小,只要它介于最小和最大大小之间。然而,在过去的几天里,我一直在努力修复一个错误,即添加了额外的空间并且内容向左移动(这将取决于底层 TextView 的坐标)。这可以在下图中观察到。黄色 View 是自定义 TextView (在下面的 View Controller 代码中称为 inputWindow。)

在我点击 Enter 几次以增加内容 View 的大小后,会添加一个额外的空间。尝试 ScrollView 没有任何作用。 (在宽度达到最大值并且内容大小大于框架大小后滚动确实起作用。)就好像内容在滚动中间时被卡住到位,然后才能放置在正确的位置。如果我插入另一个字符(如空格),则内容 View 将自身更新到正确的位置。
题
我需要改变什么?或者我如何手动强制底层UITextView在正确的位置显示其内容 View ?
代码
我试图删除所有无关的代码,只留下 View Controller 和 Custom Vertical TextView 的相关部分。如果还有什么我应该包括的,请告诉我。
View Controller
当内容 View 大小发生变化时, View Controller 会更新自定义 TextView 的大小限制。
import UIKit
class TempViewController: UIViewController, KeyboardDelegate {
let minimumInputWindowSize = CGSize(width: 80, height: 150)
let inputWindowSizeIncrement: CGFloat = 50
// MARK:- Outlets
@IBOutlet weak var inputWindow: UIVerticalTextView!
@IBOutlet weak var topContainerView: UIView!
@IBOutlet weak var keyboardContainer: KeyboardController!
@IBOutlet weak var inputWindowHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var inputWindowWidthConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// get rid of space at beginning of textview
self.automaticallyAdjustsScrollViewInsets = false
// setup keyboard
keyboardContainer.delegate = self
inputWindow.underlyingTextView.inputView = UIView()
inputWindow.underlyingTextView.becomeFirstResponder()
}
// KeyboardDelegate protocol
func keyWasTapped(character: String) {
inputWindow.insertMongolText(character) // code omitted for brevity
increaseInputWindowSizeIfNeeded()
}
func keyBackspace() {
inputWindow.deleteBackward() // code omitted for brevity
decreaseInputWindowSizeIfNeeded()
}
private func increaseInputWindowSizeIfNeeded() {
if inputWindow.frame.size == topContainerView.frame.size {
return
}
// width
if inputWindow.contentSize.width > inputWindow.frame.width &&
inputWindow.frame.width < topContainerView.frame.size.width {
if inputWindow.contentSize.width > topContainerView.frame.size.width {
//inputWindow.scrollEnabled = true
inputWindowWidthConstraint.constant = topContainerView.frame.size.width
} else {
self.inputWindowWidthConstraint.constant = self.inputWindow.contentSize.width
}
}
// height
if inputWindow.contentSize.width > inputWindow.contentSize.height {
if inputWindow.frame.height < topContainerView.frame.height {
if inputWindow.frame.height + inputWindowSizeIncrement < topContainerView.frame.height {
// increase height by increment unit
inputWindowHeightConstraint.constant = inputWindow.frame.height + inputWindowSizeIncrement
} else {
inputWindowHeightConstraint.constant = topContainerView.frame.height
}
}
}
}
private func decreaseInputWindowSizeIfNeeded() {
if inputWindow.frame.size == minimumInputWindowSize {
return
}
// width
if inputWindow.contentSize.width < inputWindow.frame.width &&
inputWindow.frame.width > minimumInputWindowSize.width {
if inputWindow.contentSize.width < minimumInputWindowSize.width {
inputWindowWidthConstraint.constant = minimumInputWindowSize.width
} else {
inputWindowWidthConstraint.constant = inputWindow.contentSize.width
}
}
// height
if (2 * inputWindow.contentSize.width) <= inputWindow.contentSize.height && inputWindow.contentSize.width < topContainerView.frame.width {
// got too high, make it shorter
if minimumInputWindowSize.height < inputWindow.contentSize.height - inputWindowSizeIncrement {
inputWindowHeightConstraint.constant = inputWindow.contentSize.height - inputWindowSizeIncrement
} else {
// Bump down to min height
inputWindowHeightConstraint.constant = minimumInputWindowSize.height
}
}
}
}
UITextView 允许它旋转和翻转,以便正确观看传统的蒙古语。import UIKit
@IBDesignable class UIVerticalTextView: UIView {
var textView = UITextView()
let rotationView = UIView()
var underlyingTextView: UITextView {
get {
return textView
}
set {
textView = newValue
}
}
var contentSize: CGSize {
get {
// height and width are swapped because underlying view is rotated 90 degrees
return CGSize(width: textView.contentSize.height, height: textView.contentSize.width)
}
set {
textView.contentSize = CGSize(width: newValue.height, height: newValue.width)
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect){
super.init(frame: frame)
self.setup()
}
override func awakeFromNib() {
super.awakeFromNib()
self.setup()
}
func setup() {
textView.backgroundColor = UIColor.yellowColor()
self.textView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(rotationView)
rotationView.addSubview(textView)
// add constraints to pin TextView to rotation view edges.
let leadingConstraint = NSLayoutConstraint(item: self.textView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: rotationView, attribute: NSLayoutAttribute.Leading, multiplier: 1.0, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: self.textView, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: rotationView, attribute: NSLayoutAttribute.Trailing, multiplier: 1.0, constant: 0)
let topConstraint = NSLayoutConstraint(item: self.textView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: rotationView, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: self.textView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: rotationView, attribute: NSLayoutAttribute.Bottom, multiplier: 1.0, constant: 0)
rotationView.addConstraints([leadingConstraint, trailingConstraint, topConstraint, bottomConstraint])
}
override func layoutSubviews() {
super.layoutSubviews()
rotationView.transform = CGAffineTransformIdentity
rotationView.frame = CGRect(origin: CGPointZero, size: CGSize(width: self.bounds.height, height: self.bounds.width))
rotationView.userInteractionEnabled = true
rotationView.transform = translateRotateFlip()
}
func translateRotateFlip() -> CGAffineTransform {
var transform = CGAffineTransformIdentity
// translate to new center
transform = CGAffineTransformTranslate(transform, (self.bounds.width / 2)-(self.bounds.height / 2), (self.bounds.height / 2)-(self.bounds.width / 2))
// rotate counterclockwise around center
transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2))
// flip vertically
transform = CGAffineTransformScale(transform, -1, 1)
return transform
}
}
layoutSubviews()我做的方法textView.frame = rotationView.bounds
setup() 中添加约束.没有明显的效果。textView.layoutManager.allowsNonContiguousLayout = false
setNeedsLayout 的各种组合和 setNeedsDisplay在 inputWindow 和底层 TextView 上。inputWindow.setNeedsLayout()
inputWindow.underlyingTextView.setNeedsLayout()
dispatch_async 内以便它在下一个运行循环中运行。dispatch_async(dispatch_get_main_queue()) {
self.inputWindow.setNeedsLayout()
}
sizeToFit在更新宽度约束后的下一个运行循环中,起初看起来很有希望,但它仍然没有解决问题。有时内容会卡住,有时它会滚动。它并不总是每次都在同一个地方卡住。self.inputWindowWidthConstraint.constant = self.inputWindow.contentSize.width
dispatch_async(dispatch_get_main_queue()) {
self.inputWindow.underlyingTextView.sizeToFit()
}

var _f = self.inputWindow.underlyingTextView.frame
_f.size.height = self.inputWindow.underlyingTextView.contentSize.height
self.inputWindow.underlyingTextView.frame = _f

UIView类是 inputWindow并且应该设置为 UIVerticalTextView .浅蓝色 View 是 topContainerView .下面的按钮取代了键盘。import UIKit
class ViewController: UIViewController {
let minimumInputWindowSize = CGSize(width: 80, height: 150)
let inputWindowSizeIncrement: CGFloat = 50
// MARK:- Outlets
@IBOutlet weak var inputWindow: UIVerticalTextView!
@IBOutlet weak var topContainerView: UIView!
//@IBOutlet weak var keyboardContainer: KeyboardController!
@IBOutlet weak var inputWindowHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var inputWindowWidthConstraint: NSLayoutConstraint!
@IBAction func enterTextButtonTapped(sender: UIButton) {
inputWindow.insertMongolText("a")
increaseInputWindowSizeIfNeeded()
}
@IBAction func newLineButtonTapped(sender: UIButton) {
inputWindow.insertMongolText("\n")
increaseInputWindowSizeIfNeeded()
}
@IBAction func deleteBackwardsButtonTapped(sender: UIButton) {
inputWindow.deleteBackward()
decreaseInputWindowSizeIfNeeded()
}
override func viewDidLoad() {
super.viewDidLoad()
// get rid of space at beginning of textview
self.automaticallyAdjustsScrollViewInsets = false
// hide system keyboard but show cursor
inputWindow.underlyingTextView.inputView = UIView()
inputWindow.underlyingTextView.becomeFirstResponder()
}
private func increaseInputWindowSizeIfNeeded() {
if inputWindow.frame.size == topContainerView.frame.size {
return
}
// width
if inputWindow.contentSize.width > inputWindow.frame.width &&
inputWindow.frame.width < topContainerView.frame.size.width {
if inputWindow.contentSize.width > topContainerView.frame.size.width {
//inputWindow.scrollEnabled = true
inputWindowWidthConstraint.constant = topContainerView.frame.size.width
} else {
self.inputWindowWidthConstraint.constant = self.inputWindow.contentSize.width
}
}
// height
if inputWindow.contentSize.width > inputWindow.contentSize.height {
if inputWindow.frame.height < topContainerView.frame.height {
if inputWindow.frame.height + inputWindowSizeIncrement < topContainerView.frame.height {
// increase height by increment unit
inputWindowHeightConstraint.constant = inputWindow.frame.height + inputWindowSizeIncrement
} else {
inputWindowHeightConstraint.constant = topContainerView.frame.height
}
}
}
}
private func decreaseInputWindowSizeIfNeeded() {
if inputWindow.frame.size == minimumInputWindowSize {
return
}
// width
if inputWindow.contentSize.width < inputWindow.frame.width &&
inputWindow.frame.width > minimumInputWindowSize.width {
if inputWindow.contentSize.width < minimumInputWindowSize.width {
inputWindowWidthConstraint.constant = minimumInputWindowSize.width
} else {
inputWindowWidthConstraint.constant = inputWindow.contentSize.width
}
}
// height
if (2 * inputWindow.contentSize.width) <= inputWindow.contentSize.height && inputWindow.contentSize.width < topContainerView.frame.width {
// got too high, make it shorter
if minimumInputWindowSize.height < inputWindow.contentSize.height - inputWindowSizeIncrement {
inputWindowHeightConstraint.constant = inputWindow.contentSize.height - inputWindowSizeIncrement
} else {
// Bump down to min height
inputWindowHeightConstraint.constant = minimumInputWindowSize.height
}
}
}
}
UIVerticalTextView 相同的代码在原始示例中,但添加了以下两种方法。func insertMongolText(unicode: String) {
textView.insertText(unicode)
}
func deleteBackward() {
textView.deleteBackward()
}
最佳答案
是否可以给我们一个示例项目(在 github 上)?
你能测试一下你的下面的代码吗? UIVerticalTextView 文件:
override func layoutSubviews() {
super.layoutSubviews()
rotationView.transform = CGAffineTransformIdentity
rotationView.frame = CGRect(origin: CGPointZero, size: CGSize(width: self.bounds.height, height: self.bounds.width))
rotationView.userInteractionEnabled = true
rotationView.transform = translateRotateFlip()
if self.textView.text.isEmpty == false {
self.textView.scrollRangeToVisible(NSMakeRange(0, 1))
}
}
关于ios - 调整大小后 UITextView 内容错位并带有额外空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37225260/
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
Region是HBase数据管理的基本单位,region有一点像关系型数据的分区。region中存储这用户的真实数据,而为了管理这些数据,HBase使用了RegionSever来管理region。Region的结构hbaseregion的大小设置默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。刚拆分时,两个子Region都位于当前的RegionServer,但处于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的RegionServer。RegionSplit时机:当1个region中的某个Store下所有StoreFile
使用rspec-rails3.0+,测试设置分为spec_helper和rails_helper我注意到生成的spec_helper不需要'rspec/rails'。这会导致zeus崩溃:spec_helper.rb:5:in`':undefinedmethod`configure'forRSpec:Module(NoMethodError)对thisissue最常见的回应是需要'rspec/rails'。但这是否会破坏仅使用spec_helper拆分rails规范和PORO规范的全部目的?或者这无关紧要,因为Zeus无论如何都会预加载Rails?我应该在我的spec_helper中做