change collectionViewCell Label font size when change orientation - swift

I am displaying my data in a collection view. My app supports all orientation, landscape and portrait. I have custom collectionViewCell with label in it. My cell size is
CGSize(width: self.view.frame.width / 3 - 40, height: self.view.frame.width / 3 - 40)`
So, it increase the cell size when I rotate device to landscape mode.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
return
}
flowLayout.invalidateLayout()
}
I have a label in cell
class ChannelViewCell: UICollectionViewCell {
let label : UILabel = {
let label = UILabel()
label.numberOfLines = 2
label.font = UIFont(name: "ProRegular", size: 13)
label.textAlignment = .center
label.textColor = UIColor.white
label.lineBreakMode = .byWordWrapping
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
addConstraintsWithFormat(format: "H:|-5-[v0]-5-|", views: label)
addConstraintsWithFormat(format: "V:|-5-[v0]-5-|", views: label)
}
}
I want to increase font size from 13 to 25 when landscape mode. Is it possible to update font size every time we rotate device ?

override func layoutSubviews() {
super.layoutSubviews()
if UIDevice.currentDevice().orientation.isLandscape.boolValue {
label.font = UIFont(name: "ProRegular", size: 25)
} else {
label.font = UIFont(name: "ProRegular", size: 13)
}
}

Related

CollectionView Cell Changing Size when screen reloads

I am creating a screen where the user can search for films and the results load in a collection View, everything loads perfectly but in the simulator when I clicked "command, shift, A" to change to light mode to make sure the colours would adapt correctly the Cells randomly changed size to full screen instead of what I have set.
This also happens when I leave the application for the home page and then click back into the app. I am creating everything programmatically so would need answer this way please.
Below is the code from my custom cell:
import UIKit
class FavouritesCell: UICollectionViewCell {
static let identifier = "FavouritesCell"
let movieTitle: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.lineBreakMode = .byWordWrapping
label.textColor = .secondaryLabel
//label.text = "Title"
label.adjustsFontSizeToFitWidth = true
label.textAlignment = .center
label.font = label.font.withSize(12)
label.minimumScaleFactor = 0.75
return label
}()
let image : UIImageView = {
let image = UIImageView()
image.clipsToBounds = true
image.translatesAutoresizingMaskIntoConstraints = false
//image.backgroundColor = .yellow
image.layer.cornerRadius = 10.0
return image
}()
let cancelItem : UILabel = {
let label = UILabel()
label.layer.borderWidth = 2.0
label.layer.borderColor = UIColor.systemGray.cgColor
label.text = "X"
label.textAlignment = .center
label.layer.cornerRadius = 15
//label.isHidden = true
return label
}()
override init(frame: CGRect) {
super.init(frame: .zero)
contentView.addSubview(image)
contentView.addSubview(movieTitle)
contentView.addSubview(cancelItem)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
image.frame = CGRect(x: 0, y: 25, width: contentView.width, height: contentView.height - 30 )
movieTitle.frame = CGRect(x: 0, y: 0, width: contentView.width, height: 25)
cancelItem.frame = CGRect(x: image.right - 25, y: image.top , width: 25, height: 25)
}
}
Here is the code from the view controller in relation to the collectionView:
private let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = 2
layout.minimumInteritemSpacing = 2
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.register(FavouritesCell.self, forCellWithReuseIdentifier: FavouritesCell.identifier)
collectionView.clipsToBounds = true
collectionView.backgroundColor = UIColor.systemBackground
return collectionView
}()
NSLayoutConstraint.activate([
searchText.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
searchText.heightAnchor.constraint(equalToConstant: 50),
searchText.leadingAnchor.constraint(equalTo: view.leadingAnchor),
searchText.trailingAnchor.constraint(equalTo: view.trailingAnchor),
collectionView.topAnchor.constraint(equalTo: searchText.bottomAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: (view.width / 3) - 4, height: (view.width / 2) - 2 )
}
image of CollectionView working normally
After the screen has been reloaded
Try to give your imageView a fixed height and fixed width and try it again, It will work

How to fix UITableView not displaying in UIStackView

I followed a tutorial to build a weather app programmatically (without a storyboard) that displays the current city and temperature. I am modifying it to display a 5 day forecast instead of just the current temperature by adding a UITableView, but it is not showing up.
Here is my WeatherView code:
class WeatherView: UIView, UITableViewDelegate, UITableViewDataSource {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setup() {
setupViews()
setupConstraints()
}
private func setupViews() {
self.addSubview(mainStack)
conditionsImageStack.addArrangedSubview(conditionsImageView)
mainStack.addArrangedSubview(conditionsImageStack)
// forecastTable.register(UITableView.self, forCellReuseIdentifier: "forecast")
forecastTable.register(UITableViewCell.self, forCellReuseIdentifier: "forecast")
forecastTable.delegate = self
forecastTable.dataSource = self
mainStack.addArrangedSubview(centerContentStack)
// centerContentStack.addArrangedSubview(temperatureLabel)
centerContentStack.addArrangedSubview(forecastTable)
centerContentStack.addArrangedSubview(cityAndConditionsStack)
cityAndConditionsStack.addArrangedSubview(cityLabel)
cityAndConditionsStack.addArrangedSubview(conditionsLabel)
mainStack.addArrangedSubview(buttonsStack)
buttonsStack.addArrangedSubview(celsiusButton)
buttonsStack.addArrangedSubview(fahrenheitButton)
buttonsStack.addArrangedSubview(UIView(frame: .zero))
}
private func setupConstraints() {
mainStack.pinEdges(to: self)
}
let mainStack: UIStackView = {
let stackView = UIStackView(frame: .zero)
stackView.axis = .vertical
stackView.distribution = .equalSpacing
stackView.spacing = 10
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(top: 10, left: 30, bottom: 30, right: 30)
return stackView
}()
let conditionsImageStack: UIStackView = {
let stackView = UIStackView(frame: .zero)
stackView.axis = .vertical
stackView.distribution = .equalSpacing
stackView.alignment = .trailing
stackView.spacing = 10
return stackView
}()
let cityAndConditionsStack: UIStackView = {
let stackView = UIStackView(frame: .zero)
stackView.axis = .vertical
stackView.distribution = .fillProportionally
stackView.spacing = 10
return stackView
}()
let centerContentStack: UIStackView = {
let stackView = UIStackView(frame: .zero)
stackView.axis = .vertical
stackView.distribution = .fillProportionally
stackView.alignment = .center
stackView.spacing = 60
return stackView
}()
// TABLE CODE HERE
var animalArray : [String] = ["elephant", "pig", "goat"]
var forecastTable: UITableView = {
let tableView = UITableView()
let estimatedHeight = tableView.numberOfRows(inSection: 3) //You may need to modify as necessary
// let width = parentView.frame.size.width
let width = estimatedHeight
tableView.frame = CGRect(x: 0, y: 0, width: width, height: estimatedHeight)
return tableView
}()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = forecastTable.dequeueReusableCell(withIdentifier: "forecast")
cell?.textLabel!.text = "Success"
return cell!
}
let temperatureLabel: UILabel = {
let label = UILabel(frame: .zero)
label.font = UIFont.systemFont(ofSize: 144)
label.textColor = .white
label.textAlignment = .center
label.text = "18°"
return label
}()
let cityLabel: UILabel = {
let label = UILabel(frame: .zero)
label.font = UIFont.systemFont(ofSize: 36)
label.textColor = .white
label.textAlignment = .center
label.text = "Atlanta"
return label
}()
let conditionsLabel: UILabel = {
let label = UILabel(frame: .zero)
label.font = UIFont.systemFont(ofSize: 20)
label.textColor = .white
label.textAlignment = .center
label.text = "Sunny"
return label
}()
let conditionsImageView: UIImageView = {
let image = UIImage(named: "sun")
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFit
imageView.widthAnchor.constraint(equalToConstant: image!.size.width).isActive = true
imageView.heightAnchor.constraint(equalToConstant: image!.size.height).isActive = true
return imageView
}()
let celsiusButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("°C", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 73)
button.setTitleColor(.white, for: .normal)
return button
}()
let fahrenheitButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("°F", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 73)
button.setTitleColor(.white, for: .normal)
return button
}()
let buttonsStack: UIStackView = {
let stackView = UIStackView(frame: .zero)
stackView.axis = .horizontal
stackView.distribution = .equalCentering
stackView.spacing = 10
return stackView
}()
}
Here is my ViewController code:
class WeatherViewController: UIViewController {
var mainView: WeatherView! { return self.view as! WeatherView }
let presenter: WeatherPresenter!
init(with presenter: WeatherPresenter){
self.presenter = presenter
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init coder not implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
updateBackground()
}
func updateBackground() {
self.mainView.updateGradient(presenter.backgroundColor)
}
override func loadView() {
self.view = WeatherView(frame: UIScreen.main.bounds)
}
}
Here is my UIView + Constraints code:
extension UIView {
func pinEdges(to view: UIView){
self.translatesAutoresizingMaskIntoConstraints = false
self.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
self.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
self.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
self.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
}
}
I have tried forcing it to display by setting the dimensions with tableView.frame = CGRect(x: 0, y: 0, width: width, height: estimatedHeight) but that did not work.
I am registering the table in the view class instead of of the view controller class, but I am not sure if this is the problem or how to modify it correctly.
You're doing a couple things wrong...
First, in your var forecastTable: UITableView = {...} declaration, you have a line:
let estimatedHeight = tableView.numberOfRows(inSection: 3)
But, at that point, the table view has no dataSource -- even if it did, your dataSource has only section. So the value returned is undefined. If Iprint(esttmatedHeight)I get9223372036854775807. So you are trying to set the frame of your table view to9223372036854775807 x 9223372036854775807`
Next, when you add a table view to a stack view, the stack view will try to arrange it based on the stack view's properties and the table view's intrinsic size. However, the table view has no intrinsic size at that point - you must use auto-layout properties.
So, remove the frame setting for your table view, and after you've added it to the stack view, use:
// I'm guessing you want a height based on number of rows * row height?
// so, something like:
let estimatedHeight = CGFloat(3 * 44)
forecastTable.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
forecastTable.widthAnchor.constraint(equalTo: centerContentStack.widthAnchor),
forecastTable.heightAnchor.constraint(equalToConstant: estimatedHeight),
])
That will make the table view the same width as the centerContentStack that holds it, and give it a height.
At this point, you should see your table.
You are adding mainStack to the superView but not specifying it's dimensions. You need to set constrains to mainStack similar this,
mainStack.translatesAutoresizingMaskIntoConstraints = false
mainStack.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
mainStack.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
mainStack.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
mainStack.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
Above code fills the entire super view with mainStack. You can modify this code according to your requirement.

