Update UICollectionView Width on Device Rotate in Swift - ios

I have custom keyboard with a UICollectionView. The cells do not have a defined size. When rotating the device from portrait to landscape the keyboard resizes appropriately but the UICollectionView stays at the original width.
What is the best way to tackle updating the width to expand to the full available with? How can I update the constraints to the available space?
The UICollectionView is created programmatically and I'm not using a storyboard to implement AutoLayout that way.
override func viewDidAppear(animated: Bool) {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.registerNib(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: kbReuseIdentifier)
collectionView.backgroundColor = UIColor.whiteColor()
self.collectionView.translatesAutoresizingMaskIntoConstraints = true
self.view.addSubview(collectionView)
let collectionViewBottomConstraint = NSLayoutConstraint(item: self.collectionView, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: -40.0)
let collectionViewTopConstraint = NSLayoutConstraint(item: self.collectionView, attribute: .Top, relatedBy: .Equal, toItem: self.view, attribute: .Top, multiplier: 1.0, constant: 10)
let collectionViewLeftConstraint = NSLayoutConstraint(item: self.collectionView, attribute: .LeadingMargin, relatedBy: .Equal, toItem: self.view, attribute: .LeadingMargin, multiplier: 1.0, constant: 0)
let collectionViewRightConstraint = NSLayoutConstraint(item: self.collectionView, attribute: .TrailingMargin, relatedBy: .Equal, toItem: self.view, attribute: .TrailingMargin, multiplier: 1.0, constant: 0)
self.view.addConstraints([collectionViewBottomConstraint, collectionViewTopConstraint, collectionViewRightConstraint, collectionViewLeftConstraint])
}

You need to implement the UICollectionViewDelegateFlowLayout protocol on your view controller.
On viewDidLoad, register for orientation changed notifications:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationDidChange:", name: UIDeviceOrientationDidChangeNotification, object: nil)
Don't forget to remove the observer when the viewController is closed:
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
When the orientation changes, tell the collectionView to update the layout:
func orientationDidChange(notification: NSNotification) {
collectionView!.collectionViewLayout.invalidateLayout()
}
Finally, implement the UICollectionViewDelegateFlowLayout protocol method. On this method you can calculate the size for your collection view cells as needed, by referencing the collectionView frame width or the device screen size:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
// Leave 10px margin on each side, plus 10px between columns
let columns = 2
let margings = 20 + 10 * (columns - 1)
let width = (collectionView.frame.size.width - margings) / columns
let height = width // square cells
return CGSizeMake(width, height)
}
In my case, I want the cells to always be proportional to the portrait screen ratio. Also I have a variable number of columns, but that might not be your case.

