How to give dynamic width for childStackview in parentStack in Swift - swift

I using stackview in tableview cell
I have one parentStackview with two childStackviews
for parentStackview i have given constraints like below
leading = 10, trailing = 10, top = 10, height = 50
for two childStackviews in parentStackview i have given like this in storyboard
now if i hide childOneStack then childTwoStack showing in full width in parentStackview.. but i dont want like that i need childTwoStack should half of the parentStackview when i hide childOneStack
code to hide childOneStack in tableview cell:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ViewTableVIewCell", for: indexPath) as! ViewTableVIewCell
let bidData = viewData?.result?.bids?[indexPath.row]
if awardData?.status == "A"{
cell.childOneStack.isHidden = true
cell.childTwoStack.frame = CGRect(x: 0, y: 0, width: 200, height: 40)
}
}
class ViewTableVIewCell: UITableViewCell {
#IBOutlet weak var parentStackview: UIStackView!
#IBOutlet weak var childOneStack: UIStackView!
#IBOutlet weak var childTwoStack: UIStackView!
}
error O/p: this is childTwoStack showing full width in parentStackview, please guide me to solve this

You could embed a stack view, which you plan to hide/unhide, in a UIView - this container view will take half of the parent stack even when child stack is hidden.
You could not hide you views, but change its alpha to 0 - in this case you need to disable user interaction, since the views will be transparent, but still interactable.

Related

Last UICollectionViewCell appearing different to the others

I'm creating a UICollectionView on my main menu and all the cells look fine bar the last one, where the image is not centered relative to the cell- it appears to be anchored to the top left corner of the cell (not sure about that though).
here is the image that contains the problem.
I didn't really know where to start with this, as all the cells use the same code and constraints.
I checked that it wasn't an image issue by repeating a previously used image (see above screenshot)
My only idea is that the final cell is in a row on its own whereas the other rows have two cells per row.
extension MainMenuViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return mainMenuOptions.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MainMenuCell", for: indexPath) as! MainMenuCollectionViewCell
let imageView = cell.mainMenuImage!
let label = cell.mainMenuLabel!
imageView.image = mainMenuImages[indexPath.item]
imageView.frame.size.height = cell.frame.size.width - 5
imageView.frame.size.width = cell.frame.size.width - 10
cell.mainMenuLabel.text = mainMenuOptions[indexPath.item]
let labelText = cell.mainMenuLabel!
label.frame.size.height = Utils.heightForView(text: labelText.text!, font: labelText.font!, width: cell.frame.width)
label.frame.size.width = cell.frame.size.width
label.center.x = cell.frame.size.width / 2
label.center.y = cell.mainMenuImage.frame.size.height + (cell.frame.size.height - cell.mainMenuImage.frame.size.height) / 2
cell.layer.borderColor = UIColor.darkGray.cgColor
cell.layer.borderWidth = CGFloat(0.5)
cell.layer.cornerRadius = CGFloat(10)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MainMenuCell", for: indexPath) as! MainMenuCollectionViewCell
let padding: CGFloat = 40
let cellWidth = (collectionView.frame.size.width - padding) / 2
let labelText = mainMenuOptions[indexPath.item]
let cellHeight = cellWidth + Utils.heightForView(text: labelText, font: cell.mainMenuLabel.font!, width: cell.frame.width) + 70
return CGSize(width: cellWidth, height: cellHeight)
}
}
Utils.heightForView() is just a function that calculates the size required for a label to fit all the text. If you need to see it I'll happily add it.
Thanks very much in advance! I hope this is the right amount of code needed but if not let me know and I'll add more.
EDIT: Cell class
class MainMenuCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var mainMenuLabel: UILabel!
#IBOutlet weak var mainMenuImage: UIImageView!
}
When you dequeue a cell in cellForItem it doesn't necessarily have its final size at that point, yet you're depending on that being correct for your code to work.
You should be using autolayout constraints or a stack view inside the cell to give you the correct layout without needing to do any work at dequeue time.
You seem to be trying to give variable heights for your cells as well, which is going to look pretty messy in a flow layout, although it doesn't seem to be making any difference to the cells in the screenshot which I'd expect to have different heights given their titles. Dequeuing a cell in sizeForItem could have some unexpected side effects too, since that's going to mess with the reuse pool.

How to change frame of UICollectionViewCell to reveal hidden button on tap?

