Swift - Rotated UITextView autosize problem - ios

I use this function to make UITextView auto fit text content when typing. It works fine when the TextView is horizontal but does not work correctly when TextView is rotated. Any ideas how it can be fixed?
func textViewDidChange(_ textView: UITextView) {
let newSize = textView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
textView.frame = CGRect(origin: textView.frame.origin, size: newSize)
}

According to the docs:
When the value of this property is anything other than the identity transform, the value in the frame property is undefined and should be ignored.
I think that might be why your code doesn't work - frame is undefined after you have applied a transform.
Try setting the transform back to identity before setting the frame:
let transform = textView.transform
textView.transform = .identity
let newSize = textView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
textView.frame = CGRect(origin: textView.frame.origin, size: newSize)
textView.transform = transform

I have seen UITextView sometimes does not play good with transformations.
Wrap your UITextView in a UIView. Set top, leading, bottom and trailing constaints of UITextView to UIView. Perform all the transformations on UIView. You should be good to go.

I have the same issue and I saw this problem, after that I fixed it like this;
extension UITextView {
func calculateSize() {
let currentTransform = transform
transform = .identity
let currentCenter = center
let fixedWidth: CGFloat = font == nil ? 300 : text.widthOfString(usingFont: font!) + 16 // 300 for the worst case scenario and 16 is for leading and trailing spaces for content
sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
let newSize = sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
var newFrame = frame
newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
frame = newFrame
center = currentCenter
transform = currentTransform
layoutIfNeeded()
}
}

Related

How to resize a UITextView that automatically resize its width and height based on the content and fixed width when reaches certain value?

I had tried to create the autoresize UITextView with the following code.
func textViewDidChange(_ textView: UITextView) {
let fixedWidth = textView.frame.size.width
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
textView.frame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
}
When i type on the first character, it does not resize the width to the character. The other solution i tried is this.
func textViewDidChange(_ textView: UITextView) {
let fixedWidth = textView.frame.size.width
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
textView.frame.size = CGSize(width: newSize.width, height: newSize.height)
}
It width stuck on the first character, only one character per line with this solutions. How can I solve this ?
Try this:
let maximumWidth: CGFloat = 200 // Change as appropriate for your use.
let newSize = textView.sizeThatFits(CGSize(width: maximumWidth, height: CGFloat.greatestFiniteMagnitude))
textView.frame.size = CGSize(width: newSize.width, height: newSize.height)
You will need to come up with a way to determine the maximum width as I have just hardcoded it for now.
This will expand the UITextView horizontally until 200 points and then start expanding vertically.

Adjust label based on Text given in Text view in swift 3?

