2016-07-22 125 views
0

我試圖添加see more功能,像this。我UITextView這是一個tableView'scell內和我使用這個類,這是基本的TableView的一個按鈕,擴大了的TextView其需要高度的子類:更新tableView當單元格的元素的框架更改

@IBDesignable 
class ReadMoreTextView: UITextView { 

    override init(frame: CGRect, textContainer: NSTextContainer?) { 
     super.init(frame: frame, textContainer: textContainer) 
     scrollEnabled = false 
     editable = false 
    } 



    convenience init(frame: CGRect) { 
     self.init(frame: frame, textContainer: nil) 
    } 

    convenience init() { 
     self.init(frame: CGRectZero, textContainer: nil) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     scrollEnabled = false 
     editable = false 
    } 

    convenience init(maximumNumberOfLines: Int, trimText: NSString?, shouldTrim: Bool) { 
     self.init() 
     self.maximumNumberOfLines = maximumNumberOfLines 
     self.trimText = trimText 
     self.shouldTrim = shouldTrim 
    } 

    convenience init(maximumNumberOfLines: Int, attributedTrimText: NSAttributedString?, shouldTrim: Bool) { 
     self.init() 
     self.maximumNumberOfLines = maximumNumberOfLines 
     self.attributedTrimText = attributedTrimText 
     self.shouldTrim = shouldTrim 
    } 

    @IBInspectable 
    var maximumNumberOfLines: Int = 0 { 
     didSet { setNeedsLayout() } 
    } 



    @IBInspectable 
    var trimText: NSString? { 
     didSet { setNeedsLayout() } 
    } 

    var attributedTrimText: NSAttributedString? { 
     didSet { setNeedsLayout() } 
    } 

    @IBInspectable 
    var shouldTrim: Bool = false { 
     didSet { setNeedsLayout() } 
    } 

    var trimTextRangePadding: UIEdgeInsets = UIEdgeInsetsZero 
    var appendTrimTextPrefix: Bool = true 
    var trimTextPrefix: String = "..." 

    private var originalText: String! 

    override var text: String! { 
     didSet { 
      originalText = text 
      originalAttributedText = nil 
      if needsTrim() { updateText() } 
     } 
    } 

    private var originalAttributedText: NSAttributedString! 

    override var attributedText: NSAttributedString! { 
     didSet { 
      originalAttributedText = attributedText 
      originalText = nil 
      if needsTrim() { updateText() } 
     } 
    } 

    override func layoutSubviews() { 
     super.layoutSubviews() 
     needsTrim() ? updateText() : resetText() 

    } 

    func needsTrim() -> Bool { 
     return shouldTrim && _trimText != nil 
    } 

    func updateText() { 
     textContainer.maximumNumberOfLines = maximumNumberOfLines 
     textContainer.size = CGSizeMake(bounds.size.width, CGFloat.max) 

     let range = rangeToReplaceWithTrimText() 
     if range.location != NSNotFound { 
      let prefix = appendTrimTextPrefix ? trimTextPrefix : "" 

      if let text = trimText?.mutableCopy() as? NSMutableString { 
       text.insertString("\(prefix) ", atIndex: 0) 
       textStorage.replaceCharactersInRange(range, withString: text as String) 
      } 
      else if let text = attributedTrimText?.mutableCopy() as? NSMutableAttributedString { 
       text.insertAttributedString(NSAttributedString(string: "\(prefix) "), atIndex: 0) 
       textStorage.replaceCharactersInRange(range, withAttributedString: text) 
      } 
     } 
     invalidateIntrinsicContentSize() 


    } 

    func resetText() { 
     textContainer.maximumNumberOfLines = 0 
     if originalText != nil { 
      textStorage.replaceCharactersInRange(NSMakeRange(0, countElements(text!)), withString: originalText) 

      print("Trim Pressed resetText") 

     } 
     else if originalAttributedText != nil { 
      textStorage.replaceCharactersInRange(NSMakeRange(0, countElements(text!)), withAttributedString: originalAttributedText) 
     } 
     invalidateIntrinsicContentSize() 

     // maybe this is what we're looking for 



    } 