I have a custom UICollectionViewCell that has a UIImage and a UIButton.
The frame for the extended cell is 110 x 60. By default it will be 60x60.
When the app loads, I'd like for the cell to start at 60x60 and only show the image. When the cell is tapped, the cell will update to the 110x60 frame and reveal the UIButton that is beside the image.
Currently, my app does load and the cells are 60x60, but due to my auto-layout setup the image is squished and the button is full size. If I tap on the cell, it does update it's frame and it looks great.
The goal is to only see the image first and then see the button after the cell has updated its frame.
I would also like to be able to tap on the cell again and resize it back to 60x60, hiding the button and only showing the image.
Here is what I am currently trying:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.performBatchUpdates(nil, completion: nil)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
switch collectionView.indexPathsForSelectedItems?.first {
case .some(indexPath):
return CGSize(width: 110.0, height: 60.0)
default:
return CGSize(width: 60.0, height: 60.0)
}
}
Per request, my CollectionViewCell Class code:
class myCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var myImageView: UIImageView!
#IBOutlet weak var myButton: UIButton!
var myCellDelegate : myCollectionViewCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
self.layer.cornerRadius = 30
self.layer.masksToBounds = true
myImageView.layer.cornerRadius = myImageView.frame.width / 2
myImageView.layer.masksToBounds = true
}
// MARK: - Actions
#IBAction func myButtonTapped(_ sender: Any) {
self.myCellDelegate?.actionClicked(self)
}
}
To note, there's not much there so not sure if it'll help any. I'm just adjusting the cornerRadius for the cell and my image and then creating a delegate for the action to the button.
I think much depends by your constraints in the nib file.
Option 1
Interface builder > select your ImageView > Right Panel > Size inspector > Play with the "content Hugging Priority" and "content Compression Resistance"
In particular the Horizontal compression resistance of the imageView has to be greater than compression resistance of the button.
The system chooses the view to stretch based of the priorities indicated for these two parameters.
Option 2
Top
+-------------+--------+
| | |
| | |
Left| (Image) |(Button)|Right
| | |
| | |
+-------------+--------+
Bottom
<------------->
Width
Left, Top, Right, Bottom ---> constraint to the cell contentView
Width ---> set to a fixed 60
(Remember to enable clipsToBounds)
When the cell enlarges your button will appear.
You can eventually add an animation.

Custom UITableViewCell programmatically with SWIFT

Attached you may find a picture of (left) my attempt to create a similar (right) UITableView. they look like buttons but they're only cells that can be clicked on as a tableview cell.
I have tried many different things including adding a container window inside a custom cell, adding a UIImage inside the custom cell but I just can't replicate these cells!
I have tried using a custom cell class, I have tried doing it through IB and I for the crazyiness of me, cannot recreate it.
Would anyone be able to give me a hint on how to create the (inside cell) text-bounding box/square? with the different background colour lighting?
If this can easily be done with IB I'd rather do it this way, but if you have a sample customcell class that I can take a look at that'd be greatly appreciated too!
Thank you for taking the time to look at my question.
I have made a sample for you close to your requirement. Have a look
https://github.com/RajanMaheshwari/CustomTableCell
I would like to do this using a UITableView.
My approach will be taking a custom cell and add a UIView with some constraints from left, right, up and down.
Also I will provide the same background color to UITableView, UIView which is the superview and the cell content view and also make the separator of UITableView as None and Selection of TableCell as None so that the UI looks like
Next after applying every constraint and making a CustomCell and making IBOutlets we will jump to code.
I will do all the shadow and outlining in Custom Cell's awakeFromNib method
This will be my CustomTableViewCell class
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var labelBackgroundView: UIView!
#IBOutlet weak var cellLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
labelBackgroundView.layer.borderWidth = 0.5
labelBackgroundView.layer.borderColor = UIColor.lightGrayColor().CGColor
labelBackgroundView.layer.shadowColor = UIColor.lightGrayColor().CGColor
labelBackgroundView.layer.shadowOpacity = 0.8
labelBackgroundView.layer.shadowRadius = 5.0
labelBackgroundView.layer.shadowOffset = CGSizeMake(0.0, 2.0)
labelBackgroundView.layer.masksToBounds = false;
}
I have two outlets.
One is the label in which you will be displaying the name.
Other is the outer view which you want to display with some outlining and shadow.
The ViewController code will be:
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
var array = [String]()
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
array = ["Wealth","Health","Esteem","Relationship"]
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomTableViewCell") as! CustomTableViewCell
cell.cellLabel.text = array[indexPath.row]
cell.labelBackgroundView.tag = indexPath.row
cell.labelBackgroundView.userInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(cellViewTapped))
cell.labelBackgroundView.addGestureRecognizer(tapGesture)
return cell
}
func cellViewTapped(sender:UITapGestureRecognizer) {
let view = sender.view
let index = view?.tag
print(index!)
}
}
Here I have not used didSelectIndex of UITableViewDelegate as I only want the tap on the Outlining LabelBackgroundView and not on complete cell.
So the final outcome is like this
I think you are on the right path. I did something similar in a project. I created a subclass of UIView (too add a shadow to the view) and added a view with this type inside the cell.
class ShadowedView: UIView {
override func awakeFromNib() {
layer.shadowColor = UIColor(red: 157.0/255.0, green: 157.0/255.0, blue: 157.0/255.0, alpha: 0.5).CGColor
layer.shadowOpacity = 0.8
layer.shadowRadius = 5.0
layer.shadowOffset = CGSizeMake(0.0, 2.0)
}
}
Don't forget to add some constraints to the view inside the cell.
You can arrange your collection view layout in "Size insepector"
And customise your image in the cell.

