我有一个UITableView,每个单元格内有两个UITextViews。我希望UITableViewCell和UITextView的高度都增加,这样用户就不需要在UITextView中滚动了。这是我尝试过的:
在TableViewController类中:
self.tableView.estimatedRowHeight = 44
self.tableView.rowHeight = UITableViewAutomaticDimension
在TableViewCell类中(从here得到):
func textViewDidChange(textView: UITextView) {
var frame : CGRect = textView.frame
frame.size.height = textView.contentSize.height
textView.frame = frame
}
当用户输入超出UITextView的设置宽度时,UITableView会将高度从44增加到大约100,而UITextView的高度不会增加。我设置了约束,以便UITextView的高度等于UITableViewCell的高度。
为什么会发生这种情况并如何正确动态更改UITextView和UITableView的高度?
答案 0 :(得分:11)
我的回答是基于我们在社交应用Overriding Templates via a Theme的制作中使用的内容,因为您在Twitter上告诉我您使用了该应用,并且您看到了在那里扩展UITextView。
首先,我们有一个基于自定义Impether的类,其中包含UITextView
,它将被展开(此类也有相应的xib文件,您可以自行设计):< / p>
class MultiLineTextInputTableViewCell: UITableViewCell {
//our cell has also a title, but you
//can get rid of it
@IBOutlet weak var titleLabel: UILabel!
//UITextView we want to expand
@IBOutlet weak var textView: UITextView!
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
/// Custom setter so we can initialize the height of the text view
var textString: String {
get {
return textView?.text ?? ""
}
set {
if let textView = textView {
textView.text = newValue
textView.delegate?.textViewDidChange?(textView)
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
// Disable scrolling inside the text view so we enlarge to fitted size
textView?.scrollEnabled = false
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if selected {
textView?.becomeFirstResponder()
} else {
textView?.resignFirstResponder()
}
}
}
定义了自定义单元格后,您可以在基于UITableViewController
的类中使用它:
class YourTableViewController: UITableViewController {
//in case where you want to have
//multiple expanding text views
var activeTextView: UITextView?
override func viewDidLoad() {
super.viewDidLoad()
//registering nib for a cell to reuse
tableView.registerNib(
UINib(nibName: "MultiLineTextInputTableViewCell", bundle: nil),
forCellReuseIdentifier: "MultiLineTextInputTableViewCell")
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
//hide keyboard when view controller disappeared
if let textView = activeTextView {
textView.resignFirstResponder()
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
//put your value here
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//put your value here
return 2
}
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let row = indexPath.row
let cell = tableView.dequeueReusableCellWithIdentifier(
"MultiLineTextInputTableViewCell",
forIndexPath: indexPath) as! MultiLineTextInputTableViewCell
let titleText = "Title label for your cell"
let textValue = "Text value you want for your text view"
cell.titleLabel.text = titleText
cell.textView.text = textValue
//store row of a cell as a tag, so you can know
//which row to reload when the text view is expanded
cell.textView.tag = row
cell.textView.delegate = self
return cell
}
override func tableView(tableView: UITableView,
estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
//standard row height
return 44.0
}
override func tableView(tableView: UITableView,
heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView,
canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
}
//extension containing method responsible for expanding text view
extension YourTableViewController: UITextViewDelegate {
func textViewDidEndEditing(textView: UITextView) {
let value = textView.text
//you can do something here when editing is ended
}
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange,
replacementText text: String) -> Bool {
//if you hit "Enter" you resign first responder
//and don't put this character into text view text
if text == "\n" {
textView.resignFirstResponder()
return false
}
return true
}
func textViewDidBeginEditing(textView: UITextView) {
activeTextView = textView
}
//this actually resize a text view
func textViewDidChange(textView: UITextView) {
let size = textView.bounds.size
let newSize = textView.sizeThatFits(CGSize(width: size.width,
height: CGFloat.max))
// Resize the cell only when cell's size is changed
if size.height != newSize.height {
UIView.setAnimationsEnabled(false)
tableView?.beginUpdates()
tableView?.endUpdates()
UIView.setAnimationsEnabled(true)
let thisIndexPath = NSIndexPath(forRow: textView.tag, inSection: 0)
tableView?.scrollToRowAtIndexPath(thisIndexPath,
atScrollPosition: .Bottom,
animated: false)
}
}
}
答案 1 :(得分:1)
首先确保您的自动布局约束不会与您设置的帧冲突。 (如果一切正常但仍然无效)请尝试将frame
更改为bounds
。视图框架(CGRect)是其超视图坐标系中矩形的位置。根据我的经验,使用frame
可能会导致奇怪的问题。
func textViewDidChange(textView: UITextView) {
var frame : CGRect = textView.bounds
frame.size.height = textView.contentSize.height
textView.bounds = frame
}