Try overriding updateViewConstraints, check what is the current orientation with UIInterfaceOrientationIsPortrait(UIApplication.sharedApplication().statusBarOrientation/UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation and update the constant of certain constraints in your NSAutoLayout logic.

Related

UICollectionView Not Responding to Touch

I am trying to programmatically draw my CollectionView from within a custom class that subclasses UIView. The app loads up with no errors and the CollectionView is being drawn correctly as I can see the cell items, but the CollectionView does not respond to touch. When I try to scroll nothing happens.
I inspected the ViewController using the Debug View Hierarchy button in Xcode to see if there was possibly a view on top. There was not and I could see the cells clearly drawn separately.
Class:
class DrawUI_mainCollectionView : UIView, UICollectionViewDelegate, UICollectionViewDataSource {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
var collectionView : UICollectionView?
private func setup() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: CGFloat(kScreenWidth),height: 137)
let offset = 120.0
let collectionViewFrame = CGRect(x: 0, y: offset, width: Double(kScreenWidth), height: Double(kScreenHeight))
self.collectionView = UICollectionView(frame: collectionViewFrame, collectionViewLayout: layout)
self.collectionView!.alwaysBounceVertical = true
self.collectionView!.delegate = self
self.collectionView!.dataSource = self
self.collectionView!.register(UINib(nibName: "MealCategoryCell", bundle:Bundle.main), forCellWithReuseIdentifier: "cell")
self.addSubview(self.collectionView!)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MealCategoryCell
cell.label.text = "test"
cell.textDescription.text = "textDescription"
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: kScreenWidth, height: 137)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("cell \(indexPath.row)")
}
required init?(coder aDecoder: NSCoder) {
fatalError("no storyboard...")
}
}
How I am implementing it on my ViewController
let collectionView = DrawUI_mainCollectionView()
self.view.addSubview(collectionView)
What am I doing wrong? Thanks in advance.
I think your main issue is not using auto layout, if you will add auto layout for the items:
view that contains the collectionView in viewController
collectionView in the view
It should work, the implementation:
In ViewController:
let collectionView = DrawUI_mainCollectionView()
collectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(collectionView)
NSLayoutConstraint(item: collectionView , attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leadingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .topMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottomMargin, multiplier: 1.0, constant: 0.0).isActive = true
Inside the view:
private func setup() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: CGFloat(kScreenWidth),height: 137)
let offset = 120.0
let collectionViewFrame = CGRect(x: 0, y: offset, width: Double(kScreenWidth), height: Double(kScreenHeight))
self.collectionView = UICollectionView(frame: collectionViewFrame, collectionViewLayout: layout)
self.collectionView!.alwaysBounceVertical = true
self.collectionView!.delegate = self
self.collectionView!.dataSource = self
self.collectionView!.register(UINib(nibName: "MealCategoryCell", bundle:Bundle.main), forCellWithReuseIdentifier: "cell")
self.collectionView!.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(self.collectionView!)
NSLayoutConstraint(item: collectionView , attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leadingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .top, relatedBy: .equal, toItem: self, attribute: .topMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottomMargin, multiplier: 1.0, constant: 0.0).isActive = true
}

Mix Objective-C delegate method with swift file

