Xcode iOS label resizes UIImage - ios

I am developing an app where I have this problem, regarding showing some products.
The product cell consists of an image and a label under it.
The image and label is inside a UIView because I need corner radius and shadow around the image and label.
But if the label text increases it will resize my image and make it smaller instead of making the parent UIView height larger.
Does anyone know or have an example for that? I want to tell it that it should make the parent UIView bigger instead of making the image inside the UIView smaller.
Image of my problem:

let ratioConstId = "ratio_const"
if let ratioConst = ivPetIcon.constraints.first(where: { $0.identifier == ratioConstId }) {
ivPetIcon.removeConstraint(ratioConst)
}
let ratio = ivPetIcon.image!.size.height / ivPetIcon.image!.size.width
let const = ivPetIcon.heightAnchor.constraint(equalTo: widthAnchor, multiplier: ratio)
const.isActive = true
const.identifier = ratioConstId

Related

Swift, how to add X number of views with constraints dynamically

I am developing a swift application which will fit 10 items on the screen. If I wanted to do this on a screen that would not change size i.e. the user doesn't change orientation or an iPad user does not use split screen, I would be able to detect the width by doing let size = bounds.width/19.
The problem is as the screen size is dynamic so therefor I need to do it with constraints. I would not like to use UICollectionView as that is too heavy and would also not like to use UIStackView if possible as I don't think it supports aspect ratio which I need for circles. I am trying to use UIViews.
Edit:
This is how I want them to look. This will be about 50 high and other information will be underneath.
UIStackView is the right tool for this job. In the future, I recommend more rigorously defining what you want to happen first, then dive into the documentation.
let sv = UIStackView()
sv.spacing = 10
// this means each arranged subview will take up the same amount of space
sv.distribution = .fillEqually
for _ in 0..<50 {
// omitting the rounded corners or any other styling because
// it's not the point of this question
let subview = UIView()
// The stack view will determine the width based on the screen size
// we just need to say that height == width
subview.widthAnchor.constraint(equalTo: subview.heightAnchor).isActive = true
sv.addArrangedSubview(subview)
}
// add your stackview to your view hierarchy and constrain it

TableView Cell with Minor Lag (Async Proper Use?) Swift

I have an array full of Data loading images in a tableView Cell. However I am getting minor lag(more of a glitch) when the table view scrolls on image index.
Array Contains Data(Seems to lag more bigger the bytes)
Data in Bytes(624230 bytes)
Data in Bytes(1619677 bytes)
Data in Bytes(2257181 bytes)
Data in Bytes(1120275bytes)
Not Sure How to properly use Async When the data is loaded.
struct messageCellStruct {
let message: String!
let photoData: Data!
}
var messageArray = [messageCellStruct]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
let message2 = cell?.viewWithTag(2) as! UITextView
var photoUploadData = messageArray[indexPath.row].photoData
let main = DispatchQueue.main
let background = DispatchQueue.global()
let helper = DispatchQueue(label: "another_thread")
if(photoUploadData != nil){
print("Data in Bytes\(String(describing: photoUploadData))")
let fullString = NSMutableAttributedString(string: "")
let image1Attachment = NSTextAttachment()
let newImageWidth = (self.message.bounds.size.width - 20 )
let messageDisplayString = self.messageArray[indexPath.row].message
background.async {
image1Attachment.image = UIImage(data: photoUploadData!)
}
image1Attachment.bounds = CGRect.init(x: 0, y: 0, width: newImageWidth, height: 200)
let image1String = NSAttributedString(attachment: image1Attachment)
fullString.append(image1String)
fullString.append(NSAttributedString(string: messageDisplayString!))
message2.attributedText = fullString
message2.textColor = .white
message2.font = UIFont.systemFont(ofSize: 17.0)
}else {
message2.text = self.messageArray[indexPath.row].message
}
return cell!
}
The reason I introduced the Async in the first place was because of the lag. It lags with and without the Async.
You should never perform any UI operations on background thread.
remove background.async from
background.async {
image1Attachment.image = UIImage(data: photoUploadData!)
}
simply use
image1Attachment.image = UIImage(data: photoUploadData!)
EDIT:
The lag is not because of UIImage(data: photoUploadData!) I agree that it is a synchronous call but that wont create a lag the real culprit is let image1String = NSAttributedString(attachment: image1Attachment) NSAttributedString is known to be notorious.
To test the hypothesis you can comment out
let image1String = NSAttributedString(attachment: image1Attachment)
fullString.append(image1String)
fullString.append(NSAttributedString(string: messageDisplayString!))
message2.attributedText = fullString
message2.textColor = .white
message2.font = UIFont.systemFont(ofSize: 17.0)
and you should not see a lag.
Unfortunately I don't know the way to fix the issue with NSAttributedString we had same issue and it would often add up lag on scrolling huge pile of rows. Hence we decided to opt for DTCoreText
Somehow this performs better than NSAttributedString
EDIT:
We concluded that the delay/lag is probably because of conversion of huge data to NSAttributedString. As all that OP wanna do is show image and text below it n he did not know how to handle multiple components in cell I am updating the answer to same.
I am not claiming that this is the only way to do it this way might help the OP is assumption here
Step1:
Create UITableViewCell xib and drag UIImageView to it.
Now imageViews can take implicit size. What does that mean is UIImageView's can grow based on the image shows. If the images you are loading happen to be in your control (Server sending images is yours) and if your backend team can assure that they wont send crazy big images you dont need height constraint to ImageView.
But more often than not, server team claims that its a client team job. Because you would like to show the image best possible way and showing image with aspect fit and let the bigger part of image being chopped off or if image happens to be small leaving the huge space around image ask the backend team to send aspect ratio as a part of the response.
So in that case create a height constraint to imageView
Create an IBOutlet to the height constraint lets assume you call it as imageHeightConstraint
Now when you load the image in cell, you know that imageView's width will be equal to the width of the cell and you know the aspect ratio of the image to be shown so you can calculate the height of supposed image as
either in cellFroRowAtIndexPath
cell.imageHeightConstraint.constant = cell.bounds.size.width * aspectRatioOfImage
or better if you have configure method in a cell where you would expect cell to configure its subviews then
self.imageHeightConstraint.constant = self.bounds.size.width * aspectRatioOfImage
Obviously you might need to convert it to Float from CGFloat am sure u can do it :)
Now if you dont have any control over image and you are downloading it from some random website and hence dont have aspect ratio info then rather than adding height constraint add aspect ratio constraint to imageView and change imageView content mode to .aspectFit this might have side effects I mentioned above but thats the best you get without any support :)
Now add TextView below imageView
add vertical height constraint between imageView and TextView
Select textView and set scroll enabled as false
Select TextView and change vertical content hugging priority and compression resistance to 999
Thats it :)
Now what have you achieved with all these circus is that now you have a TableViewCell which can take implicit size based on content it has without any ambiguity :)
Now that makes the life easy. Implement tableView delegates and dont forget to use
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0;
Thats it :) Now run your code and enjoy self expanding tableView cells based on the content they show :) And you have the layout u wanted
Hope it helps