    override func intrinsicContentSize() -> CGSize { 
     textContainer.size = CGSizeMake(bounds.size.width, CGFloat.max) 
     var intrinsicContentSize = layoutManager.boundingRectForGlyphRange(layoutManager.glyphRangeForTextContainer(textContainer), inTextContainer: textContainer).size 
     intrinsicContentSize.width = UIViewNoIntrinsicMetric 
     intrinsicContentSize.height += (textContainerInset.top + textContainerInset.bottom) 
     return intrinsicContentSize 


    } 

    override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { 

     if needsTrim() && pointInTrimTextRange(point) { 
      shouldTrim = false 
      maximumNumberOfLines = 0 
     } 

     return super.hitTest(point, withEvent: event) 

    } 

    //MARK: Private methods 

    private var _trimText: NSString? { 
     get { 
      return trimText ?? attributedTrimText?.string 
     } 
    } 

    private var _trimTextPrefixLength: Int { 
     get { 
      return appendTrimTextPrefix ? countElements(trimTextPrefix) + 1 : 1 
     } 
    } 

    private var _originalTextLength: Int { 
     get { 
      if originalText != nil { 
       return countElements(originalText!) 
      } 
      else if originalAttributedText != nil { 
       return originalAttributedText!.length 
      } 
      return 0 
     } 
    } 

    private func rangeToReplaceWithTrimText() -> NSRange { 
     let emptyRange = NSMakeRange(NSNotFound, 0) 

     var rangeToReplace = layoutManager.characterRangeThatFits(textContainer) 
     if NSMaxRange(rangeToReplace) == _originalTextLength { 
      rangeToReplace = emptyRange 
     } 
     else { 
      rangeToReplace.location = NSMaxRange(rangeToReplace) - _trimText!.length - _trimTextPrefixLength 
      if rangeToReplace.location < 0 { 
       rangeToReplace = emptyRange 
      } 
      else { 
       rangeToReplace.length = textStorage.length - rangeToReplace.location 
      } 
     } 
     return rangeToReplace 
    } 

    private func trimTextRange() -> NSRange { 
     var trimTextRange = rangeToReplaceWithTrimText() 
     if trimTextRange.location != NSNotFound { 
      trimTextRange.length = _trimTextPrefixLength + _trimText!.length 
     } 
     return trimTextRange 
    } 

    private func pointInTrimTextRange(point: CGPoint) -> Bool { 
     let offset = CGPointMake(textContainerInset.left, textContainerInset.top) 
     var boundingRect = layoutManager.boundingRectForCharacterRange(trimTextRange(), inTextContainer: textContainer, textContainerOffset: offset) 
     boundingRect = CGRectOffset(boundingRect, textContainerInset.left, textContainerInset.top) 
     boundingRect = CGRectInset(boundingRect, -(trimTextRangePadding.left + trimTextRangePadding.right), -(trimTextRangePadding.top + trimTextRangePadding.bottom)) 
     return CGRectContainsPoint(boundingRect, point) 
    } 

    func countElements(text: String) -> Int { 
     return text.characters.count 
    } 
} 

//MARK: NSLayoutManager extension 

extension NSLayoutManager { 

    func characterRangeThatFits(textContainer: NSTextContainer) -> NSRange { 
     var rangeThatFits = self.glyphRangeForTextContainer(textContainer) 
     rangeThatFits = self.characterRangeForGlyphRange(rangeThatFits, actualGlyphRange: nil) 
     return rangeThatFits 
    } 

    func boundingRectForCharacterRange(range: NSRange, inTextContainer textContainer: NSTextContainer, textContainerOffset: CGPoint) -> CGRect { 
     let glyphRange = self.glyphRangeForCharacterRange(range, actualCharacterRange: nil) 
     let boundingRect = self.boundingRectForGlyphRange(glyphRange, inTextContainer: textContainer) 
     return boundingRect 
    } 

} 

上述工作正常,如果我的textView是在一個ViewController,但因爲我有這裏面的單元格在UITableViewController,我不能夠更新單元格的高度與新的TextView的高度(更新的textView)任何想法如何更新我的tableView時,textView的高度更新?

P.S.我知道我必須使用tableView.beginUpdate,endUpdate,但我問什麼時候使用?如何知道textView的幀是否已更改

+0

