Ios 当单元格';s元素';s帧更改
我正在尝试添加Ios 当单元格';s元素';s帧更改,ios,uitableview,swift2,uitextview,Ios,Uitableview,Swift2,Uitextview,我正在尝试添加查看更多功能,例如。在我的UITextView上,它位于tableView的单元格中,为此我使用这个类,它基本上是tableView的一个子类,带有一个按钮,可以将TextView扩展到所需的高度: @IBDesignable class ReadMoreTextView: UITextView { override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(
查看更多功能,例如。在我的UITextView
上,它位于tableView的
单元格
中,为此我使用这个类,它基本上是tableView的一个子类,带有一个按钮,可以将TextView扩展到所需的高度:
@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
}
}
@IBDesignable
类ReadMoreTextView:UITextView{
重写init(frame:CGRect,textContainer:NSTextContainer?){
super.init(frame:frame,textContainer:textContainer)
scrollEnabled=false
可编辑=假
}
便利初始化(帧:CGRect){
self.init(frame:frame,textContainer:nil)
}
便利初始化(){
init(frame:CGRectZero,textContainer:nil)
}
必需的初始化?(编码器aDecoder:NSCoder){
super.init(编码者:aDecoder)
scrollEnabled=false
可编辑=假
}
便利初始化(maximumNumberOfLines:Int,trimText:NSString?,shouldTrim:Bool){
self.init()
self.maximumNumberOfLines=maximumNumberOfLines
self.trimText=trimText
self.shouldtim=shouldtim
}
便利初始化(maximumNumberOfLines:Int,attributedTrimText:NSAttributedString?,shouldTrim:Bool){
self.init()
self.maximumNumberOfLines=maximumNumberOfLines
self.attributedTrimText=attributedTrimText
self.shouldtim=shouldtim
}
@我看得见
var maximumNumberOfLines:Int=0{
didSet{setNeedsLayout()}
}
@我看得见
var-trimText:NSString{
didSet{setNeedsLayout()}
}
var attributedTrimText:NSAttributedString{
didSet{setNeedsLayout()}
}
@我看得见
变量shouldTrim:Bool=false{
didSet{setNeedsLayout()}
}
var trimTextRangePadding:UIEdgeInsets=UIEdgeInsetsZero
var appendTrimTextPrefix:Bool=true
var trimTextPrefix:String=“…”
private var originalText:字符串!
覆盖变量文本:字符串{
迪塞特{
原始文本=文本
originalAttributedText=nil
如果需要strim(){updateText()}
}
}
private var originalAttributedText:NSAttributedString!
重写var attributedText:NSAttributedString{
迪塞特{
originalAttributedText=attributedText
原始文本=零
如果需要strim(){updateText()}
}
}
覆盖func布局子视图(){
super.layoutSubviews()
needsTrim()?updateText():resetText()
}
func needsTrim()->Bool{
返回shouldTrim&&u trimText!=nil
}
func updateText(){
textContainer.maximumNumberOfLines=maximumNumberOfLines
textContainer.size=CGSizeMake(bounds.size.width,CGFloat.max)
let range=rangeToReplaceWithTrimText()
如果range.location!=NSNotFound{
let prefix=appendTrimTextPrefix?trimTextPrefix:“
如果let text=trimText?.mutableCopy()作为?NSMutableString{
text.insertString(“\(前缀)”,索引:0)
textStorage.ReplaceCharactersRange(范围,带字符串:文本作为字符串)
}
否则,如果让text=attributedTrimText?.mutableCopy()作为?NSMutableAttributedString{
text.insertAttributedString(NSAttributedString(字符串:\(前缀)”),索引:0)
textStorage.ReplaceCharactersRange(范围,withAttributedString:text)
}
}
InvalidateIntriseContentSize()无效
}
func resetText(){
textContainer.maximumNumberOfLines=0
如果原始文本!=无{
textStorage.replaceCharactersRange(NSMakeRange(0,countElements(text!)),带字符串:originalText)
打印(“修剪文本”)
}
如果originalAttributedText!=无,则为else{
textStorage.ReplaceCharactersRange(NSMakeRange(0,countElements(text!)),带AttributeString:originalAttributedText)
}
InvalidateIntriseContentSize()无效
//也许这就是我们要找的
}
重写func intrinsicContentSize()->CGSize{
textContainer.size=CGSizeMake(bounds.size.width,CGFloat.max)
var intrinsicContentSize=layoutManager.boundingrectformlyphrange(layoutManager.glyphRangeForTextContainer(textContainer),inTextContainer:textContainer).size
intrinsicContentSize.width=UIViewNoIntrinsicMetric
intrinsicContentSize.height+=(textContainerSet.top+textContainerSet.bottom)
返回intrinsicContentSize
}
覆盖func hitTest(点:CGPoint,withEvent事件:UIEvent?->UIView{
如果需要strim()&&pointInTrimTextRange(点){
shouldTrim=false
maximumNumberOfLines=0
}
返回super.hitTest(point,withEvent:event)
}
//标记:私有方法
私有变量trimText:NSString{
得到{
返回trimText??attributedTrimText?字符串
}
}
专用变量trimTextPrefixLength:Int{
得到{
返回appendTrimTextPrefix?countElements(trimTextPrefix)+1:1
}
}
private var_originalTextLength:Int{
得到{
如果原始文本!=无{
返回countElements(originalText!)
}
如果originalAttributedText!=无,则为else{
返回originalAttributedText!。长度
}
返回0
}
}
private func rangeToReplaceWithTrimText()->NSRange{
让emptyRange=NSMakeRange(NSNotFound,0)
var rangeToReplace=layoutManager.characterRangeThatFits(textContainer)
如果NSMaxRange(rangeToReplace)=\u originalTextLength{
rangeToReplace=emptyRange
}
否则{
rangeToReplace.location=NSMaxRange(rangeToReplace)-(U trimText!.length-\U trimTextPrefixLen
override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
// an here use intrinsicContentSize
return self.intrinsicContentSize().height
}
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)
}
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
}
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()
}
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
}