uiCollectionView inside a uiCollectionViewCell is not scrolling horizontally - swift

Hey Everyone and thank you for taking your time to view this, I am trying to make a uiCollectionView scroll horizontally within a uiCollectionViewCell, the background and elements are showing but im unable to scroll, the uiCollectionViewcontaining the uiCollectionViewCell (which contains the uiCollectionView i need to scroll horizontally) in scrolling vertically as expected. Below are the relative classes:
The uiCollectionView and its uiCollectionViewCells which contains the uiCollectionView that needs horizontal scrolling, in the collectionView method the cases that needs scrolling are Prop4 and Countries:
lazy var collView: UICollectionView = {
let sub = SubclassedCollectionViewCell.self
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: self.view.frame.width, height:self.view.frame.height/100)
layout.scrollDirection = .vertical
// layout.minimumLineSpacing = 1000
layout.sectionInset = UIEdgeInsets(top:100, left: 0, bottom: 100, right: 0)
print("the frame",self.view.frame)
let view = UICollectionView(frame: CGRect(x:0, y:0, width: self.view.frame.width, height: self.view.frame.height), collectionViewLayout: layout)
view.register(sub, forCellWithReuseIdentifier: "profInfo")
view.backgroundColor = .clear
view.isUserInteractionEnabled = true
view.dataSource = self
view.delegate = self
return view
}()
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "profInfo", for: indexPath) as! SubclassedCollectionViewCell
myCell.isUserInteractionEnabled = true
myCell.frame = CGRect(x: 10, y: (indexPath.row+1)*75, width: Int(self.view.frame.width) - 10, height: 50)
myCell.backgroundColor = .clear
let v = UIView(frame: CGRect(x: 0, y: 0, width: 150, height: 50))
let v2 = UIView(frame: CGRect(x: 150, y: 0, width: Int(self.view.frame.width) - 160, height: 50))
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
let label2 = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
let imageV = UIImageView(frame: CGRect(x: 0, y: 12.5, width: 25, height: 25))
let imageV2 = UIImageView(frame: CGRect(x: 0, y: 12.5, width: 25, height: 25))
label.center = CGPoint(x: 150, y: 25)
label.textColor = .white
label2.textColor = .white
label2.center = CGPoint(x: 115, y: 25)
label2.textAlignment = .center
imageV2.center = CGPoint(x: 115, y: 25)
label.text = prof!.arrInfo[indexPath.row].title + ":"
print("array info", prof!.arrInfo)
switch(prof!.arrInfo[indexPath.row].title){
case "Prop1" :
imageV.image = UIImage(named: "art.scnassets/prop1.png")?.resized(to: CGSize(width: 10, height: 10))
label2.text = prof!.arrInfo[indexPath.row].text
v2.addSubview(label2)
break;
case "DOB" :
imageV.image = UIImage(named: "art.scnassets/DOB.png")?.resized(to: CGSize(width: 10, height: 10))
label2.text = getDOBFormat(dateStr: prof!.arrInfo[indexPath.row].text!)
v2.addSubview(label2)
break;
case "Prop3" :
imageV.image = UIImage(named: "art.scnassets/prop3.png")?.resized(to: CGSize(width: 10, height: 10))
imageV2.image = UIImage(named: prof!.arrInfo[indexPath.row].text!)?.resized(to: CGSize(width: 10, height: 10))
break;
case "Prop4" :
imageV.image = UIImage(named: "art.scnassets/prop4.png")?.resized(to: CGSize(width: 10, height: 10))
collectionViews[prof!.arrInfo[indexPath.row].title] = GeneralCollectionView()
collectionViews[prof!.arrInfo[indexPath.row].title]?.type = "Images"
collectionViews[prof!.arrInfo[indexPath.row].title]?.data = prof!.arrInfo[indexPath.row].selected
myCell.contentView.addSubview(collectionViews[prof!.arrInfo[indexPath.row].title]!.Container)
break;
case "Countries" :
imageV.image = UIImage(named: "art.scnassets/translation.png")?.resized(to: CGSize(width: 10, height: 10))
collectionViews[prof!.arrInfo[indexPath.row].title] = GeneralCollectionView()
collectionViews[prof!.arrInfo[indexPath.row].title]?.type = "Countries"
collectionViews[prof!.arrInfo[indexPath.row].title]?.data = prof!.arrInfo[indexPath.row].selected
myCell.contentView.addSubview(collectionViews[prof!.arrInfo[indexPath.row].title]!.Container)
break;
case "location":
imageV.image = UIImage(named: "art.scnassets/location.png")?.resized(to: CGSize(width: 10, height: 10))
label2.text = prof!.arrInfo[indexPath.row].text
v2.addSubview(label2)
break;
default:
break;
}
v.addSubview(label)
v.addSubview(imageV)
v2.addSubview(imageV2)
myCell.contentView.addSubview(v)
myCell.contentView.addSubview(v2)
return myCell
}
And this is the uiCollectionView that needs Horizontal scrolling and thats within the uiCollectionViewCell:
public class GeneralCollectionView:NSObject,UICollectionViewDelegate,UICollectionViewDataSource{
weak var parent:AnyObject?
var data:[String]?
var type:String?
lazy var Container: UICollectionView = {
let sub = SubclassedCollectionViewCell.self
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 50, height:50)
layout.scrollDirection = .horizontal
let view = UICollectionView(frame: CGRect(x:150, y:0, width: 250, height: 50), collectionViewLayout: layout)
view.showsHorizontalScrollIndicator = false
view.isDirectionalLockEnabled = true
view.isScrollEnabled = true
view.isPagingEnabled = true
view.isUserInteractionEnabled = true
view.alwaysBounceHorizontal = true
view.clipsToBounds = true
view.translatesAutoresizingMaskIntoConstraints = false
view.register(sub, forCellWithReuseIdentifier: "myGenCell")
view.dataSource = self
view.delegate = self
view.backgroundColor = .white
layout.sectionInset = UIEdgeInsets(top:0, left: 10, bottom: 0, right: 10)
layout.minimumLineSpacing = 10 // space between rows
layout.minimumInteritemSpacing = 5 // space between items in the same
layout.itemSize = CGSize(width: 50, height: 50)
return view
}()
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data!.count
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "myGenCell", for: indexPath) as! SubclassedCollectionViewCell
myCell.isUserInteractionEnabled = true
if type == "Countries"{
let country = data![indexPath.item].split(separator: "-")
let label = UILabel()
label.frame.size = CGSize(width: 50, height: 50)
label.text = countryFlag(country: String(country[1]))
label.center = CGPoint(x: 30, y: 25)
myCell.contentView.addSubview(label)
print(label, countryFlag(country: String(country[1])))
} else {
let val = data![indexPath.item]
let imgView = UIImageView()
imgView.frame.size = CGSize(width: 20, height: 20)
imgView.image = UIImage(named: val)?.resized(to: CGSize(width: 25, height: 25))
imgView.center = CGPoint(x: 30, y: 25)
myCell.contentView.addSubview(imgView)
}
return myCell
}
}