Adjusting UILabel height depending on contents?

I have a custom CollectionViewCell class, which contains a label and an image. Basically, the image will be constrained to the left, top and right of the cell. However, I want its height to vary depending on the height of the UILabel, which in turns is going to be dependent on the contents inside it. Below is my attempt at it:
import UIKit
class CustomCollectionViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .yellow
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
convenience init(cellTextTile text: String) {
self.init()
}
func setupCustomCellElements(cellImageName image: String, cellTitleTextColour textColour: UIColor, cellTitleTextSize textSize: CGFloat, cellTitleFontType fontType: String, cellTitle title: String) {
let cellImage: UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = .clear
imageView.image = UIImage(named: image)
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let cellTitle: UILabel = {
let label = UILabel()
label.textColor = textColour
label.font = UIFont(name: fontType, size: textSize)
label.text = title
label.textAlignment = .center
label.frame.size = CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude)
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.sizeToFit()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
addSubview(cellImage)
addSubview(cellTitle)
NSLayoutConstraint.activate([
cellTitle.bottomAnchor.constraint(equalTo: bottomAnchor),
cellTitle.leftAnchor.constraint(equalTo: leftAnchor),
cellTitle.rightAnchor.constraint(equalTo: rightAnchor),
cellImage.bottomAnchor.constraint(equalTo: cellTitle.topAnchor),
cellImage.topAnchor.constraint(equalTo: topAnchor),
cellImage.leftAnchor.constraint(equalTo: leftAnchor),
cellImage.rightAnchor.constraint(equalTo: rightAnchor)
])
}
}
However, with the above code I am not getting the kind of behaviour I am looking for. I want the height of the UIlabel to change based on its contents. And in turn the height of the image to adjust accordingly?
Regards,
Shadi.
You need a height constraint for the imageView
cellImage.heightAnchor.constraint(equalToConstant: 50), // or any value
Also don't add the properties inside the method setupCustomCellElements make them an instance variables , and add them inside the init function
It's better also to add the views to
contentView.addSubview(cellImage)
contentView.addSubview(cellTitle)
and constrcut the constraints with it