Width of UITableView content view does not match Container

I have a TableVC embedded in a Container. The width of the Container running on an iPhone5 is 320. However the width of the ContentView in the TableView cell is 600. How can I make them match? (+/- padding). Am I missing a constraint? I have also tried setNeedsLayout() and layoutSubViews() in cellForRowAtIndexPath and in the custom cells subclass, but this doesn't seem to work either.
In the picture below, I want the width of the darkgrey to match the light grey (+- padding)
Any help much appreciated.....
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("EventCell") as! CustomResultsTVCell
// cell.setNeedsLayout()
// cell.layoutSubviews()
// cell.layoutIfNeeded()
let barViewWidth = Float(cell.barView.frame.width)
print("barview width is \(barViewWidth)")
// prints 584
let contentViewWidth = cell.myContentView.frame.width
print("contentView width is \(contentViewWidth)")
// prints 600
The CustomCell class is
import Foundation
import UIKit
class CustomResultsTVCell: UITableViewCell {
#IBOutlet weak var myContentView: UIView!
#IBOutlet weak var barView: UIView!
override func awakeFromNib() {
super.awakeFromNib()
// super.layoutSubviews()
// setNeedsLayout()
// layoutSubviews()
layoutIfNeeded()
}
Can you check property of your leading and trailing constraints. Make sure it unchecked relative to margin for both first item and second item.
see attached screenshots if it helps you.
Hope this will help you to fix your issue.

How to add constraints to a Custom UITableViewCell

I have created a custom cell for my table view and it works fine except that my Image View will not align correctly.
Is there a way to add constraints to a custom cell view? Programmatically or otherwise?
This is what my cell looks like in the storyboard - which is what I was hoping to achieve at run time:
But when I demo the app this is what happens:
Here is another image from the storyboard:
View Controller /w TableView
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
println(questions)
println(finalResults)
let theWidth = view.frame.size.width
let theHeight = view.frame.size.height
tableView.frame = CGRectMake(0,0, theHeight, theWidth)
}
Cell View Controller
override func awakeFromNib() {
let theWidth = UIScreen.mainScreen().bounds.width
contentView.frame = CGRectMake(0,0, theWidth, 64)
answerImage.center = CGPointMake(115, 15)
}
You only have to set up your constraints correctly. Indeed, even if Add Missing Constraints and Reset to Suggested Constraints are handy sometimes they don't know what you want, thus the result cannot always be what you expect.
What you might want to do here is the following.
For you question label set it in center Y of it's container and set it's leading space to the superview. Like so :
Then for you image, you want to set it in center Y of it's container too and set a ratio 1:1 on it. Like so :
Note that you might also want to check the width and height if you don't want your image to upscale (if you set a bigger cell on some device).
You should now have something like that :
And the result :
Let me know if it helped.
PS : I don't have your image so I've just set a background color on the uiimageview
Assuming that you started with a View Controller, Dragged a table and a Cell into the table...
in ViewController: UIViewController...{
#IBOutlet weak var resultsTable: UITableView! // connect to tableView
override func viewDidLoad() {
super.viewDidLoad()
let theWidth = view.frame.size.width
let theHeight = view.frame.size.height
resultsTable.frame = CGRectMake(0,0, theWidth, theHeight)
}
}
in UITableViewCell file:
#IBOutlet weak var imageView: UIImageView!
override func awakeFromNib() {
let theWidth = UIScreen.mainScreen().bounds.width
contentView.frame = CGRectMake(0,0 theWidth, 64)
imageView.center = CGPointMake(115, 15) //mess around with these #
}