Label, font programmatically - swift

I need help in this view.
I have to solve these things:
- instead of the 2 "duck" labels, I need to have different label.text with different fonts. I used this method here, in which I assign all the fonts to my datasource and assign the label to it by changing the font. the final result must be, for example, "duck" "ciccio" and "another"..
At the moment the view in which to insert the text is not connected to the colors or the fonts, I have to be able to insert the text and then if I click on a color it automatically changes the color to the written text and so the same thing for the fonts ..
What do I have to do?
I am attaching part of the code, only the one in which I put the "duck" label and the controller of the whole view.
that I have now
class CollectionFont: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
weak var delegate: FontDelegate?
var collectionView: UICollectionView?
let cellSpacing:CGFloat = 1
let indexPath: IndexPath
var datasource: [UIFont] = []
var imageArray: Array<UIImageView> = []
var onceOnly = false
init(datasource: [UIFont], index: IndexPath = [0,0]) {
self.indexPath = index
self.datasource = Theme.CustomFontsFamily.customFonts
super.init(nibName: nil, bundle: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.delegate = self
collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewLayout())
collectionView!.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView!)
collectionView!.activate(constraint(edgesTo: self.view))
collectionView!.backgroundColor = Theme.Colors.sky
let collectionViewFlowLayout = UICollectionViewFlowLayout()
collectionView!.setCollectionViewLayout(collectionViewFlowLayout, animated: true)
collectionViewFlowLayout.scrollDirection = .horizontal
collectionViewFlowLayout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
collectionViewFlowLayout.minimumLineSpacing = 0
collectionViewFlowLayout.minimumInteritemSpacing = 0
collectionView!.register(FontCell.self, forCellWithReuseIdentifier: FontCell.reuseIdentifier)
collectionView!.delegate = self
collectionView!.dataSource = self
collectionView!.isPagingEnabled = true
collectionView!.bounces = false
self.collectionView?.reloadData()
}
class FontRound {
let font: UILabel
init(font: UILabel) {
self.font = font
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.datasource.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FontCell.reuseIdentifier, for: indexPath) as! FontCell
cell.array.font = self.datasource[indexPath.row]
return cell
}
//UICollectionViewDelegateFlowLayout - constraint della collecion view da innestare
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = UIScreen.main.bounds.size.width/4
let height = UIScreen.main.bounds.size.width/4
return CGSize(width: width, height: height)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
debugPrint("sucaaaa")
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
var visibleRect = CGRect()
visibleRect.origin = collectionView!.contentOffset
visibleRect.size = collectionView!.bounds.size
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
guard let indexPath = collectionView!.indexPathForItem(at: visiblePoint) else { return }
print(indexPath[1])
self.delegate?.sincronizeScroll(indexPath: indexPath)
}
internal func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if !onceOnly {
//set the row and section you need.
collectionView.scrollToItem(at: self.indexPath, at: UICollectionView.ScrollPosition.right, animated: false)
onceOnly = true
}
}
}
final class CollectionFontView: UICollectionView {
init(_ collectionViewLayout: UICollectionViewLayout) {
super.init(frame: .zero, collectionViewLayout: collectionViewLayout)
self.backgroundColor = UIColor.red
self.showsHorizontalScrollIndicator = false
register(FontCell.self, forCellWithReuseIdentifier: FontCell.reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class FontCell: UICollectionViewCell {
static let reuseIdentifier = "FontCell_RID"
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
var cellID: String?
var array = UILabel().then{
$0.text = "duck"
$0.font = UIFont(name:"Jellee-Roman",size:15)
$0.contentMode = UIView.ContentMode.scaleAspectFit
$0.layer.cornerRadius = (((UIScreen.main.bounds.size.width/8)*0.8)/2)
}
func setupViews(){
self.addSubview(self.array)
self.array.activate([
array.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.8),
array.heightAnchor.constraint(equalTo: self.array.widthAnchor),
array.centerXAnchor.constraint(equalTo: self.centerXAnchor),
array.centerYAnchor.constraint(equalTo: self.centerYAnchor),
])
}
func setContents(container: UILabel) {
for sv in self.contentView.subviews {
sv.removeFromSuperview()
}
self.contentView.addSubview(container)
container.activate(constraint(edgesTo: self.contentView))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Related

Setting imageView.image causes unbounded memory growth

Steps
Create UIImages in array
Load UIImage into reusable collection view cell
Scroll
View memory XCode
Code that repros the issue
import UIKit
class Cell: UICollectionViewCell {
static let ReuseIdentifier = "reuseID"
var imageView: UIImageView
override init(frame: CGRect) {
imageView = UIImageView()
super.init(frame: frame)
addSubview(imageView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
imageView.frame = bounds
super.layoutSubviews()
}
func configureWith(image: UIImage) {
imageView.image = image
layoutSubviews()
}
}
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var images:[UIImage] = []
var collectionView: UICollectionView
required init?(coder: NSCoder) {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
collectionView.register(Cell.self, forCellWithReuseIdentifier: Cell.ReuseIdentifier)
super.init(coder: coder)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.addSubview(collectionView)
collectionView.frame = view.frame
collectionView.backgroundColor = .green
collectionView.dataSource = self
collectionView.delegate = self
loadMoreImages()
collectionView.reloadData()
}
func loadMoreImages() {
for _ in 0...50 {
images.append(cloneImage(image: UIImage(named: "bigImage")!))
}
}
// MARK: - UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print(images.count)
return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Cell.ReuseIdentifier, for: indexPath) as! Cell
cell.configureWith(image: images[indexPath.row])
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return view.frame.size
}
}
func cloneImage(image:UIImage) -> UIImage {
let newCgIm = image.cgImage!.copy()!
let newImage = UIImage(cgImage: newCgIm, scale: image.scale, orientation: image.imageOrientation)
return newImage
}
Video demo: https://i.stack.imgur.com/QRDWl.gif
Things that resolve the issue
Make UIImages optional, and set UIImages to nil after they've been displayed
Comment out imageView.image = image
Not using cloneImage, and instead images.append(UIImage(named: "bigImage")!)
Any idea what UIImageView is doing under the hood that causes unbounded memory growth? Seems like it's allocating a bunch of memory in the UIImage object that never gets released.

How to update a UICollectionViewCell Label?

I am trying to change a text label in a UICollectionViewCell, but for some reason it just will not update. Any help would be aprreciated. Thanks!
You can use didSet to make your code a bit reactive.
class CollectionViewCell : UICollectionViewCell{
var text = "" {
didSet{
self.label.text = text
}
}
private var label : UILabel = {
let label = UILabel()
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class CollectionViewClass : UIViewController,UICollectionViewDelegate,UICollectionViewDataSource{
var collectionView = UICollectionView()
let id = "cell ID"
override func viewDidLoad() {
super.viewDidLoad()
collectionView = UICollectionView(frame: self.view.frame)
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: id)
collectionView.dataSource = self
collectionView.delegate = self
self.view.addSubview(collectionView)
collectionView.backgroundColor = .white
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: id, for: indexPath) as! CollectionViewCell
cell.text = "some text"
cell.backgroundColor = .red
return cell
}
}
In the above code, cell's text value is given everytime it's loaded. Whenever text is set, didset is called which updates the label value.

Swift Add different actions to cells on a UICollectionView

I don't know where to start, I have a UICollectionView with multiple cells filled with a UIImage. I want each cell/UIImage to do a different action on a fingertap. Can someone pinpoint me in the right direction here?
The action that I have is a #IBAction from a UIButton, I know want have that action on a cell in the UICollectionView..
( I Guess I have to do something with the 'let cell = countryCollectionView.dequeueReusableCell' ?
import UIKit
class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
#IBOutlet weak var soundsCollectionView: UICollectionView!
lazy var cv: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
var cc = UICollectionView(frame: .zero, collectionViewLayout: layout)
cc.translatesAutoresizingMaskIntoConstraints = false
cc.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell")
cc.delegate = self
cc.dataSource = self
cc.backgroundColor = .white
return cc
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.addSubview(cv)
cv.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
cv.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
cv.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
cv.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.tag = indexPath.row
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 100)
}
}
class CustomCell: UICollectionViewCell {
lazy var centerImageView: UIImageView = {
var img = UIImageView()
img.translatesAutoresizingMaskIntoConstraints = false
img.image = UIImage(named: "1")
img.clipsToBounds = true
img.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handler(_:)))
tapGesture.numberOfTapsRequired = 1
img.addGestureRecognizer(tapGesture)
return img
}()
#objc private func handler(_ sender: UITapGestureRecognizer) {
print("tapped tag > ", self.tag)
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(centerImageView)
centerImageView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
centerImageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
centerImageView.heightAnchor.constraint(equalToConstant: 80).isActive = true
centerImageView.widthAnchor.constraint(equalToConstant: 80).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I edit as new programmatically example for your problem solution.
class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
lazy var cv: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
var cc = UICollectionView(frame: .zero, collectionViewLayout: layout)
cc.translatesAutoresizingMaskIntoConstraints = false
cc.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell")
cc.delegate = self
cc.dataSource = self
cc.backgroundColor = .white
return cc
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(cv)
cv.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
cv.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
cv.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
cv.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.tag = indexPath.row
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 100)
}
}
class CustomCell: UICollectionViewCell {
lazy var centerImageView: UIImageView = {
var img = UIImageView()
img.translatesAutoresizingMaskIntoConstraints = false
img.image = UIImage(named: "1")
img.clipsToBounds = true
img.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handler(_:)))
tapGesture.numberOfTapsRequired = 1
img.addGestureRecognizer(tapGesture)
return img
}()
#objc private func handler(_ sender: UITapGestureRecognizer) {
print("tapped tag > ", self.tag)
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(centerImageView)
centerImageView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
centerImageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
centerImageView.heightAnchor.constraint(equalToConstant: 80).isActive = true
centerImageView.widthAnchor.constraint(equalToConstant: 80).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
In this scenario, I would avoid using buttons on your cells. Instead you should hook into the didSelectItemAt delegate method and just add the necessary information into a data model:
struct Country {
let imageName: String
let sound: Sound // You didn't specify what type the sound1 object is but you get the gist
}
So your countries array will now contain this new struct instead of just raw Strings:
let countries = [
Country("country1", sound1),
Country("country2", sound2),
...
]
Then you can get the exact sound you want to play from the indexPath passed into didSelectItemAt:
let sound = self.countries[indexPath.row].sound
sound.play()
You'll also need to adjust how you're setting the cell's image in cellForItemAt:
let imageName = self.countries[indexPath.row].imageName
cell.countryImageView.image = UIImage(named: imageName)