It is because v2 is added after the horizontal collection view, therefore coming on top blocking all user interactions like your scroll gestures.
Give all your views different background colors to debug this sort of thing.
Set isUserInteractionEnabled = false to v2 and any other view blocking your scroll gestures.
Besides that,
Check out Modern collection views to get some examples of how to build a collection view.
Checkout Auto layout to properly size your views.

Related

Messaging App: Textview not autoresizing it's height to display full message

For the ChatLogController of my messaging feature, I'm having trouble getting the message bubble to automatically adjust its size based on its textView content size. It's showing only one line from the textview as the rest of the text is truncated. Here's how I've defined my textView and the message bubbleContainer:
private let textView: UITextView = {
let tv = UITextView()
tv.backgroundColor = .clear
tv.font = .systemFont(ofSize: 16)
tv.isScrollEnabled = false
tv.isEditable = false
tv.textColor = .white
return tv
}()
private let bubbleContainer: UIView = {
let view = UIView()
view.backgroundColor = .systemPurple
return view
}()
And here are the constraints:
addSubview(bubbleContainer)
bubbleContainer.layer.cornerRadius = 12
bubbleContainer.anchor(top: topAnchor, bottom: bottomAnchor)
bubbleContainer.widthAnchor.constraint(lessThanOrEqualToConstant: 250).isActive = true
bubbleLeftAnchor = bubbleContainer.leftAnchor.constraint(equalTo: profileImageView.rightAnchor, constant: 12)
bubbleLeftAnchor.isActive = false
bubbleRightAnchor = bubbleContainer.rightAnchor.constraint(equalTo: rightAnchor, constant: -12)
bubbleRightAnchor.isActive = false
bubbleContainer.addSubview(textView)
textView.anchor(top: bubbleContainer.topAnchor, left: bubbleContainer.leftAnchor,
bottom: bubbleContainer.bottomAnchor, right: bubbleContainer.rightAnchor,
paddingTop: 4, paddingLeft: 12, paddingBottom: 4, paddingRight: 12)
The ChatLogController is a UICollectionViewController, and this is the way I've set up sizeForItemAt:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 50)
let estimatedSizeCell = MessageCell(frame: frame)
estimatedSizeCell.message = messages[indexPath.row]
estimatedSizeCell.layoutIfNeeded()
let targetSize = CGSize(width: view.frame.width, height: 1000)
let estimatedSize = estimatedSizeCell.systemLayoutSizeFitting(targetSize)
return .init(width: view.frame.width, height: estimatedSize.height)
}
The delegate is set to self but it seems as if the function is not even being called.
in the pic below, you can see how the messages are being truncated and the cell height is stuck to 50 pixels, where it should have been adjusted to display the rest of the message:
Inside cell take label with 0 number of lines which has following constraints:
Leading: Grater than 90 superview
All other with as usual

