[英]Animate a change in part of an NSMutableAttributedString
我正在制作一个具有 UITextView 的 iOS 应用程序。 在该 UITextView 中关闭括号时,我想向用户突出显示它与哪个左括号配对。 到目前为止,我已经使用 NSMutableAttributedString 并更改了成对括号的字体大小来完成此操作,这可行但有点难看。 我真正想要的是在我的代码中关闭括号时,以类似于 xcode 执行相同操作的方式进行动画处理。 有没有办法做到这一点?
非常感谢任何帮助,尽管我对此很陌生,所以请不要假设我知道太多:)
这是我的代码:
@IBAction func didPressClosingParentheses(sender: AnyObject) {
appendStringToInputTextView(")")
var count = 1
let currentString = inputTextView.attributedText.string
let characterArray = Array(currentString)
let closingIndex = characterArray.count - 1
for i in reverse(0...closingIndex-1) {
if characterArray[i] == "(" {
count--
}
else if characterArray[i] == ")" {
count++
}
if count == 0 {
let startingIndex = i
var newString = NSMutableAttributedString(string: currentString)
newString.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue-Thin", size: 28)!, range: NSMakeRange(0, newString.length))
newString.addAttribute(NSForegroundColorAttributeName, value: UIColor(red: 243, green: 243, blue: 243, alpha: 1), range: NSMakeRange(0, newString.length))
newString.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue-Thin", size: 35)!, range: NSMakeRange(startingIndex, 1))
newString.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue-Thin", size: 35)!, range: NSMakeRange(closingIndex, 1))
UIView.animateWithDuration(0.4, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.8, options: nil, animations: {
self.inputTextView.attributedText = newString
}, nil)
break
}
}
}
正如您所看到的,我已经尝试使用 UIView.animateWithDuration 来执行此操作,正如我所怀疑的那样,这不起作用。
另一个对我有用的解决方案(Swift 4)是生成多个属性字符串,将一个分配给标签,然后替换过渡动画块内的内容( attributedText
文本)。 例如:
// MARK: Extension util which generates NSAttributedString by text,font,color,backgroundColor
extension NSAttributedString {
class func generate(from text: String, font: UIFont = UIFont.systemFont(ofSize: 16), color: UIColor = .black, backgroundColor: UIColor = .clear) -> NSAttributedString {
let atts: [NSAttributedStringKey : Any] = [.foregroundColor : color, .font : font, .backgroundColor : backgroundColor]
return NSAttributedString(string: text, attributes: atts)
}
}
// MARK: Sentence
let string1 = "Hi, i'm "
let string2 = "Daniel"
// MARK: Generate highlighted string
let prefixAttString = NSAttributedString.generate(from: string1)
let highlightedSuffixAttString = NSAttributedString.generate(from: string2, backgroundColor: .red)
let highlightedString = NSMutableAttributedString()
highlightedString.append(prefixAttString)
highlightedString.append(highlightedSuffixAttString)
// MARK: Generate regular string (Same prefix, different suffix)enter image description here
let regularSuffixAttString = NSAttributedString.generate(from: string2)
let regularString = NSMutableAttributedString()
regularString.append(prefixAttString)
regularString.append(regularSuffixAttString)
self.view.addSubview(label)
label.attributedText = regularString
// UIViewAnimationOptions.transitionCrossDissolve is necessary.
UIView.transition(with: self.label, duration: 4, options: [.transitionCrossDissolve], animations: {
self.label.attributedText = highlightedString
}, completion: nil)
}
不要忘记在动画选项中使用.transitionCrossDissolve
。
我通过获取实际括号的框架并在我的 UITextView 顶部创建新的 UILabels 并为这些标签设置动画来实现我想要的。
@IBAction func didPressClosingParentheses(sender: AnyObject) {
inputTextView.text = inputTextView.text + ")"
var count = 1
let currentString = inputTextView.attributedText.string
let characterArray = Array(currentString)
let closingIndex = characterArray.count - 1
for i in reverse(0...closingIndex-1) {
if characterArray[i] == "(" {
count--
}
else if characterArray[i] == ")" {
count++
}
if count == 0 {
let startingIndex = i
let openingRange = NSMakeRange(startingIndex, 1)
let closingRange = NSMakeRange(closingIndex, 1)
var openingFrame = inputTextView.layoutManager.boundingRectForGlyphRange(openingRange, inTextContainer: inputTextView.textContainer)
openingFrame.origin.y += inputTextView.textContainerInset.top
var openingLabel = UILabel(frame: openingFrame)
openingLabel.text = "("
openingLabel.font = UIFont(name: "HelveticaNeue-Thin", size: 28)
openingLabel.textColor = whiteishColor
openingLabel.backgroundColor = bluishColor
var closingFrame = inputTextView.layoutManager.boundingRectForGlyphRange(closingRange, inTextContainer: inputTextView.textContainer)
closingFrame.origin.y += inputTextView.textContainerInset.top
var closingLabel = UILabel(frame: closingFrame)
closingLabel.text = ")"
closingLabel.font = UIFont(name: "HelveticaNeue-Thin", size: 28)
closingLabel.textColor = whiteishColor
closingLabel.backgroundColor = bluishColor
inputTextView.addSubview(openingLabel)
inputTextView.addSubview(closingLabel)
UIView.animateWithDuration(0.4, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.8, options: nil, animations: {
openingLabel.transform = CGAffineTransformMakeScale(1.25, 1.25)
closingLabel.transform = CGAffineTransformMakeScale(1.25, 1.25)
}, nil)
UIView.animateWithDuration(0.4, delay: 0.2, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.8, options: nil, animations: {
openingLabel.transform = CGAffineTransformMakeScale(1.0, 1.0)
closingLabel.transform = CGAffineTransformMakeScale(1.0, 1.0)
}, nil)
UIView.animateWithDuration(0.25, delay: 0.4, options: nil, animations: {
openingLabel.alpha = 0
closingLabel.alpha = 0
}, completion: { finished in
openingLabel.removeFromSuperview()
closingLabel.removeFromSuperview()
})
break
}
}
}
有一种更简单的方法可以做到这一点,您可以在此答案中看到: 在 UILabel 中动画文本更改。
你只需要设置label.attributedText
属性:
UIView.transition(
with: label,
duration: 0.15,
options: .transitionCrossDissolve,
animations: {
label.attributedText = NSAttributedString(string: text, attributes: attributes)
},
completion: nil
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.