Setting size of JTCalendar cell

I am working through the tutorial of JTCalendar (version 6.1.5). When I run on smaller phones such as the iPhone SE, one side of the circle in the Selection View gets clipped. This because the cells are about 45x45 points, but the Selection View's size is 50x50 points and is therefore too large to fully fit into the cell.
How can I make my selection view fit properly into date cells of varying sizes?
How can I get the proper value of cornerRadius for the selection view circle?
I was able to resolve this issue. The problem is that the tutorial set the size of the Selected View and left it at that. What I did was
Made Outlets for both the width and height constraints in CellView.swift
In ViewContoller.swift, I modified cell selection as follows:
if cellState.isSelected {
var parentMinDimension = min(view.frame.width, view.frame.height)
parentMinDimension = round(parentMinDimension - 0.5)
myCustomCell.widthConstraint.constant = parentMinDimension
myCustomCell.heightConstraint.constant = parentMinDimension
myCustomCell.selectedView.layer.cornerRadius = parentMinDimension / 2
myCustomCell.selectedView.isHidden = false
} else {
myCustomCell.selectedView.isHidden = true
}
This gets the parent view and determines the smaller dimension. This needs to be rounded down. I then uses this parent view dimension to set the width and height of the CellView as well as for determining the corner radius.

How do i make the constraints resize the buttons correctly?