I started working on this App in Objective-C. Through some problems I had recently, I started using swift for some Features. Everything is working fine. Now I started building a new Feature and decided to do it in swift. I wrote the code in a Swift only Project, for testing. Everything is working fine in the test version, but when implementing it in my main Project I faced a Problem.
The Problem is that I set the view options in the delegate file like this:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
return true
}
But because my main Project delegate file is in Objective-C I dont know how to get this to work in my Swift file in the Objective-C Project. I tried setting the view in the viewDidLaunch file. But that doesnt work.
So i am asking myself if it is actually possible to set the code for my swift file in the Objective-C delegate method in objective-c. But for my Project I would like to set the view options inside the swift file. So this is what I tried so far:
import UIKit
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var window: UIWindow?
override func viewDidLoad() {
super.viewDidLoad()
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
navigationItem.title = "Home"
collectionView?.backgroundColor = UIColor.white
collectionView?.register(VideoCell.self, forCellWithReuseIdentifier: "cellId")
}
//number of items
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 200)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
class VideoCell: UICollectionViewCell{
override init(frame:CGRect){
super.init(frame: frame)
setupViews()
}
let thumbnailImageView: UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = UIColor.blue
return imageView
}()
let userProfileImageView: UIImageView = {
let imageView = UIImageView ()
imageView.backgroundColor = UIColor.green
return imageView
}()
let separatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black
return view
}()
let titleLabel: UILabel = {
let label = UILabel()
label.backgroundColor = UIColor.purple
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let subtitleTextView: UITextView = {
let textView = UITextView()
textView.backgroundColor = UIColor.red
textView.translatesAutoresizingMaskIntoConstraints = false
return textView
}()
func setupViews(){
addSubview(thumbnailImageView)
addSubview(separatorView)
addSubview(userProfileImageView)
addSubview(titleLabel)
addSubview(subtitleTextView)
//Abstand zum Bildschirmrand (Blau)
addConstraintsWithFormat(format: "H:|-16-[v0]-16-|", views: thumbnailImageView)
//Grün
addConstraintsWithFormat(format: "H:|-16-[v0(42)]", views: userProfileImageView)
//vertical constraints / v0 = Blau höhe / v1 = Grün höhe / v2 = Linie höhe
addConstraintsWithFormat(format: "V:|-32-[v0(75)]-8-[v1(44)]-16-[v2(1)]|", views: thumbnailImageView, userProfileImageView, separatorView)
//Abtrennung zwischen Zellen /zweite Zeile wird in "Große Fläche" umgesetzt
addConstraintsWithFormat(format: "H:|[v0]|", views: separatorView)
//top constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: thumbnailImageView, attribute: .bottom, multiplier: 1, constant: 8))
//left constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .left, relatedBy: .equal, toItem: userProfileImageView, attribute: .right, multiplier: 1, constant: 8))
//right constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .right, relatedBy: .equal, toItem: thumbnailImageView, attribute: .right, multiplier: 1, constant: 0))
//height constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 0, constant: 20))
//top constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .top, relatedBy: .equal, toItem: titleLabel, attribute: .bottom, multiplier: 1, constant: 4))
//left constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .left, relatedBy: .equal, toItem: userProfileImageView, attribute: .right, multiplier: 1, constant: 8))
//right constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .right, relatedBy: .equal, toItem: thumbnailImageView, attribute: .right, multiplier: 1, constant: 0))
//height constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 0, constant: 20))
thumbnailImageView.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension UIView {
func addConstraintsWithFormat(format: String, views: UIView...){
var viewsDictionary = [String: UIView]()
for (index, view) in views.enumerated(){
let key = "v\(index)"
view.translatesAutoresizingMaskIntoConstraints = false
viewsDictionary[key] = view
}
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: viewsDictionary))
}
}
In general to make swift classes available in objective-c.
Also helpful for me was another question/answer on stack.
But give a thought to fundamental changes:
it may be better, to create a new app in swift and connect to the old classes via the brindging header. The documentation is really helpful.
In future, it would be easier to add new elements in swift and use new functionallity.
It's simply not safe to do this from within viewDidLoad in a view controller, and you shouldn't even attempt it.
That's because it is possible for viewDidLoad to be executed multiple times.
If that happens, it's going to replace your window and rootViewController with new instances in the middle of your app's execution (looking to the user like the app has reset itself).
You need to initialize the window and root controller from the app delegate, there's no choice.
However, you can still write most of the code in Swift.
First, create a Swift extension on UIWindow that includes a class function which initialises and configures your window, then returns it. Make sure that extension is accessible by Objective-C by adding #objc to the declaration:
#objc extension UIWindow {
class func setRootHomeViewController() -> UIWindow {
let window = UIWindow(frame: UIScreen.main.bounds)
window.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
return window;
}
}
In your Objective-C app delegate, you then need to import your Swift header and call the new UIWindow class method that you've defined. Assign the returned window object to the app delegate's window property.
#import "YourProjectName-Swift.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
_window = [UIWindow setRootHomeViewController];
return YES;
}
#end
It's only one line of Objective-C code, but it's necessary as the app delegate is the only safe place to do this.

Shadow rate on UITableViewCell contenview increasing while scrolling

