UIWebView : Get Webview Content size? - ios

I have loaded HTML in webview.Β Β I want to dynamically update font size(increase or decrease) of text loaded in web view Same as in Apple News Article app. But According to my design I need to stop web view scrolling and need to update it height according to text. So I need to get content size of article, but I am not getting it proper. Can anyone help?

When font change at that time change Webview height to 1 than get proper offsetHeight for Webview
webView1.frame.size.height = 1
let size : String = self.webView1.stringByEvaluatingJavaScript(from: "document.documentElement.offsetHeight")!

add below lines of code into your webViewDidFinishLoad
webView.layoutSubviews()
webView.frame.size.height = 1
webView.frame.size = webView.sizeThatFits(.zero)
print("WebView Height : \(webView.scrollView.contentSize.height)")
webViewHgtConst.constant = webView.scrollView.contentSize.height
webView.scalesPageToFit = true
webView.scrollView.isScrollEnabled = false
webView.scrollView.maximumZoomScale = 1.0
webView.scrollView.minimumZoomScale = 1.0
and don't forget to add UIWebViewDelegate
and add YOUR_WEBVIEW.delegate = self to your viewDidLoad
Hope this will help you

First stop its scrolling :
webView.scrollView.isScrollEnabled = false
webView.scrollView.showsVerticalScrollIndicator = false
webView.scrollView.showsHorizontalScrollIndicator = false
webView.scrollView.bounces = false
webView.loadHTMLString(dataHtmlString, baseURL: nil)
Make outlet of webView height Constraint and give its value by calculating its height:
webviewHeightConst.constant = (dataHtmlString.htmlAttributedString()?.height(withConstrainedWidth: yourwidthcont))!
This Extension Calculates height
extension String {
func htmlAttributedString() -> NSAttributedString? {
guard let data = self.data(using: String.Encoding.utf16, allowLossyConversion: false) else { return nil }
guard let html = try? NSMutableAttributedString(
data: data,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
documentAttributes: nil) else { return nil }
var found = false
html.beginEditing()
html.enumerateAttribute(NSFontAttributeName, in: NSMakeRange(0, html.length), options: NSAttributedString.EnumerationOptions(rawValue: 0)) { (value, range, stop) in
if (value != nil) {
let oldFont = value as! UIFont
let newFont = oldFont.withSize(16)
html.addAttribute(NSFontAttributeName, value: newFont, range: range)
found = true
}
}
if !found{
// No font was found - do something else?
}
html.endEditing()
return html
}
}

Related

How to detect the orientation of a PDF page in Swift with PDFKit IOS

I'm trying to get the orientation property of a PDF document. The purpose is, I would like to add a button widget in a location that depends on the orientation of the PDF document.
For example:
func openPDFDocument() {
if let documentURL = Bundle.main.url(forResource: "PDF document", withExtension: "pdf"),
let document = PDFDocument(url: documentURL),
let page = document.page(at: 0) {
// Set our document to the view, center it, and set a background color
pdfView?.document = document
pdfView?.autoScales = true
pdfView?.backgroundColor = UIColor.lightGray
//I think I should be able to add a code here like:
if page.orientation = Horizontal {
self.insertResetButtonInto(page)
} else {
//do nothing or do something else
}
}
}
This is the function I would like to add in case the document is in Landscape mode:
func insertResetButtonInto(_ page: PDFPage) {
let pageBounds = page.bounds(for: .cropBox)
let resetButtonBounds = CGRect(x: 90, y: pageBounds.size.height - 300, width: 106, height: 32)
let resetButton = PDFAnnotation(bounds: resetButtonBounds, forType: PDFAnnotationSubtype(rawValue: PDFAnnotationSubtype.widget.rawValue), withProperties: nil)
resetButton.widgetFieldType = PDFAnnotationWidgetSubtype(rawValue: PDFAnnotationWidgetSubtype.button.rawValue)
resetButton.widgetControlType = .pushButtonControl
resetButton.caption = "Reset"
page.addAnnotation(resetButton)
// Create PDFActionResetForm action to clear form fields.
let resetFormAction = PDFActionResetForm()
resetFormAction.fieldsIncludedAreCleared = false
resetButton.action = resetFormAction
}
I got the example project from Apple's documentation website. I looked at a previous similar question, however it seems this was in Objective C.
I would appreciate the help in this matter.
There is no direct API to get the orientation from a PDFPage. But you can first get the page size from .mediaBox, then calculate the orientation like below.
let pageSize = page.bounds(for: .mediaBox).size
if pageSize.width > pageSize.height {
//landscape
} else {
//portrait
}
I use another way to get the orientation of my pdf page.
func IsLandscape(page: PDFPage) -> Bool {
let pointZero = pdfView.convert(CGPoint(x: 0, y: 0), from: page)
let pointTen = pdfView.convert(CGPoint(x: 10, y: 10), from: page)
let caculate = pointTen.x - pointZero.x
print("pointZero: \(pointZero), pointTen:\(pointTen)")
if (caculate > 0) {
print("landscape")
return true
}
else {
print("portrait")
return false
}
}