I am working on Photo Editing App and i am trying to adjust label Based on Text given in Text View . I have tried Lots of code but it did not work for me. i want to add Label on Image Which is based on text given in my textview as shown in Image given below. I am unable to set width and height of label based on textview's text. I have Tried Following code. Some one please help.
let newWidth: CGFloat = CGFloat(txtView.text.boundingRect(with: txtView.frame.size, options: .usesLineFragmentOrigin, context: nil).size.width)
let Label = UILabel(frame: CGRect(x: 100, y: 100, width: newWidth, height: 100))
imgView?.addSubview(Label)
I have also tried
var maximumLabelSize = CGSize(width: 296, height: FLT_MAX)
var expectedLabelSize: CGSize = yourString.size(withFont: yourLabel.font, constrainedTo: maximumLabelSize, lineBreakMode: yourLabel.lineBreakMode)
//adjust the label the the new height.
var newFrame: CGRect = yourLabel.frame
newFrame.size.height = expectedLabelSize.height
yourLabel.frame = newFrame
I have solved my issue using JLStickerTextView but in this repository its not compatible for Swift 3.0 so i have made changes in project and you can find out Working Project without any errors from her https://github.com/khush004/StickerView/tree/master
func calcheight(strin:String) -> CGFloat
{
let label = UILabel(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.text = strin
label.sizeToFit()
return label.frame.height + 2
}

How can i increase the height of textview in upper side instead of regular bottom side?

I want to increase height of textview according content of textview increase. i tried different way but i did't get solution to increase height in up direction. Attached image
Change frame of UITextView in textViewDidChange delegate method,
func textViewDidChange(_ textView: UITextView) {
let fixedWidth = textView.frame.size.width
textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
var textViewFrame = textView.frame
textViewFrame = CGRect.init(x: textViewFrame.origin.x, y: textViewFrame.origin.y+textViewFrame.height-newSize.height, width: max(newSize.width, fixedWidth), height: newSize.height)
textView.frame = textViewFrame
}
It will increase size of UITextView from bottom.
After setting the text, so in the viewWillLayoutSubView()
let contentSize = textView.sizeThatFits(textView.bounds.size)
After that you will be able to use the contentSize Height:
height: contentSize.height

Content of scrollview clear when taking screenshot

I have a scrollview and i need a screenshot of the complete content of that scrollview, i search and try many solutions on stackoverflow but that provide only the screenshot of the total height of the viewcontroller.
For example if the height of the scrollview is 1096 and Viewcontroller height is 532 , it screenshot the content according to the Viewcontroller height
I found only this code useful on stackoverflow and it return the complete height of the scrollview but it clear the content of scrollview in the Viewcontroller. Any help how to retain the content of scrollview or any better solution to take a complete screenshot in swift. Thankyou
func getImageOfScrollView()->UIImage{
var image = UIImage();
UIGraphicsBeginImageContextWithOptions(self.scrollView.contentSize, false, UIScreen.mainScreen().scale)
// save initial values
let savedContentOffset = self.scrollView.contentOffset;
let savedFrame = self.scrollView.frame;
let savedBackgroundColor = self.scrollView.backgroundColor
// reset offset to top left point
self.scrollView.contentOffset = CGPointZero;
// set frame to content size
self.scrollView.frame = CGRectMake(0, 0, self.scrollView.contentSize.width, self.scrollView.contentSize.height);
// remove background
self.scrollView.backgroundColor = UIColor.clearColor()
// make temp view with scroll view content size
// a workaround for issue when image on ipad was drawn incorrectly
let tempView = UIView(frame: CGRectMake(0, 0, self.scrollView.contentSize.width, self.scrollView.contentSize.height))
// save superview
let tempSuperView = self.scrollView.superview
// remove scrollView from old superview
self.scrollView.removeFromSuperview()
// and add to tempView
tempView.addSubview(self.scrollView)
// render view
// drawViewHierarchyInRect not working correctly
tempView.layer.renderInContext(UIGraphicsGetCurrentContext())
// and get image
image = UIGraphicsGetImageFromCurrentImageContext();
// and return everything back
tempView.subviews[0].removeFromSuperview()
tempSuperView?.addSubview(self.scrollView)
// restore saved settings
self.scrollView.contentOffset = savedContentOffset;
self.scrollView.frame = savedFrame;
self.scrollView.backgroundColor = savedBackgroundColor
UIGraphicsEndImageContext();
return image
}
Using this as I guide, I think you can snapshot any view using:
func snapShot(view:UIView) -> UIImage
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, true, 0)
view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
Though with a scroll view this will only return an image of what's visible in the scroll view's frame, so we can create a helper function:
func snapShotScrollView(scrollView:UIScrollView) -> UIImage
{
let bounds = scrollView.bounds
scrollView.bounds.size = scrollView.contentSize
let image = snapShot(scrollView)
scrollView.bounds = bounds
return image
}
This will briefly adjust our scroll view's bounds to it's content size.
I don't know how performant this code is, but this works for me in a swift playground. For example, running this code:
let scrollView = UIScrollView(frame:CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0))
scrollView.backgroundColor = UIColor.whiteColor()
scrollView.contentSize = CGSize(width: 600.0, height: 600.0)
let blueView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0))
blueView.backgroundColor = UIColor.blueColor()
let redView = UIView(frame: CGRect(x: 200.0, y: 200.0, width: 400.0, height: 600.0))
redView.backgroundColor = UIColor.redColor()
scrollView.addSubview(blueView)
scrollView.addSubview(redView)
let image = snapShotScrollView(scrollView)
Results in
where as calling snapShot by itself only returns a blue square. After the snapshot the scroll view is the original size with the original content.

Setting dynamic height on UItextview to fit content programmatically

Just by programmatically coding, I'm trying to achieve something like below image. TextView and ContainerView are embedded in scrollview although it is not shown in the image.
Here is my code for this.
override func viewDidLoad() {
super.viewDidLoad()
let margin = CGFloat(10)
textView = UITextView()
textView.text = "asdadaasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadaadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadadasdadadaddadd"
let contentSize = textView.sizeThatFits(textView.bounds.size)
textView.frame = CGRectMake(margin, 0, self.view.frame.width - 2 * margin, contentSize.height)
let scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height - 50))
let containerView = UIView(frame: CGRectMake(margin, contentSize.height + margin, self.view.frame.width - 2 * margin, self.view.frame.height))
let button1 = UIButton(frame: CGRectMake(margin, contentSize.height + containerView.frame.height + 2 * margin, (view.frame.width - 2 * margin)/2, 30))
scrollView.contentSize = CGSize(width: self.view.frame.width, height: button1.frame.origin.y + button1.frame.height + margin)
self.view.addSubview(scrollView)
scrollView.addSubview(textView)
scrollView.addSubview(containerView)
scrollView.backgroundColor = UIColor.blueColor()
containerView.backgroundColor = UIColor.yellowColor()
textView.backgroundColor = UIColor.greenColor()
}
The problem is that textview's height is not dynamic to show all content in textview.
I've confirmed that if I add below code in viewdidappear, it does make the height of textview dynamic but it is stacked under Container view because below code runs after ViewDidLoad configured everything.
let contentSize = textView.sizeThatFits(textView.bounds.size)
textView.frame = CGRectMake(margin, 0, self.view.frame.width - 2 * margin, contentSize.height)
What would be the best approach for this kind of problem?
I think this is caused due to rendering order in viewdidload but I'm not 100% sure. It would be great if someone can talk about rendering order too.
To answer the original question, your call to sizeThatFits has no idea how tall the TextView should be because it has no idea how wide you want it to be. I think before the sizeThatFits line you want the following:
textView.frame.size.width = self.view.frame.width - 2 * margin

Resources