In my app, I'm using dynamic height cells using auto layout. So for creating cardview effect I've to use tableview willdisplaycell method. It only add shadow only once to cell. But I don't know why shadow increasing while scrolling.
Here's my code
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
//setup card view style on cell
if !cellArray.contains(indexPath.row) {
cell.contentView.backgroundColor = UIColor.clear
let whiteRoundedView : UIView = UIView(frame: CGRect(x: 5.0, y: 5.0, width: cell.contentView.frame.size.width-10, height: cell.contentView.frame.size.height-10))
whiteRoundedView.layer.backgroundColor = UIColor.white.cgColor
whiteRoundedView.layer.masksToBounds = false
whiteRoundedView.layer.cornerRadius = 5.0
whiteRoundedView.layer.shadowOffset = CGSize(width: -1, height: 1)
whiteRoundedView.layer.shadowOpacity = 0.5
cell.contentView.addSubview(whiteRoundedView)
cell.contentView.sendSubview(toBack: whiteRoundedView)
cellArray.add(indexPath.row)
}
}
this piece of line is the causing the issue.
cell.contentView.addSubview(whiteRoundedView)
whenever willDisplayCell gets called, you will be adding the view everytime. That is the reason shadow is getting increased while scrolling. The solution is,
1. check the cell content view if the view is already added or not. If not, then add the view. use view tag to do it.
2. otherwise, create a shadow view and initialize the specific things in the -(void)awakeFromNib, which will get called only once.
but personally, i prefer option 2, which will isolate your view render logic from view controller or cell.
add the below code to your custom cell class. In this case, i have given leading-trialing-top-bottom constraints as 15-15-15-15. If you wish you can set it to 0. but make sure that it should in sync with the background constraints.
override func awakeFromNib() {
super.awakeFromNib()
contentView.backgroundColor = UIColor.clear
let whiteRoundedView : UIView = UIView(frame: CGRect(x: 5.0, y: 5.0, width: contentView.frame.size.width-10, height: contentView.frame.size.height-10))
whiteRoundedView.layer.backgroundColor = UIColor.white.cgColor
whiteRoundedView.layer.masksToBounds = false
whiteRoundedView.layer.cornerRadius = 5.0
whiteRoundedView.layer.shadowOffset = CGSize(width: -1, height: 1)
whiteRoundedView.layer.shadowOpacity = 0.5
whiteRoundedView.tag = shadowTag
whiteRoundedView.translatesAutoresizingMaskIntoConstraints=false
contentView.addSubview(whiteRoundedView)
contentView.sendSubview(toBack: whiteRoundedView)
let leading = NSLayoutConstraint(item: whiteRoundedView,
attribute: .leading,
relatedBy: .equal,
toItem: contentView,
attribute: .leading,
multiplier: 1.0,
constant: 15.0)
let trailing = NSLayoutConstraint(item: whiteRoundedView,
attribute: .trailing,
relatedBy: .equal,
toItem: contentView,
attribute: .trailing,
multiplier: 1.0,
constant: -15.0)
let top = NSLayoutConstraint(item: whiteRoundedView,
attribute: .top,
relatedBy: .equal,
toItem: contentView,
attribute: .top,
multiplier: 1.0,
constant: 15.0)
let bottom = NSLayoutConstraint(item: whiteRoundedView,
attribute: .bottom,
relatedBy: .equal,
toItem: contentView,
attribute: .bottom,
multiplier: 1.0,
constant: -15.0)
contentView.addConstraint(leading)
contentView.addConstraint(trailing)
contentView.addConstraint(top)
contentView.addConstraint(bottom)
}
Ref screenshot :
You can add your code here
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: <idenitfier>, for: indexPath) as? JobListTableViewCell
if cell == nil {
//Initialization and setting of shadow
}
return cell
}
Hope this helps

Can't add constraints between UICollectionView cell and the cell subview

After I run my app, it crashes:
Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal.
My image is subview of the cell.
What am I doing wrong?
let image = UIImageView(frame: CGRect(x: 0, y: 0, width: 300, height: 50))
image.image = UIImage.init(named: "Bitmap")
cell.contentView.addSubview(image)
let bottomConstr = NSLayoutConstraint(item: image, attribute: .bottom, relatedBy: .equal, toItem: cell.contentView, attribute: .bottom, multiplier: 1, constant: 0)
//let leftConstr = NSLayoutConstraint(item: image, attribute: .leading, relatedBy: .equal, toItem: cell.contentView, attribute: .leading, multiplier: 1, constant: 0)
//let rightConstr = NSLayoutConstraint(item: image, attribute: .trailing, relatedBy: .equal, toItem: cell.contentView, attribute: .trailing, multiplier: 1, constant: 0)
let heightConstr = NSLayoutConstraint(item: image, attribute: .height, relatedBy: .equal, toItem: nil , attribute: .notAnAttribute, multiplier: 1, constant: 10)
image.addConstraint(bottomConstr)
//image.addConstraint(leftConstr)
//image.addConstraint(rightConstr)
image.addConstraint(heightConstr)
You need to add constraint on Superview. so, add it on cell contentView.
cell.contentView.addConstraint(bottomConstr)
cell.contentView.addConstraint(heightConstr)
Constraints weren't working well for me when zooming UICollectionView. Here's how I resized a label to always fill the cell.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mycell", for: indexPath as IndexPath) as! SliceCollectionViewCell
cell.label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
func collectionView(_ collectionView: UICollectionView,
willDisplay cell: UICollectionViewCell,
forItemAt indexPath: IndexPath) {
guard let cell = cell as? MyCollectionViewCell else {
print("ERROR: wrong cell type")
return
}
cell.label.frame = CGRect(x: 0, y: 0, width: cell.frame.width, height: cell.frame.height)
}