Emoji skin-tone detect

Following this post I tried to update the code from Swift 2.0 to Swift 5.0 to check which emojis have skin tones available or not and other variations already present.
My updated code in detail:
extension String {
var emojiSkinToneModifiers: [String] {
return [ "🏻", "🏼", "🏽", "🏾", "🏿" ]
}
var emojiVisibleLength: Int {
var count = 0
enumerateSubstrings(in: startIndex..<endIndex, options: .byComposedCharacterSequences) { (_, _, _, _) in
count = count + 1
}
return count
}
var emojiUnmodified: String {
if self.count == 0 {
return ""
}
let range = String(self[..<self.index(self.startIndex, offsetBy: 1)])
return range
}
var canHaveSkinToneModifier: Bool {
if self.count == 0 {
return false
}
let modified = self.emojiUnmodified + self.emojiSkinToneModifiers[0]
return modified.emojiVisibleLength == 1
}
}
And use this with an array:
let emojis = [ "πŸ‘", "πŸ‘πŸΏ", "🐸" ]
for emoji in emojis {
if emoji.canHaveSkinToneModifier {
let unmodified = emoji.emojiUnmodified
print(emoji)
for modifier in emoji.emojiSkinToneModifiers {
print(unmodified + modifier)
}
} else {
print(emoji)
}
}
The output:
πŸ‘πŸ‘πŸ»πŸ‘πŸΌπŸ‘πŸ½πŸ‘πŸΎπŸ‘πŸΏ πŸ‘πŸΏπŸ‘πŸΏπŸ»πŸ‘πŸΏπŸΌπŸ‘πŸΏπŸ½πŸ‘πŸΏπŸΎπŸ‘πŸΏπŸΏ 🐸🐸🏻🐸🏼🐸🏽🐸🏾🐸🏿
assigns variations to emojis that do not have them or that already is instead of: πŸ‘πŸ‘πŸ»πŸ‘πŸΌπŸ‘πŸ½πŸ‘πŸΎπŸ‘πŸΏ πŸ‘πŸΏ 🐸
I suppose enumerateSubstringsInRange is incorrect and self.characters.count now became self.count easy and correct to count one emoji (composed) compared to before Swift 4 but maybe not useful in this case. What am I not seeing wrong?
Thanks
A "hack" would be to compare the visual representation of a correct emoji (like "🐸") and a wanna-be emoji (like "🐸🏽").
I've modified your code here and there to make it work:
extension String {
static let emojiSkinToneModifiers: [String] = ["🏻", "🏼", "🏽", "🏾", "🏿"]
var emojiVisibleLength: Int {
var count = 0
let nsstr = self as NSString
let range = NSRange(location: 0, length: nsstr.length)
nsstr.enumerateSubstrings(in: range,
options: .byComposedCharacterSequences)
{ (_, _, _, _) in
count = count + 1
}
return count
}
var emojiUnmodified: String {
if isEmpty {
return self
}
let string = String(self.unicodeScalars.first!)
return string
}
private static let emojiReferenceSize: CGSize = {
let size = CGSize(width : CGFloat.greatestFiniteMagnitude,
height: CGFloat.greatestFiniteMagnitude)
let rect = ("πŸ‘" as NSString).boundingRect(with: size,
options: .usesLineFragmentOrigin,
context: nil)
return rect.size
}()
var canHaveSkinToneModifier: Bool {
if isEmpty {
return false
}
let modified = self.emojiUnmodified + String.emojiSkinToneModifiers[0]
let size = (modified as NSString)
.boundingRect(with: CGSize(width : CGFloat.greatestFiniteMagnitude,
height: .greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
context: nil).size
return size == String.emojiReferenceSize
}
}
Let's try it out:
let emojis = [ "πŸ‘", "πŸ‘πŸΏ", "🐸" ]
for emoji in emojis {
if emoji.canHaveSkinToneModifier {
let unmodified = emoji.emojiUnmodified
print(unmodified)
for modifier in String.emojiSkinToneModifiers {
print(unmodified + modifier)
}
} else {
print(emoji)
}
print("\n")
}
And voila!
πŸ‘
πŸ‘πŸ»
πŸ‘πŸΌ
πŸ‘πŸ½
πŸ‘πŸΎ
πŸ‘πŸΏ
πŸ‘
πŸ‘πŸ»
πŸ‘πŸΌ
πŸ‘πŸ½
πŸ‘πŸΎ
πŸ‘πŸΏ
🐸

How to allow and get Memoji Stickers in a text field

I'm trying to use Memoji Stickers on my app, but neither UITextField or TextField from SwiftUI displays them on the keyboard. How can I make them show up, and how do I retrieve them afterwards?
I tried different text input traits, but had no success. I even tried using the Twitter keyboard option, because the stickers work in the Twitter app, but it was to no avail.
Here's a picture of how it shows up for me in apps that support it, like WhatsApp, Telegram and Twitter
So... how you can get it is to implement the paste method on the view controller where your textfield/view is.
Then you can grab the image from the pasteboard. Basically
Objective-C
UIImage *image = [[UIPasteboard generalPasteboard] image];
or Swift
let image = UIPasteboard.general.image
Which will let you find the UIImage then you can wrap it in
Objective-c
NSAttributedString *memojiStrong = [[NSAttributedString alloc] initWithAttributedString: image];
Swift
let memojiString = NSAttributedString(attachment: image)
This will let you add it as a string to whatever you need to add it to.
You can find a little more for the image -> String if you want to save it for an image: https://www.hackingwithswift.com/example-code/system/how-to-insert-images-into-an-attributed-string-with-nstextattachment
and the poster for some credit to get me this far:
https://www.reddit.com/r/iOSProgramming/comments/cuz3ut/memoji_in_chat/ey4onqg/?context=3
set the "allowsEditingTextAttributes" property to YES in UITextField.
For RxSwift:
textView.rx.attributedText.subscribe(onNext: { [weak self] attributeString in
guard let attributeString = attributeString else { return }
attributeString.enumerateAttribute(NSAttributedStringKey.attachment, in: NSRange(location: 0, length: attributeString.length), options: [], using: {(value,range,_) -> Void in
if (value is NSTextAttachment) {
let attachment: NSTextAttachment? = (value as? NSTextAttachment)
var image: UIImage?
if ((attachment?.image) != nil) {
image = attachment?.image
} else {
image = attachment?.image(forBounds: (attachment?.bounds)!, textContainer: nil, characterIndex: range.location)
}
guard let pasteImage = image else { return }
guard let pngData = UIImagePNGRepresentation(pasteImage) else { return }
guard let pngImage = UIImage(data: pngData) else { return }
guard let attachmentImage = OutgoingFile(image: pngImage, type: .image, isPNG: true) else { return }
let newString = NSMutableAttributedString(attributedString: attributeString)
newString.replaceCharacters(in: range, with: "")
self?.newCommentBodyTextView.textView.attributedText = newString
self?.addFileOnNews(attachmentImage)
return
}
})
}).disposed(by: bag)
You can find more information in https://kostyakulakov.ru/how-to-get-memoji-from-uitextfield-or-uitextview-swift-4/

Crash specialized String.imageSize(),

I have a crash in this extension method of String:
func imageSize() -> CGSize {
// self = "https://s3-eu-west-1.amazonaws.com/mimg.haraj.com.sa/userfiles30/2018-8-6/524x334-1_-E7VSb5T20mOouX.jpg"
var width = 0
var height = 0
let split0 = self.split(separator: "/")
if split0.count > 0 {
let split1 = split0.last?.split(separator: "-")
if (split1?.count)! > 0 {
let split2 = split1?.first?.decomposedStringWithCanonicalMapping.split(separator: "x")
width = (split2?.first?.decomposedStringWithCanonicalMapping.toInt())!
if (split2?.count)! > 1 {
// let split2 = split1![1].decomposedStringWithCanonicalMapping.split(separator: "-")
height = (split2?.last?.decomposedStringWithCanonicalMapping.toInt())!
}
}
}
return CGSize(width: width, height: height)
}
The crash is on line return CGSize(width: width, height: height)
I have created an NSString version like this to use the same above method:
#objc extension NSString {
func imageSize1() -> CGSize {
return (self as String).imageSize()
}
}
This is then called from obj-c code:
CGSize imageSize = [url imageSize1];
Examples of url are:
https://s3-eu-west-1.amazonaws.com/mimg.haraj.com.sa/userfiles30/2019-02-07/675x900-1_-CdC62Y2hcV7208.jpg
https://s3-eu-west-1.amazonaws.com/mimg.haraj.com.sa/userfiles30/2019-02-07/675x900-1_-697e3no8ec2E1I.jpg
https://s3-eu-west-1.amazonaws.com/mimg.haraj.com.sa/userfiles30/2019-02-07/675x900-1_-8Af5D20wh9b62z.jpg
What this imageSize() method does is that it parses the image size from the url. The urls above contain the sizes 675x900 -> widthxheight.
In rare case we encounter a url where there is no information of the size and the url is not in the format above. So if the size is not found CGSize = (0 , 0) is returned.
I have tested this method on all expected scenarios.
But due to some reasons the method is causing crashes. May be I missed/messed something.
Here is the link to Crashlytics issue.
Any help would be appreciated.
Try don't use force unwrap !
let exampleString1 = "https://s3-eu-west-1.amazonaws.com/mimg.haraj.com.sa/userfiles30/2018-8-6/524x334-1_-E7VSb5T20mOouX.jpg"
let exampleString2 = "https://s3-eu-west-1.amazonaws.com/mimg.haraj.com.sa/userfiles30/2019-02-07/675x900-1_-697e3no8ec2E1I.jpg"
let exampleString3 = "https://s3-eu-west-1.amazonaws.com/mimg.haraj.com.sa/userfiles30/2019-02-07/675x900-1_-CdC62Y2hcV7208.jpg"
extension String {
func imageSize() -> CGSize? {
// last url component
guard let imageName = self.split(separator: "/").last else { return nil }
guard let imageSizeString = imageName.split(separator: "-").first else { return nil }
let sizes = imageSizeString.split(separator: "x")
guard let first = sizes.first,
let last = sizes.last,
let wight = Int(String(first)),
let height = Int(String(last))
else { return nil }
return CGSize(width: wight, height: height)
}
}
exampleString1.imageSize() // Optional((524.0, 334.0))
exampleString2.imageSize() // Optional((675.0, 900.0))
exampleString3.imageSize() // Optional((675.0, 900.0))
Also try to use guard let and return nil if something wrong. For example Url schema can be changed
The crash is most likely due to force unwrapping optionals. There are several cases in your code where you're using it, which will lead to a runtime error if file name in your URL has a different format than you expect. Try
func imageSize() -> CGSize {
// self = "https://s3-eu-west-1.amazonaws.com/mimg.haraj.com.sa/userfiles30/2018-8-6/524x334-1_-E7VSb5T20mOouX.jpg"
var width = 0
var height = 0
let split0 = self.split(separator: "/")
if let split1 = split0.last?.split(separator: "-")
{
if let split2 = split1.first?.decomposedStringWithCanonicalMapping.split(separator: "x")
{
width = (split2.first?.decomposedStringWithCanonicalMapping.toInt()) ?? 0
if split2.count > 1 {
height = (split2.last?.decomposedStringWithCanonicalMapping.toInt()) ?? 0
}
}
}
return CGSize(width: width, height: height)
}