Change label's font size dynamically when scrolling tableView

I have tableView and on top of it an imageView. Made stretchable header with this guide https://github.com/abhimuralidharan/StretchableTableViewHeader-Swift
And now I have to add label on my image. This label should change size/font when tableView is scrolling.
I created my imageView in another class:
class LotteryHeaderView: UIImageView {
let ticketsCountLabel: UILabel = {
let label = UILabel()
label.textColor = .white
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.boldSystemFont(ofSize: 100)
return label
}()
let infoLabel: UILabel = {
let label = UILabel()
label.textColor = .white
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 13, weight: .medium)
label.numberOfLines = 2
label.text = Localizable.all_user_tickets_count()
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubViews([ticketsCountLabel, infoLabel])
ticketsCountLabel.centerX(to: self.centerXAnchor)
.centerY(to: self.centerYAnchor)
infoLabel.top(to: ticketsCountLabel.bottomAnchor, constant: 7)
.width(constant: 184)
.centerX(to: self.centerXAnchor)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Initialized it in my controller:
let imageView = LotteryHeaderView(frame: CGRect(x: 0, y: 0, width: Constants.Size.screenWidth, height: 300))
Setup in viewDidLoad:
imageView.frame = CGRect(x: 0, y: 0, width: Constants.Size.screenWidth, height: 300)
imageView.image = R.image.santa_fe()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
view.addSubview(imageView)
Here func which gets called every time the tableview is scrolled, and it works for my image (it collapsable and stretchable):
func scrollImageInHeader(scrollView: UIScrollView) {
let y = 300 - (scrollView.contentOffset.y + 300)
let height = min(max(y, 60), 450)
imageView.frame = CGRect(x: 0, y: 0, width: Constants.Size.screenWidth, height: height)
}
Tried to add in scrollImageInHeader() code under, from this StackOverFlowAnswer, but it doesn't help
let offset = scrollView.contentOffset.y
let scale = min(max(1.0 - offset / 200.0, 0.0), 1.0)
imageView.ticketsCountLabel.transform = CGAffineTransform(scaleX: scale, y: scale)
Please, any help will be appreciated.
UIScrollView is parent UITableViewController. You use UIScrollView with UIScrollViewDelegate for setup label font size with scrollOffset: CGFloat follow .y
extension ViewController: UIScrollViewDelegate{
func scrollViewDidScroll(_ scrollView: UIScrollView) {
var scrollOffset : CGFloat = scrollView.contentOffset.y
// process with scrollOffset
}
}
Actually I found my mistake. Code from Here helped.
Class LotteryHeaderView I changed to UIView and added there an UIImageView.

Scroll view parallax effect

I made a program from one youtube channel and ran into a problem. I think that it is related to the layout. On different devices displayed differently. And can someone tell me how to fix what text will fit onto another one and how to make the image appear on the whole my CustomView.
import UIKit struct scrollViewDataStruct {
let title: String?
let image: UIImage?
} class ScrollController: UIViewController, UIScrollViewDelegate{
#IBOutlet weak var scrollView: UIScrollView!
var scrollViewData = [scrollViewDataStruct]()
var viewTagValue = 10
var tagValue = 100
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
scrollViewData = [scrollViewDataStruct.init(title: "There was written a very large line that climbs to another line", image: #imageLiteral(resourceName: "knowledge_graph_logo")),
scrollViewDataStruct.init(title: "Second", image: #imageLiteral(resourceName: "knowledge_graph_logo"))]
scrollView.contentSize.width = self.scrollView.frame.width * CGFloat(scrollViewData.count)
var i = 0
for data in scrollViewData {
let view = CustomView(frame: CGRect(x: 10 + (self.scrollView.frame.width * CGFloat(i)), y: 200, width: self.scrollView.frame.width - 75, height: self.scrollView.frame.height - 90))
view.imageView.image = data.image
view.tag = i + viewTagValue
self.scrollView.addSubview(view)
let label = UILabel(frame: CGRect.init(origin: CGPoint.init(x: 0, y: 20), size: CGSize.init(width: 0, height: 40)))
label.text = data.title
label.font = UIFont.boldSystemFont(ofSize: 30)
label.textColor = UIColor.black
label.sizeToFit()
label.tag = i + tagValue
if i == 0 {
label.center.x = view.center.x
} else {
label.center.x = view.center.x - self.scrollView.frame.width / 2
}
self.scrollView.addSubview(label)
i += 1
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView == scrollView {
for i in 0..<scrollViewData.count {
let label = scrollView.viewWithTag(i + tagValue) as! UILabel
let view = scrollView.viewWithTag(i + viewTagValue) as! CustomView
var scrollContentOffset = scrollView.contentOffset.x + self.scrollView.frame.width
var viewOffset = (view.center.x - scrollView.bounds.width / 4) - scrollContentOffset
label.center.x = scrollContentOffset - ((scrollView.bounds.width / 4 - viewOffset) / 2)
}
}
}}class CustomView: UIView {
let imageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = UIColor.darkGray
imageView.contentMode = .scaleAspectFit
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(imageView)
imageView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
imageView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
imageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}}
This is a launch on iPhone 5s
This is a launch on iPhone 8 plus
What you should be doing is setting the width of each UILabel to the size of the CustomView that contains the image, and setting each label's "numberOfLines" to 0 and set the lineBreak to wordWrap. This should, in theory, let the labels only be the width of the images AND let the UILabels fit the size of the text vertically, rather than horizontally - which is what sizeToFit does.