UITextView height doesn't work on iPhone when I use dynamic content from UITextViewCell. On any iPad it works is well. I already read it(How do I size a UITextView to its content?) but it didn't help me.
My code is below
#IBOutlet weak var textView: UITextView! {
didSet {
textView?.text = textOfText
self.textView.delegate = self
self.textView.editable = false
self.textView.scrollEnabled = false
}
}
#IBOutlet weak var textViewHeight: NSLayoutConstraint! {
didSet {
self.textViewHeight.constant = self.textView.sizeThatFits(CGSizeMake(self.textView.frame.size.width, CGFloat.max)).height
}
}
UPDATED
That is how same text is look on iPhone and iPad.
UPDATED 2
I made following code
#IBOutlet weak var textView: UITextView! {
didSet {
textView?.text = textOfText
self.textView.delegate = self
self.textView.editable = false
self.textView.scrollEnabled = false
var frame: CGRect!
frame = textView.frame
frame.size.height = textView.contentSize.height
textView.frame = frame
}
}
I have the work UITextView height. I deleted #IBOutlet weak var textViewHeight: NSLayoutConstraint! and it works for me. My UITextView code is look as
#IBOutlet weak var textView: UITextView! {
didSet {
textView?.text = textOfText
textView.delegate = self
var frame: CGRect!
frame = textView.frame
frame.size.height = self.textView.contentSize.height
self.textView.frame = frame
}
}
Related
According my question, I have to pass a data to my collection view cell
It made laggy when scroll. It happened because my setup data function, it pass too big of data but I have no idea how to fix it.
My cell class .
class VerificationStepCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var stepLabel: UILabel!
#IBOutlet weak var stepTitleLabel: UILabel!
#IBOutlet weak var stepNoLabel: UILabel!
#IBOutlet weak var iconImageView: UIImageView!
#IBOutlet weak var stepDescriptionLabel: UILabel!
#IBOutlet weak var stepStatusLabel: UILabel!
#IBOutlet weak var stepStatusView: UIView!
#IBOutlet weak var buttonStatus: BaseButton!
var currentStepType: VerifyAccountStepType?
var currentStatus: UserLevelInfoStatus?
var data: HomeModels.ViewModel.VerifyAccountStepModel? = nil
override func awakeFromNib() {
super.awakeFromNib()
self.setupView()
}
private func setupView() {
self.stepStatusView.layer.cornerRadius = self.stepStatusView.frame.height / 2
}
func setupData() {
guard let data = self.data else { return }
self.currentStepType = data.stepType
self.currentStatus = data.stepStatus
self.stepStatusView.isHidden = data.stepStatus == .notVerify
self.stepLabel.text = "Step\(data.stepNo)"
self.stepTitleLabel.text = data.stepTitle
self.stepNoLabel.text = "\(data.stepNo)"
self.iconImageView.image = data.stepIconImage
self.stepDescriptionLabel.text = data.stepDescription
self.stepStatusLabel.text = "home_unverified_account_\(data.stepStatus.rawValue)_status".localized()
switch data.stepStatus {
case .approve:
self.buttonStatus.setIsEnable(false)
self.buttonStatus.setTitle(data.stepButtonTitle, for: .normal)
self.stepStatusView.backgroundColor = UIColor.Yellows.brighterYellow
self.stepStatusLabel.textColor = .black
case .notVerify:
self.buttonStatus.setIsEnable(true)
self.buttonStatus.setTitle(data.stepButtonTitle, for: .normal)
self.stepStatusLabel.textColor = .white
case .reject:
self.buttonStatus.setIsEnable(true)
self.buttonStatus.setTitle("แก้ไข", for: .normal)
self.stepStatusView.backgroundColor = UIColor.Reds.loss
self.stepStatusLabel.textColor = .white
case .pending:
self.buttonStatus.setIsEnable(false)
self.buttonStatus.setTitle(data.stepButtonTitle, for: .normal)
self.stepStatusView.backgroundColor = UIColor.Oranges.deepOrange
self.stepStatusLabel.textColor = .white
}
}
}
I know my data is too big but It have to, Has anyone ever face with this problem?
Thank you
Update solution
It found my problem already, It cause from my localized text function.
After I removed it everything working fine!~
I'm making a chat app and trying to figure out table cells reuse mechanics. I'm having trouble with aligning chat bubbles to left and right, depending on incoming/ougoing message. What i have right now is:
class ConversationTableViewCell: UITableViewCell {
#IBOutlet weak var messageTextLabel: UILabel?
#IBOutlet weak var messageView: UIView?
#IBOutlet weak var trailingPaddingConstraint: NSLayoutConstraint?
#IBOutlet weak var leadingPaddingConstraint: NSLayoutConstraint?
func configure(with data: ConversationViewController.ConversationDataModel.Message) {
messageView?.layer.cornerRadius = 12
messageTextLabel?.text = data.text
switch data.messageType {
case .incoming:
trailingPaddingConstraint?.isActive = false
leadingPaddingConstraint?.isActive = true
messageView?.backgroundColor = UIColor(named: "IncomingMessage") ?? .gray
case .outgoing:
trailingPaddingConstraint?.isActive = true
leadingPaddingConstraint?.isActive = false
messageView?.backgroundColor = UIColor(named: "OutgoingMessage") ?? .green
}
}
}
as you can see i'm enabling or disabling the needed constraint depending on message type, but it seems like these constraints (and only them) reset when a cell is being reused, causing the bubble to align to leading side. What can i do to successfully update constraints and not run into such problem?
I figured out that setting .isActive to false actually removes the constraint (sets the property to nil). As stated in this answer i tried to make constraint class properties not weak and everything worked!
now code looks like this:
class ConversationTableViewCell: UITableViewCell {
#IBOutlet weak var messageTextLabel: UILabel?
#IBOutlet weak var messageView: UIView?
#IBOutlet var trailingPaddingConstraint: NSLayoutConstraint? //not weak
#IBOutlet var leadingPaddingConstraint: NSLayoutConstraint? //not weak
func configure(with data: ConversationViewController.ConversationDataModel.Message) {
messageView?.layer.cornerRadius = 12
messageTextLabel?.text = data.text
switch data.messageType {
case .incoming:
trailingPaddingConstraint?.isActive = false
leadingPaddingConstraint?.isActive = true
messageView?.backgroundColor = UIColor(named: "IncomingMessage") ?? .gray
case .outgoing:
trailingPaddingConstraint?.isActive = true
leadingPaddingConstraint?.isActive = false
messageView?.backgroundColor = UIColor(named: "OutgoingMessage") ?? .green
}
}
}
I am getting an error. It is returning nil on a DispatchQueue call.
DispatchQueue.main.async {
self.headerImageView.image = image // <- CRASH
}
Turns out that this is where I am getting a crash.
headerImageView is just a variable which is not connected to the storyboard via IBOutlet. Here is the entire code:
import UIKit
import WebKit
let offset_HeaderStop:CGFloat = 40.0
let offset_B_LabelHeader:CGFloat = 95.0
let distance_W_LabelHeader:CGFloat = 35.0
class MovieDetailsViewController: UIViewController, UIScrollViewDelegate {
var movie: Movie?
var urlBuilder = MovieUrlBuilder()
var config = TMDBConfiguration()
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var headerView: UIView!
#IBOutlet weak var headerLabel: UILabel!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var genreLabel: UILabel!
#IBOutlet weak var ratingLabel: UILabel!
#IBOutlet weak var releaseLabel: UILabel!
#IBOutlet weak var descriptionText: UITextView!
#IBOutlet weak var trailerContainerView: UIView!
#IBOutlet weak var trailerLabel: UILabel!
#IBOutlet weak var videoContainer: WKWebView!
var headerImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
headerImageView = UIImageView(frame: headerView.bounds)
headerImageView.image = UIImage(named: "Poster")
headerImageView.contentMode = .scaleAspectFill
headerView.insertSubview(headerImageView, belowSubview: headerLabel)
headerView.clipsToBounds = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
fetchPopularMovies()
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offset = scrollView.contentOffset.y
var headerTransform = CATransform3DIdentity
if offset < 0 {
let headerScaleFactor: CGFloat = -(offset) / headerView.bounds.height
let headerSizeVariation = ((headerView.bounds.height * (1.0 + headerScaleFactor)) - headerView.bounds.height)/2.0
headerTransform = CATransform3DTranslate(headerTransform, 0, headerSizeVariation, 0)
headerTransform = CATransform3DScale(headerTransform, 1.0 + headerScaleFactor, 1.0 + headerScaleFactor, 0)
headerView.layer.transform = headerTransform
} else {
headerTransform = CATransform3DTranslate(headerTransform, 0, max(-offset_HeaderStop, -offset), 0)
let labelTransform = CATransform3DMakeTranslation(0, max(-distance_W_LabelHeader, offset_B_LabelHeader - offset), 0)
headerLabel.layer.transform = labelTransform
}
headerView.layer.transform = headerTransform
}
override var preferredStatusBarStyle: UIStatusBarStyle{
return UIStatusBarStyle.lightContent
}
private func fetchPopularMovies() {
if let poster = movie?.backdropPath {
let baseURL = URL(string: config.baseImageURL)!
let url = baseURL.appendingPathComponent("w500").appendingPathComponent(poster)
let request = URLRequest(url: url)
let task = urlBuilder.session.dataTask(with: request) {(data, response, error) in
do {
if let image = UIImage(data: data!) {
DispatchQueue.main.async {
self.headerImageView.image = image // <- CRASH
}
}
}
}
task.resume()
}
}
}
Thank you for the support!
You are initializing the image view in viewDidAppear which will be called after viewWillAppear where the image view is populated. Despite the asynchronous task it's not guaranteed that the view is initialized before being populated.
I recommend to initialize the image view lazily, the benefit is that the property is non-optional and it's initialized once when it's accessed the first time.
lazy var headerImageView: UIImageView = {
let view = UIImageView(frame: self.headerView.bounds)
view.image = UIImage(named: "Poster")
view.contentMode = .scaleAspectFill
self.headerView.insertSubview(view, belowSubview: self.headerLabel)
view.clipsToBounds = true
return view
}()
Your async call is located in fetchPopularMovies, which is called at viewWillAppear. You initialise your image view in viewDidAppear, which is called after viewWillAppear.
Basically, headerImageView is nil.
"But I put the call in an async block! So viewDidAppear should have been called already when I set the image view's image, right?" you said.
Well, relying on async to say "I want this thing to run after a certain method returns" is not a good idea. It is not always guaranteed to do that.
To fix this, you need to initialise header image view before fetchPopularMovies is called. You can put it in viewDidLoad for example.
Can anybody tell me why my photos go beyond the boundary of UIImageView?
The pictures end up covering the buttons below it.
My code:
import UIKit
class ViewController: UIViewController {
#IBOutlet var Photo: UIImageView!
#IBOutlet var QuestionLabel: UILabel!
#IBOutlet var Button1: UIButton!
#IBOutlet var Button2: UIButton!
#IBOutlet var Button3: UIButton!
#IBOutlet var Button4: UIButton!
#IBOutlet var LabelEnd: UILabel!
var CorrectAnswer = String()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
Hide()
Photo.layer.cornerRadius = self.Photo.frame.size.width / 10
Photo.clipsToBounds = true
Photo.layer.masksToBounds = true
Photo.layer.borderWidth = 1
Photo.layer.borderColor = UIColor.blackColor().CGColor
Photo.contentMode = .ScaleAspectFit
Photo.contentMode = .ScaleAspectFill
RandomQuestions()
}
I apologize for being such a novice, just learning how to code.
Are you sure it's going beyond the boundary of your image view?
Try printing out the frame of your view to double check. Doesn't look like you have constraints set up from that screenshot - maybe your image view is sized to fit.
I'm trying to change the labels of a viewController after a certain action is taken from a modal view which triggers an unwind segue.
Once unwind segue happens the labels of the current view (the one which the modal was covering) should be changed.
My current attempt at doing this is resulting in a "unexpectedly found nil while unwrapping an Optional value" error. Here is the code:
class DataViewController: UIViewController {
var experiment: NSDictionary?
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var bodyLabel: UILabel!
#IBOutlet weak var tlRightLine: UIImageView!
#IBOutlet weak var tlLeftLine: UIImageView!
#IBOutlet weak var brRightLine: UIImageView!
#IBOutlet weak var brLeftLine: UIImageView!
#IBOutlet weak var bodyTest: UITextView!
#IBAction func removeExperimentSegue(unwindSegue:UIStoryboardSegue) {
removeExperiment = true
titleLabel.text = "Done"
bodyLabel.text = "Done"
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if let dict: NSDictionary = experiment {
if let title = dict.objectForKey("title") as? String {
self.titleLabel!.text = title
}
if let body = dict.objectForKey("body") as? String {
self.bodyTest!.text = body
}
} else {
self.titleLabel!.text = ""
self.bodyLabel!.text = ""
}
}
}
What am I doing wrong?
I did! I ended up using a global boolean variable. I set it true on the initial load of the menu and then had it flip to false during the unwind segue.
var removeExperiment = false
class DataViewController: UIViewController {
#IBAction func removeExperimentSegue(unwindSegue:UIStoryboardSegue) {
removeExperiment = true
}
if removeExperiment == true {
doneLabel.text = "You've completed this experiment. You won't see it again unless you hit 'Reset' from the Home menu."
}
}
Hope that helps!