How to fix UITextView text content position in Swift - swift

I have UIView class and in this class have UITextView for use as inputText
In textViewDidChange from row 2 through 5 with any inter, or adding text, I add the UITextView bounds.size.height as much as need.
The problem is, in rows 3 and 5, first line text does not appear.
To be roughly a row above its own space.
And is created from the bottom of the empty space, without scrolling.
But the text in the 4th row have exact position
class QuestionCell: UIView, UITextViewDelegate{
var paragraph = UITextView()
func setParagraph(){
let frame = CGRect(x: 50,
y: 0,
width: forground.width-55,
height: forground.height)
paragraph.frame = frame
paragraph.isEditable = true
paragraph.delegate = self
// forground is some UIView in this View
forground.addSubview(paragraph)
}
func textViewDidChange(_ textView: UITextView) {
paragraph.bounds.size.height = paragraph.paragraphHeight
}
}
extension UITextView{
var paragraphHeight: CGFloat{
let fixedWidth = self.width
let newSize = self.sizeThatFits(CGSize.init(width: fixedWidth,
height: CGFloat(MAXFLOAT)))
var newFrame = self.frame
newFrame.size = CGSize.init(width: CGFloat(fmaxf(Float(newSize.width),
Float(fixedWidth))),
height: newSize.height)
return newSize.height
}
}

During Creating you need to specify :
paragraph.isScrollEnabled = false
After creating, you may set it back.

Related

Issue centering placeholder inside a textfield

Essentially I have the following code for a textfield to display a button on the right side when a no text is present, I also have some placeholder text text for the textfield that is displaying off center. Is there anyway to have the place holder text stay centered when there is a button in rightViewMode?
let centeredParagraphStyle = NSMutableParagraphStyle()
centeredParagraphStyle.alignment = .center
let attributedPlaceholder = NSAttributedString(string: "Scan", attributes: [NSAttributedString.Key.paragraphStyle: centeredParagraphStyle])
serialTF.attributedPlaceholder = attributedPlaceholder
let wSize = serialTF.frame.size.height - 2
let scanSerialButton = UIButton( type: .custom )
scanSerialButton.setImage(UIImage(named: "barcodeScan"), for: .normal )
scanSerialButton.addTarget( self, action: #selector(scanSerial), for: .touchUpInside )
scanSerialButton.frame = CGRect( x: wSize, y: 0, width: wSize, height: wSize )
let wV = UIView()
wV.frame = CGRect( x:0, y:0, width: wSize * 2, height: wSize )
wV.addSubview(scanSerialButton)
serialTF.rightView = wV;
serialTF.rightViewMode = .unlessEditing;
You can subclass UITextField and it will provide a chance to customize the placeholder frame like this.
class CustomTextField: UITextField {
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
// return what you want from here
}
}
Don't embed the button in a view assign button directly to the rightView
txtField.rightView = scanSerialButton

How can I show the rest of a character that has gone slightly outside of UITextView?

I have a UITextView which changes size depending on the text the user inputs (the purple box), which is inside another UIView (the red box).
But when using a handwritten style font like this, the end character sometimes gets cut off at the edge:
I have tried used text1.clipsToBounds = false but that didn't show the edge of the character. Is there a way to show the full character without changing the width of the text view?
Also here is the code I am using to set up the text view:
let text1 = UITextView()
text1.text = ""
text1.font = UIFont(name: "Gotcha", size: 27)
text1.frame = CGRect(x: 10, y: 5, width: 70, height: 50)
text1.isScrollEnabled = false
text1.delegate = self
text1.textAlignment = .center
text1.isEditable = false
text1.isSelectable = false
holdingView.addSubview(text1)
The frame then gets updated with this function, and whenever the text is changed:
func adjustTextViewSize(_ textView: UITextView) {
let maxWidth = 300
let newSize = textView.sizeThatFits(CGSize(width: maxWidth, height: CGFloat.greatestFiniteMagnitude))
textView.frame = CGRect(x: (textView.frame.minX), y: (textView.frame.minY), width: newSize.width, height: newSize.height)
}
Thanks!
Update:
I solved this by adding an extra 30px to newSize.width for any font that is handwritten:
if fontFile?.isHandwritten == true {
currentView.widthConstraint?.constant = newSize.width + 30
currentTextHoldingView.widthConstraint?.constant = newSize.width + 30
}
call this function for get height according to string length
extension String {
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin,
attributes: [NSAttributedString.Key.font: font], context: nil)
return ceil(boundingBox.height)
}
}

How can I insert image to end of the string and insert more than one image in UITextView with swift?