Unable to Format the Section Header of UITableView

One View Controller which has three Table Views in it. I am struggling with formatting and setting the section header for each table.My func for viewForHeaderInSection is attached below
My Goal is to achieve something like the image. Struggling to format and design the section header for each of the table views. Using the attached code get the Terminating app due to uncaught exception 'CALayerInvalid', reason: 'layer <CALayer: 0x12cc80610> is a part of cycle in its layer tree' error message
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if(tableView == firstTableView){
let button = UIButton(frame: CGRect(x: 270, y: 15, width:20 , height: 20))
button.tag = section
button.setImage(UIImage(named: "InfoIcon"), for: UIControl.State.normal)
button.addTarget(self,action:#selector(buttonClicked),for:.touchUpInside)
let view = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
view.addSubview(button)
let label = UILabel(frame: CGRect(x: 12, y: 7, width: tableView.frame.size.width, height: 30))
label.font = UIFont.systemFont(ofSize: 24)
label.textColor = .white
label.text = "Learn More"
view.addSubview(label)
view.backgroundColor = UIColor.gray // Set your background color
}
else if (tableView == secondTableView) {
let button = UIButton(frame: CGRect(x: 270, y: 15, width:20 , height: 20))
button.tag = section
button.setImage(UIImage(named: "InfoIcon"), for: UIControl.State.normal)
button.addTarget(self,action:#selector(buttonClickedSecond),for:.touchUpInside)
let view = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
view.addSubview(button)
let label = UILabel(frame: CGRect(x: 12, y: 7, width: tableView.frame.size.width, height: 30))
label.font = UIFont.systemFont(ofSize: 24)
label.textColor = .white
label.text = "Get Support"
view.addSubview(label)
view.backgroundColor = UIColor.gray
}
else if (tableView == thirdTableView)
{
let button = UIButton(frame: CGRect(x: 270, y: 15, width:20 , height: 20))
button.tag = section
button.setImage(UIImage(named: "InfoIcon"), for: UIControl.State.normal)
button.addTarget(self,action:#selector(buttonClickedThird),for:.touchUpInside)
let view = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
view.addSubview(button)
let label = UILabel(frame: CGRect(x: 12, y: 7, width: tableView.frame.size.width, height: 30))
label.font = UIFont.systemFont(ofSize: 24)
label.textColor = .white
label.text = "Community"
view.addSubview(label)
view.backgroundColor = UIColor.gray
}
return view
}
Any help and assistance will be appreciated. Thanks!
In your viewForHeaderInSection func, you are creating a UIView object named view inside each if block. At the end of each if block, that object goes out-of-scope... it no longer exists.
Xcode doesn't give you a warning or error on this line:
return view
because view is an existing object of your controller.
This is one of the reasons it's a bad practice to use "built-in" object names for variables you are creating.
Change the top of your func to this:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
if(tableView == firstTableView){
// etc...
and remove that line from within each of your if blocks.
Better yet, change it to something like:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let myHeaderView = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
if(tableView == firstTableView){
// etc... but change all instances of view. to myHeaderView.
} // end of last if block
return myHeaderView
}

how to add table view footer with one label in swift 5

I want to add only one label at the end of the tableview.
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
customView.backgroundColor = UIColor.red
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
label.text = "app version"
customView.addSubview(label)
sideMenuTableView.tableFooterView = customView
I want to set the customView width equal to main view's width and label should be at the left most corner of the view
Try this with mainView width
let customView = UIView(frame: CGRect(x: 0, y: 0, width: self.mainView.frame.size.width, height: 50))
customView.backgroundColor = UIColor.red
let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.mainView.frame.size.width, height: 50))
label.text = "app version"
label.textAlignment = .left
customView.addSubview(label)
sideMenuTableView.tableFooterView = customView
Swift 5
Add UITableViewDelegate Methods:-
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 40))
footerView.backgroundColor = UIColor.yellow
let labelFooter = UILabel(frame: footerView.frame)
labelFooter.text = "Footer view label text."
labelFooter.textColor = .red
footerView.addSubview(labelFooter)
return footerView
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 40
}

