I put photos inside a textView if there is video in the text, then I replace the video's photo with the player, the problem arose with the player, I can't understand why the player position is not correct, I noticed replaceCharacters does not work correctly, copy? .replaceCharacters (in: videoRange [i - wrong], with: "this is correct position") replaces only the first photo and copy? .replaceCharacters (in: videoRange [i - wrong], with: "+") all but with the wrong position, example how replaceCharacters work is below
extension UITextView {
// conver range to CGRect
func boundingRect(forCharacterRange range: NSRange) -> CGRect? {
guard let attributedText = attributedText else { return nil }
let textStorage = NSTextStorage(attributedString: attributedText)
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(size: intrinsicContentSize)
textContainer.lineFragmentPadding = 0
//layoutManager.hyphenationFactor = 1.0
layoutManager.addTextContainer(textContainer)
var glyphRange = NSRange()
layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: &glyphRange)
var rect = layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer)
rect.size.height = self.frame.width / 1.7
rect.size.width = self.frame.width
rect.origin.x = 0
return rect
}
// add image and video in text
func convertToInlineImageFormat(htmlString:String){
let text = videoInText(htmlString: htmlString)
let videoId = text.1
let HTMLString = text.0
guard let data = HTMLString.data(using: String.Encoding.unicode, allowLossyConversion: true) else { return }
let content = try! NSMutableAttributedString(
data: data,
options: [ .documentType: NSAttributedString.DocumentType.html],
documentAttributes: nil)
var videoRange = [NSRange]()
var height = [CGFloat]()
var isVideo = [Bool]()
let fontDesc = UIFont(name:"roboto-light", size: 19)
content.addAttribute(NSAttributedString.Key.font, value: fontDesc!, range: NSRange(location: 0, length: content.length))
content.enumerateAttribute(NSAttributedString.Key.attachment, in: NSRange(location: 0, length: content.length), options: [], using: {(value,range,stop) -> Void in
if (value is NSTextAttachment) {
let attachment: NSTextAttachment? = (value as? NSTextAttachment)
let fileWrapper = attachment?.fileWrapper
DispatchQueue.main.async {
let width = self.frame.size.width
if fileWrapper?.preferredFilename == "0.jpg" {
isVideo.append(true)
videoRange.append(range)
height.append(self.frame.width / 1.7)
attachment?.bounds.size = CGSize(width: width, height: self.frame.width / 1.7)
} else {
isVideo.append(false)
height.append(0)
attachment?.bounds.origin = CGPoint(x: 0, y: 20)
attachment?.bounds.size = CGSize(width: width, height: CGFloat(width/(attachment?.bounds.width ?? width) * (attachment?.bounds.height ?? width)))
}
}
}
})
DispatchQueue.main.async {
self.textContainer.lineFragmentPadding = 0 // отступы внутри textView
self.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
self.attributedText = content
var wrong = 0
for i in 0 ..< height.count {
// get CGRect of player
var rect = self.boundingRect(forCharacterRange: videoRange[i - wrong])!
print(rect, "rect")
if isVideo[i] {
for i in 0 ..< i {
rect.origin.y += height[i]
}
//place for player
let imgRect : UIBezierPath = UIBezierPath(rect:rect)
if self.textContainer.exclusionPaths == [] {
self.textContainer.exclusionPaths = [imgRect]
} else {
self.textContainer.exclusionPaths.append(imgRect)
}
//add player
YouTubeManager.shared.addVideo(textView: self, id: videoId[i - wrong], rect: rect)
// replace image of video
let copy = self.attributedText.mutableCopy() as? NSMutableAttributedString
copy?.replaceCharacters(in: videoRange[i - wrong], with: "this is correct position")
self.attributedText = copy
} else {
wrong += 1
}
}
}
}
//remove iframe and return video`s id
func videoInText(htmlString:String)-> (String, [String]){
func setText(text: String) -> (String, [String]) {
return formatString(text: text);
}
//main function that adds the youtube frame
func formatString(text: String) -> (String, [String]) {
let iframe_texts = matches(for: ".*iframe.*", in: text);
var new_text = text;
var video_id = [String]()
if iframe_texts.count > 0 {
for iframe_text in iframe_texts {
let iframe_id = matches(for: "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)", in: iframe_text);
if iframe_id.count > 0 { //just in case there is another type of iframe
new_text = new_text.replacingOccurrences(of: iframe_text, with:"<a href='https://www.youtube.com/watch?v=\(iframe_id[0])'><img src=\"https://img.youtube.com/vi/" + iframe_id[0] + "/0.jpg\" alt=\"\" width=\"600\" /></a>");
video_id.append(iframe_id[0])
}
}
} else {
// print("there is no iframe in this text");
}
return (new_text, video_id)
}
func matches(for regex: String, in text: String) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex, options: .caseInsensitive)
let nsString = text as NSString
let results = regex.matches(in: text, range: NSRange(location: 0, length: nsString.length))
return results.map { nsString.substring(with: $0.range)}
} catch let error {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
return setText(text: htmlString)
}
}
from textView with exclusionPaths and video



No comments:
Post a Comment