您是否嘗試過設置你的tableview的屬性'RequiredHeight'(我不知道它的確切名稱,但在智能感知什麼仰望與'高度'在它)到'UITableView.AutomaticDimension'? –

+0

我會建議以下庫: - https://github.com/Ramotion/folding-cell – MShah

+0

男人我只想擴大單元格,當用戶在單元格中點擊@ZIL這就是爲什麼設置AutomaticDimension不會爲我工作 –

回答

1

我已使用this code of Ilya Puchka來解決在TextView中爲TableViewCell讀取更多內容的問題。

更新

也許ü可以使用tableView.heightForRowAtIndexPath(),並有intrinsicContentSize這將改變後擴大

override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat { 
    // an here use intrinsicContentSize 
    return self.intrinsicContentSize().height 
} 

沒有測試!只調試!已經夠晚了;-)

+0

以及我使用相同的,但你如何通知tableview更新其行高? –

+0

嗯,對不起,不知道:-( –

+0

看看我更新的答案... –

1

第一張:我沒有在您的表中看到datasourcedelegate方法。

你需要在你的對象中有3個鍵。

"heightCell" : 53, "originalHeight" : 0, "isexpanded" : 0

cellForRowAtIndexPath

你需要:

let eachRow = faqInfo.objectAtIndex(indexPath.row) 
eachRow.setValue(53, forKey: "heightCell") 

var currentHeght = eachRow["heightCell"] as! CGFloat 
//25 default question height 
eachRow.setValue(currentHeght + (newQuestionHeight - 25), forKey: "heightCell") 

var currentHeght = eachRow["heightCell"] as! CGFloat 
eachRow.setValue(currentHeght, forKey: "originalHeight") 

let isExpanded = eachRow["isexpanded"] as! Bool 
if isExpanded == true { 
    increaseTextViewInCell(cell, eachRow: eachRow) 
} 

Function用於增加TextView的細胞

func increaseTextViewInCell(cell: FAQTableViewCellController, eachRow: AnyObject) { 
     let answer = eachRow["answer"] as? String 
     let newAnswerHeight = Utils.heightForView(answer!, font: UIFont(name: "AvenirNextCondensed-Regular", size: CGFloat(15))!, width: cell.textviewAnswer.frame.size.width, xpos: cell.textviewAnswer.frame.origin.x) 

     //1 default question height 
     let currentHeght = eachRow["heightCell"] as! CGFloat 
     eachRow.setValue(currentHeght + (newAnswerHeight - 1) + 40, forKey: "heightCell") 
     cell.textviewAnswer.text = answer 
    } 

並在didSelectRowAtIndexPath

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
    let cell = tableView.cellForRowAtIndexPath(indexPath) as! FAQTableViewCellController 
    let eachRow = faqInfo.objectAtIndex(indexPath.row) 

    let isExpanded = eachRow["isexpanded"] as! Bool 
    if isExpanded == false { 

     increaseTextViewInCell(cell, eachRow: eachRow) 
     /* unncoment if need unexpand all the others cell 
     var i = 0 
     for eachInfo in faqInfo { 
      let isExpanded = eachInfo["isexpanded"] as! Bool 
      if isExpanded == true { 
       eachInfo.setValue(0, forKey: "isexpanded") 
       tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: i, inSection: 0)], withRowAnimation: .Fade) 
       break 
      } 
      i += 1 
     } 
     */ 
     eachRow.setValue(1, forKey: "isexpanded") 

    } else { 
     let originalHeight = eachRow["originalHeight"] as! CGFloat 
     eachRow.setValue(originalHeight, forKey: "heightCell") 

     eachRow.setValue(0, forKey: "isexpanded") 
    } 

    tableView.beginUpdates() 
    tableView.endUpdates() 
} 

而且heightForView功能

class func heightForView(text:String, font:UIFont, width:CGFloat, xpos:CGFloat) -> CGFloat { 
     let label:UILabel = UILabel(frame: CGRectMake(xpos, 0, width, CGFloat.max)) 
     label.numberOfLines = 0 
     label.lineBreakMode = NSLineBreakMode.ByWordWrapping 
     label.font = font 
     label.text = text 

     label.sizeToFit() 
     return label.frame.height 
    } 
相關問題