Swift 3, Display some lines of the HTML text

I try to add html code inside webView:
webView.loadHTMLString(myHTML, baseURL: nil)
But last line displays cropped:
What is the best way to hide this cropped bottom line in my webView?
I recommend you too use UILabel
Full example
ViewController.swift
import UIKit
class ViewController: UIViewController {
var label: UILabel?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
var bounds = view.bounds
bounds.origin.y = 44
bounds.size.height = 100
label = UILabel(frame: bounds)
label?.backgroundColor = UIColor.white
view.addSubview(label!)
let filename = "HTMLPage.html"
if let path = Bundle.main.path(forResource: filename, ofType: nil) {
do {
let text = try String(contentsOfFile: path, encoding: String.Encoding.utf8)
label?.attributedText = text.htmlToAttributedString
label?.numberOfLines = 5
label?.lineBreakMode = .byTruncatingTail
} catch {
print("Failed to read text from \(filename)")
}
} else {
print("Failed to load file from app bundle \(filename)")
}
}
}
extension String {
var htmlToAttributedString: NSAttributedString? {
do {
let data = self.data(using: String.Encoding.utf8, allowLossyConversion: true)
if let d = data {
let str = try NSAttributedString(data: d,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
documentAttributes: nil)
return str
}
} catch {
}
return nil
}
}
HTMLPage.html
<div style="font-family:'Helvetica'; font-size: 11pt;"><div class="feed-description"><p>The apple tree (Malus pumila, commonly and erroneously called Malus domestica) is a deciduous tree in the rose family best known for its sweet, pomaceous fruit, the apple. link It is cultivated worldwide as a fruit tree, and is the most widely grown species in the genus Malus. The tree originated in Central Asia, where its wild ancestor, Malus sieversii, is still found today. Apples have been grown for thousands of years in Asia and Europe, and were brought to North America by European colonists. Apples have religious and mythological significance in many cultures, including Norse, Greek and European Christian traditions. link text text text</p></div></div>
Result

Resources