Cells not appearing in UICollectionView

I don't understand why my cells aren't showing:
class MenuBar: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
let cellId = "pouet"
lazy var customCollectionView : UICollectionView = {
let layout = UICollectionViewLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = UIColor.gray
cv.dataSource = self
cv.delegate = self
return cv
}()
override init(frame: CGRect) {
super.init(frame: frame)
customCollectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
addSubview(customCollectionView)
addConstraintsWithFormat(format: "H:|[v0]|", views: customCollectionView)
addConstraintsWithFormat(format: "V:|[v0]|", views: customCollectionView)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = customCollectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
print("test")
return cell
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Now my print("test") is not showing either, meaning that the method is actually not called, right? So what is wrong ?
Change this line of code:
let layout = UICollectionViewLayout()
To:
let layout = UICollectionViewFlowLayout()
UICollectionViewLayout is abstract class you can't use it directly.

Swift - Draw lines between several random CGPoints

I am trying to create a simple line graph that should display the average monthly user score. So far I have created a collectionView with a white dot at the top of each cell, but now I would like to have a straight line between each dot. I have added a temporary array for testing purposes.
Since it will be variable server data (the last six months), the location of the dots can be different each time. What should I do to connect the first dot with the second one and the second one with the next one (until all dots are connected)?
User profile data controller
class UserProfileData: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var cellId = "cellId"
let values: [CGFloat] = [4.5, 3.2, 4.8, 5.0, 2.3, 2.9]
init() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
super.init(collectionViewLayout: layout)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView?.dataSource = self
self.collectionView?.delegate = self
collectionView?.backgroundColor = Constants.MAIN_THEME_COLOR
collectionView?.isScrollEnabled = false
collectionView?.register(BarCell.self, forCellWithReuseIdentifier: cellId)
}
// MARK: UICollectionViewDataSource
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return values.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 50, height: view.frame.height - 20)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! BarCell
if let max = values.max() {
let value = values[indexPath.item]
let ratio = value / max
cell.barHeightConstraint?.constant = view.frame.height * ratio
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 4, bottom: 0, right: 4)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
}
My custom cell
// Create custom cell(s)
class BarCell: UICollectionViewCell {
let barView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let barLabel: UILabel = {
let label = UILabel()
label.text = "."
label.textColor = .white
label.font = UIFont.systemFont(ofSize: 70)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
var barHeightConstraint: NSLayoutConstraint?
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(barView)
barView.addSubview(barLabel)
barHeightConstraint = barView.heightAnchor.constraint(equalToConstant: 300)
barHeightConstraint?.isActive = true
barHeightConstraint?.constant = 100
barView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
barView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
barView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
barLabel.centerXAnchor.constraint(equalTo: barView.centerXAnchor).isActive = true
barLabel.topAnchor.constraint(equalTo: barView.topAnchor, constant: 5).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
A UICollectionView has a backgroundView property. You should be able to set the backgroundView of your UICollectionView to a custom UIView that draws the lines between your items.