I created an UITextView and I can add image with image picker into text view. But I have some problem about replacement image. I want add this image end of the text. And I want to add images more than one. (like: text + image + text...). How can I solve this problem ? Can anyone help me ?
let pickImage = UIImageView() // this is for imagepickercontroller
lazy var writePost: UITextView = {
let wpost = UITextView()
let images = pickImage
let attachment = NSTextAttachment()
let attString = NSAttributedString(attachment: attachment)
attachment.image = images.image
images.frame = CGRect(x: 0, y: 0, width: 220, height: 220)
images.contentMode = .scaleAspectFill
wpost.textStorage.insert(attString, at: wpost.selectedRange.location)
wpost.addSubview(images)
wpost.textAlignment = .center
wpost.textColor = UIColor.lightGray
wpost.font = UIFont(name: "AvenirNext-DemiBoldItalic", size: 16)
wpost.isEditable = true
wpost.isScrollEnabled = true
wpost.layer.borderWidth = 1.5
wpost.layer.cornerRadius = 7.0
wpost.layer.borderColor = UIColor.orange.cgColor
wpost.delegate = self
return wpost
}()
What you should do is use UITextView's textContainer's exclusionPaths property. The exclusionPaths property lets you assign an array of UIBezierPaths to your textContainer. When exclusionPaths are set, none of the UITextView's text will appear within these paths. You could then add a UIImageView as a subview of the UITextView's super view placed above the UITextView that has a frame equal to said exclusion path.
The end result will be a UITextView with a UIImageView placed above it. None of the UITextView's text will be blocked by the UIImageView as the UITextView's textContainer's exclusionPaths have instructed the text not to populate there.
Here is an example of some code I've done to do something similar, with variable names changed to match your code a bit:
let imageView: UIImageView!
func addImageView() {
imageView = UIImageView(frame: CGRect(x: textView.frame.maxX - 200, y: textView.frame.maxY - 150, width: 200, height: 150))
textView.superView.addSubview(imageView)
}
func setExclusionPath(for imageView: UIImageView) {
let imageViewPath = UIBezierPath(rect: CGRect(x: textView.frame.maxX - imageView.frame.width, y: textView.frame.maxY - imageView.frame.height, width: imageView.frame.width, height: imageView.frame.height))
textView.textContainer.exclusionPaths.append(imageViewPath)
}
func someMethod() {
addImageView()
setExclusionPath(for: self.imageView)
}
Resources:
exclusionPaths reference from Apple

Multiple UILabel in Page Control

I am trying to do a scrollView + pageControl for multiple UILabel i.e. each view should have 2 UILabel - one for title and one for descriptions.
I am familiar with adding a single UILabel into scrollView + pageControl. The question is how do I add more than one UILabel into the scrollView's subview? I have the following code which works fine for a single UILabel:
#IBOutlet weak var bloggerReviewScrollView: UIScrollView!
#IBOutlet weak var bloggerReviewPageControl: UIPageControl!
var frame = CGRect(x: 0, y: 0, width: 0, height: 0)
var reviews: [Reviews] = [Reviews(name: "NameA", description: "DescriptionA", date: Date.init(), url: nil), Reviews(name: "NameB", description: "DescriptionB", date: Date.init(), url: nil)]
func updateReview() {
reviewPageControl.numberOfPages = reviews.count
for index in 0..<reviews.count {
frame.origin.x = reviewScrollView.frame.size.width * CGFloat(index)
frame.size = reviewScrollView.frame.size
let reviewContent = UILabel(frame: frame)
reviewContent.text = reviews[index].description
reviewContent.numberOfLines = 0
reviewScrollView.addSubview(reviewContent)
}
reviewScrollView.contentSize = CGSize(width: reviewScrollView.frame.size.width * CGFloat(reviews.count), height: reviewScrollView.frame.size.height)
reviewScrollView.delegate = self
}
However, other than reviews[index].description, I also want to display reviews[index].name in a different label so that the style for that label is independent of the style of the description label in the view. Are there any ways for me to do so?
Thanks a bunch!
What you need is to decide where and how you want to display your both labels, meaning label frames, I have divided into two parts you can change the frame based on your requirement and create new Label instance and add that to your reviewScrollView
func updateReview() {
reviewPageControl.numberOfPages = reviews.count
for index in 0..<reviews.count {
frame.origin.x = reviewScrollView.frame.size.width * CGFloat(index)
frame.size = reviewScrollView.frame.size
//title lable
////set title frame based on your requirment
let reviewLabelFrame = CGRect(x: frame.origin.x, y: 0, width: frame.width, height: frame.height/2)
let titleLabel = UILabel(frame: reviewLabelFrame)
titleLabel.text = reviews[index]. name // get name and set the title
titleLabel.numberOfLines = 0
reviewScrollView.addSubview(titleLabel)
//descriptions Label
//set descriptions frame based on your requirment
let desLableFram = CGRect(x: frame.origin.x, y: frame.height/2, width: frame.width, height: frame.height/2)
let desLable = UILabel(frame: desLableFram)
desLable.text = reviews[index].description //get description and set
desLable.numberOfLines = 0
reviewScrollView.addSubview(desLable) //add your descriptions
}
you need to calculate the frames for both the label based on your requirement

How to reload/update UITableView after resizing a cell containing web view dynamically?

I have few sections in table view. One section has only one cell containing a UIWebView. When it got loaded with html, I update cell with correct height as follows:
func webViewDidFinishLoad(webView: UIWebView) {
var frame = webView.frame
frame.size.height = 1
webView.frame = frame
var fittingSize = webView.sizeThatFits(CGSizeZero)
fittingSize = fittingSize.height > CGFloat(100) ? fittingSize : CGSize(width: fittingSize.width, height: CGFloat(100))
frame.size = fittingSize
webView.frame = frame
let cellSize = fittingSize.height;
print(cellSize)
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, fittingSize.width + 7, fittingSize.height + 7)
parent?.reloadTable()
}
In Parent,
func reloadTable() {
//let t = self.numberOfSectionsInTableView(self.tableView)
//self.tableView.reloadData()
self.tableView.setNeedsLayout()
self.tableView.layoutIfNeeded()
//self.tableView.reloadSections(NSIndexSet(index: 4), withRowAnimation: .None)
}
There is an another section under the cell. I tried several ways to update body cell. It got updated but following section header doesn't got moved below with body cells adjusted height.
Now any suggestion please?
Thanks