iOS + Swift 2: Dynamic height in UITableViewCell doesn't work with an empty view

This is my problem. I'm using a custom UITableViewCell as a Cell prototype with identifier "cellidentifier" into the UITableView. In this UITableViewCell I have added (in Interface Builder) an empty UIView into contentView's cell that I call "bubbleView", It has a connection #IBOutlet and I added constraint top = 0, bottom = 0, leading = 0 and trailing = 0.
In the controller (which inherit from UITableViewDataSource and UITableViewDelegate), into the viewDidLoad function I added this lines:
override func viewDidLoad() {
...
self.mytable.delegate = self
self.mytable.dataSource = self
self.mytable.estimatedRowHeight = 100.0
self.mytable.rowHeight = UITableViewAutomaticDimension;
...
}
Then, I implemented methods of UITableViewDelegate in this way:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cellidentifier") as! myCustomCell!
if (cell == nil) {
cell = myCustomCell(style:UITableViewCellStyle.Subtitle, reuseIdentifier:"cellidentifier")
}
let myNewView = UIView(frame: CGRectMake(0, 10, randomWidth, random Height))
cell.bubbleView.addSubview(myNewView)
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
With that code, I can add myNewView into the cell, but the cell not adjust to the real height according the myNewView height, for example if myNewView height is 134, my custom view cell always return 44 in height. I added the layoutIfNeeded property as some tutorials says but It doesn't work. Anyone have a solution of this?
Does your empty view have a height constraint? If you are just pinning the bubble view to the superview's edges, I don't think that is enough for Auto Layout to figure out how tall the cell should be.
Also, for your prototype cell, go to the Size inspector. How is your Table View Cell configured there? Having it configured as "default" vs Custom may or may not resolve the problem.
If you want the cell to truly autosize itself, you will definitely need to provide enough constraints so that a height can actually be calculated.
SOLUTION: this is a topic about constraints. If you notice in Interface Builder, you need to be very clear with constraints, so assign top, bottom, leading and trailing are ambiguos for empty view. Then, the solution is add constraints to myNewView according your needs (in my case on top, width and height) and set height constraint to view container (cell.bubbleView) in reference with myNewView:
//Create my view
let myNewView = UIView(frame: CGRectMake(0, 10, randomWidth, random Height))
myNewView.translatesAutoresizingMaskIntoConstraints = true
//Assign top constraint according with container (cell.bubbleView)
let pinTop = NSLayoutConstraint(item: myNewView, attribute: .Top, relatedBy: .Equal, toItem: cell.bubbleView, attribute: .Top, multiplier: 1.0, constant: 10)
cell.bubbleView.addConstraint(pinTop)
//set width constraint of myNewView
let pinWidth = NSLayoutConstraint(item: myNewView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: myNewView.frame.size.width)
cell.bubbleView.addConstraint(pinWidth)
//set height constraint of myNewView
let pinHeight = NSLayoutConstraint(item: myNewView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: myNewView.frame.size.height)
cell.bubbleView.addConstraint(pinHeight)
//set height constraint of container according the myNewView plus top and bottom space
let pinHeightView = NSLayoutConstraint(item: cell.bubbleView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: myNewView.frame.size.height+20)
cell.bubbleView.addConstraint(pinHeightView)
cell.bubbleView.addSubview(myNewView)
and finally don't forget configure UITableView to make height cell dynamically.
self.mytable.estimatedRowHeight = 100.0
self.mytable.rowHeight = UITableViewAutomaticDimension;
And it works perfectly

Resources