I've added a stoplight image and red, yellow, and green buttons. I want to have the buttons resize to iPhone 4S and iPhone 6S screens, but the buttons either disappear off the page or are the wrong size for the iPhone 4S. I thought the number of point would resize proportionately, but it appears it does not. Any help would be appreciated, I really want to understand constraints but I am just not getting it! Normally I would just do a x-position/screensize, y-position/screensize to relocated it, but this could be noticeably too long.
Here is the constraints of the latest incorrect location. When I try to select the stoplight image, it won't provide a constraint for the leading and trailing edge to the stoplight image.
The yellow button is placed against the stoplight image, but it won't resize.
The easiest solution would be to give all images fixed values for their width and height constraints. Then you can align the spotlightImage in the superview as you wish and define the alignment of the circle images relative to the stoplight image.
However, if you would like to stretch the width of the stoplight image depending on the width of the screen, this is a complex problem. I played around a bit trying to define all constraints in storyboard, but could not come up with a proper solution. What one ideally would like to do, for example, is define the centreX of the circles proportionally to the spotlight image's width. Similarly for the y position. Unfortunately this is not possible.
In code one have a little bit more control. Here is a solution that will work. It is not pretty, because you are actually recalculating the width of the spotlightImage, but it works :-)
class ViewController: UIViewController {
lazy var stopLightImageView: UIImageView = {
return UIImageView(image: UIImage(named:"stopLight"))
}()
lazy var circleImageView: UIImageView = {
return UIImageView(image: UIImage(named:"circle"))
}()
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
private func setupViews() {
//Values at start. This is used to calculate the proportional values, since you know they produce the correct results.
let stoplightStartWidth: CGFloat = 540
let stoplightStartHeight: CGFloat = 542
let circleStartWidth: CGFloat = 151
let circleStartLeading: CGFloat = 231
let circleStartTop: CGFloat = 52
let screenWidth = UIScreen.mainScreen().bounds.size.width
let stoplightMargin: CGFloat = 20
self.view.addSubview(stopLightImageView)
stopLightImageView.translatesAutoresizingMaskIntoConstraints = false
//stoplightImage constraints
stopLightImageView.leadingAnchor.constraintEqualToAnchor(self.view.leadingAnchor, constant: stoplightMargin).active = true
stopLightImageView.trailingAnchor.constraintEqualToAnchor(self.view.trailingAnchor, constant: -stoplightMargin).active = true
stopLightImageView.centerYAnchor.constraintEqualToAnchor(self.view.centerYAnchor, constant: 0).active = true
stopLightImageView.heightAnchor.constraintEqualToAnchor(stopLightImageView.widthAnchor, multiplier: stoplightStartWidth/stoplightStartHeight).active = true
self.view.addSubview(circleImageView)
circleImageView.translatesAutoresizingMaskIntoConstraints = false
//circle constraints
circleImageView.widthAnchor.constraintEqualToAnchor(stopLightImageView.widthAnchor, multiplier: circleStartWidth/stoplightStartWidth).active = true
circleImageView.heightAnchor.constraintEqualToAnchor(circleImageView.widthAnchor, multiplier: 1).active = true
let stoplightWidth = screenWidth - 2*stoplightMargin
let stoplightHeight = stoplightWidth * stoplightStartHeight/stoplightStartWidth
circleImageView.leadingAnchor.constraintEqualToAnchor(stopLightImageView.leadingAnchor, constant: stoplightWidth*circleStartLeading/stoplightStartWidth).active = true
circleImageView.topAnchor.constraintEqualToAnchor(stopLightImageView.topAnchor, constant: stoplightHeight*circleStartTop/stoplightStartHeight).active = true
}
}
Constraints are tricky, and it looks like you have a lot going on there. It's hard to tell you exactly what to do for this so, here's what I would try to do if I was having this issue(hopefully one works for you):
Set the images in the Attributes Inspector to either Aspect Fit or Redraw... That should fix your issue with them being different shapes.
Also look through the list of constraints to see if one relies on another, (for example the red and yellow seem to have similar constraints). If they rely on each other, ensure to satisfy any constraints that aren't yet - based off of the "parent" image.
Select everything and set to "Reset to Suggested Constraints". Build and run. If that doesn't fix it then there's only a few things left you can do.
Remove all the constraints on every object. Start with the black image and add missing constraints... or set it to "Center Horizontally in Container". Right click and drag the image or asset to your "view" or to the yellow "First" circle located above.
Hopefully this helps.

iPhone - resizing image and two labels to fit the screen

I'm new to iPhone developing. I have a screen with image, title and content:
Image has dynamic size and also all text can have any length. What I want to achievie is to fit the image exactly in screen and make all labels to be only as long as they should be.
Afterk about 5 hours of work I have:
Working labels length, achieved by setting Lines=0 and Preferred Width=content width
Not working image, which lefts blank spaces
I have read a lot, I understand Content Hugging Priority and Content Compression Resistance Priority. I know differences in UIViewContentMode. I know that I can manually set UIImage.frame=CGRectMake(...). Nothing works. My image is more wider than higher (lets assume that width/height = 3). If I have UIViewContentMode=Aspect Fit then I will have blank space above and below the image. If set to Aspect fill then image is too high and also cropped. Changing frame in code doesn't change anything in view. What I want is to have image with size that was made using Aspect fit, but without blank space.
Finally I dit it. First of all, everyone writes that UIImageView.Frame should be modified to shrink the image, but be aware, that if your view is UITableViewCell then you should do that in layoutSubviews method (remember to invoke super.layoutSubviews() at the begging).
Secondly, make in IB a height constraint for your UIImageView for temporary value (for example 100). You will change that constraint in layoutSubviews method.
And finally: fitting image is NOT about its ratio. Set UIViewContentMode=Aspect Fit. Then the case with blank top and bottom areas occurs only when the initial image is wider than screen. Calculating the proper height should also take place in layoutSubviews.
Example implementation:
override func layoutSubviews() {
super.layoutSubviews()
var imageWidth = (imageViewObject.image?.size.width)!
var imageHeight = (imageViewObject.image?.size.height)!
var frameWidth = UIScreen.mainScreen().bounds.width
var properHeight: CGFloat
if imageWidth > frameWidth {
var ratio = frameWidth / imageWidth
properHeight = imageHeight * ratio
}
else {
properHeight = imageHeight
}
imageHeightConstraint.constant = properHeight
imageViewObject.frame = CGRectMake(0, 0, frameWidth, properHeight)
}

Resources