Edit- how can I get UIlabel to get in the middle of the container?

how can i get UIlabel to get in the middle of the container? and that text and view disappear equally and come to the next view.
EDIT: This code is working fine for me now
class TestViewController: UIViewController {
let container = UIView()
let redSquare = UIView()
let blueSquare = UIView()
let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.label.textColor = UIColor.orange
self.label.font = label.font.withSize(25)
self.label.numberOfLines = 0
self.label.center = self.blueSquare.center
self.label.textAlignment = NSTextAlignment.center
self.label.text =
"sosdihfiosdfhsdhfdisfhsdfhdsoifhsdofhsdifhdsofhdsofhsdohdsfdosdohdfh"
self.blueSquare.addSubview(label)
self.label.frame = CGRect(x: 45, y: 120, width: 300, height: 100)
self.container.frame = CGRect(x: 7, y: 200, width: 400, height: 500)
self.view.addSubview(container)
self.redSquare.frame = CGRect(x: 0, y: 0, width: 400, height: 500)
self.blueSquare.frame = redSquare.frame
self.redSquare.backgroundColor = UIColor.darkGray
self.blueSquare.backgroundColor = UIColor.darkGray
self.container.addSubview(self.redSquare)
}
Define two labels like:
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 30))
let label2 = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 30))
then inside viewDidLoad() before adding redSquare to container fix some labels's property and add label's to blue and red square:
label.center = self.redSquare.center
label.textAlignment = NSTextAlignment.center
label.text = "same text"
label2.textAlignment = NSTextAlignment.center
label2.center = self.blueSquare.center
label2.text = "same text"
self.blueSquare.addSubview(label2)
self.redSquare.addSubview(label)

Making UITableView drop down with stackview

I am trying to achieve a UITableView drop down when I click on a button. Initially the tableView should be hidden, and when user presses button, it should drop down. I have been trying to achieve this with a UIStackView but to no success. Maybe I am doing it wrong or maybe there is another approach do do this.
let stackView = UIStackView()
var btn: UIButton!
var myTableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
myTableView.delegate = self
myTableView.dataSource = self
myTableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 1))
myTableView.frame = CGRect(x: 0, y: 0, width: 300, height: 200)
myTableView.center = CGPoint(x: self.view.frame.width/2, y: self.view.frame.height/2)
myTableView.showsVerticalScrollIndicator = false
btn = UIButton(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 50))
btn.backgroundColor = UIColor.blue.withAlphaComponent(0.3)
btn.setTitle("DropDownMenu", for: UIControlState.normal)
btn.titleLabel?.textColor = .white
btn.titleLabel?.textAlignment = .center
btn.center = CGPoint(x: self.view.frame.width/2, y: myTableView.center.y - myTableView.frame.height/2 - btn.frame.height/2)
btn.addTarget(self, action: #selector(btnPressed), for: UIControlEvents.touchUpInside)
stackView.axis = UILayoutConstraintAxis.vertical
stackView.distribution = UIStackViewDistribution.equalSpacing
stackView.alignment = UIStackViewAlignment.center
stackView.spacing = 16.0
stackView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(btn)
stackView.addSubview(myTableView)
self.view.addSubview(stackView)
}
#objc func btnPressed() {
UIView.animate(withDuration: 1) {
self.myTableView.isHidden = !self.myTableView.isHidden
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "This is cell " + indexPath.row.description
cell.textLabel?.textColor = .black
return cell
}
I can get the tableView to disappear but with no animations. Any thoughts?
The approach I ended up taking was not going via a UIStackView but insead simply having a button that animates the tableView's frame. The frame is initially set to the width of the screen and a height of 0. When user presses button, I set the height.
UIView.animate(withDuration: 0.25, animations: {
self.menuTable.frame = CGRect(x: 0, y: (sender.center.y + sender.frame.height/2), width: self.view.frame.width, height: yourHeight)
})