Collectionview cell height from label height swift - swift

I'm trying to create a collection view that can be resized automatically from label height. I have two different cell, one of them with photo another without photo and both in xib files.
I've tried different ways to make this height dynamic but no solution ((.
var CollectionViewCellNib = UINib(nibName: "CollectionViewCell", bundle: nil)
collectionView.registerNib(CollectionViewCellNib, forCellWithReuseIdentifier: "CollectionViewCell")
var CollectionViewCellWithPhotoNib = UINib(nibName: "CollectionViewCellWithPhoto", bundle: nil)
collectionView.registerNib(CollectionViewCellWithPhotoNib, forCellWithReuseIdentifier: "CollectionViewCell")
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let pikirler = self.pikirler[indexPath.row]
let targetWidth: CGFloat = (self.collectionView.bounds.width - 2 * kHorizontalInsets)
if indexPath.row == 2 {
var cell = self.offscreenCells[CollectionViewKeyWords.collectionViewOnlyTextCell] as? CollectionViewCell
if cell == nil {
cell = NSBundle.mainBundle().loadNibNamed("CollectionViewCell", owner: self, options: nil)[0] as? CollectionViewCell
self.offscreenCells[CollectionViewKeyWords.collectionViewOnlyTextCell] = cell
}
cell!.configCell("sometext", content: "sometext")
cell!.bounds = CGRectMake(0, 0, targetWidth, cell!.bounds.height)
cell!.contentView.bounds = cell!.bounds
cell!.setNeedsLayout()
cell!.layoutIfNeeded()
var size = cell!.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
size.width = targetWidth
return size
}else{
var cell = self.offscreenCells[CollectionViewKeyWords.collectioViewWithPhotoCell] as? CollectionViewCellWithPhoto
if cell == nil {
cell = NSBundle.mainBundle().loadNibNamed("CollectionViewCellWithPhoto", owner: self, options: nil)[0] as? CollectionViewCellWithPhoto
self.offscreenCells[CollectionViewKeyWords.collectioViewWithPhotoCell] = cell
}
cell!.configCell("Some text", content: "sometext")
cell!.bounds = CGRectMake(0, 0, targetWidth, cell!.bounds.height)
cell!.contentView.bounds = cell!.bounds
cell!.setNeedsLayout()
cell!.layoutIfNeeded()
var size = cell!.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
size.width = targetWidth
return size
}
}

Related

having issues with cached table viewcells

I have the following code
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "book", for: indexPath) as! BookTableViewCell
cell.cellIndex = indexPath
cell.dataSource = self
cell.delegate = self
cell.backgroundColor = UIColor.white
var books = [Book]();
let count = self.enterpriseBooks.count;
if count > 0 && indexPath.section < self.enterpriseBooks_2.count {
books = self.enterpriseBooks_2[indexPath.section]!;
}
if (indexPath.section == (count)) {
books = nytbooks;
} else if (indexPath.section == (count + 1)) {
books = trendingbooks;
} else if (indexPath.section == (count + 2)) {
books = newbooks
}
if (books.count > 0) {
if (cell.collectionView === nil) {
cell.addCollectionView();
cell.collectionView.tag = 124;
cell.collectionView.reloadData()
}
}
return cell
}
// BookTableViewCell
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath as IndexPath) as! BookCollectionViewCell
self.dataSource?.getData(cell: self)
let books = self.books
let book = books?[indexPath.row]
if book != nil {
cell.label.text = book?.title
cell.imageView.sd_setImage(with: URL(string: book?.image as! String), placeholderImage: nil)
}
return cell
}
func addCollectionView () {
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
flowLayout.itemSize = CGSize(width: 100, height: self.frame.height)
//You can also provide estimated Height and Width
flowLayout.estimatedItemSize = CGSize(width: 100, height: self.frame.height)
//For Setting the Spacing between cells
flowLayout.minimumInteritemSpacing = 25
flowLayout.minimumLineSpacing = 20
let cellReuseIdentifier = "collectionCell"
self.collectionView = UICollectionView(frame: CGRect(x: 10,
y: 0,
width: self.frame.width,
height: self.frame.height),
collectionViewLayout: flowLayout)
self.collectionView.showsHorizontalScrollIndicator = false
self.collectionView.translatesAutoresizingMaskIntoConstraints = false
self.collectionView.backgroundColor = .clear
self.collectionView.delegate = self
self.collectionView.dataSource = self
self.collectionView.register(BookCollectionViewCell.self, forCellWithReuseIdentifier: cellReuseIdentifier)
self.backgroundColor = UIColor.white
self.addSubview(collectionView)
}
The issue is I'm running into caching issues where content in a table view cell or collection view cell are overlapping with each other. Can anyone please help?
The above content shows images horizontally aligned into three rows using collection views for each.

My UICollectionView does not scroll smoothly using Swift

I have a CollectionView which dequeues a cell depending on the message type (eg; text, image).
The problem I am having is that when I scroll up/down the scroll is really choppy and thus not a very good user experience. This only happens the first time the cells are loaded, after that the scrolling is smooth.
Any ideas how I can fix this?, could this be an issue with the time its taking to fetch data before the cell is displayed?
I am not too familiar with running tasks on background threads etc. and not sure what changes I can make to prefect the data pre/fetching etc.. please help!
The Gif shows scroll up when the view loads, it shows the cells/view being choppy as I attempt to scroll up.
This is my func loadConversation() which loads the messages array
func loadConversation(){
DataService.run.observeUsersMessagesFor(forUserId: chatPartnerId!) { (chatLog) in
self.messages = chatLog
DispatchQueue.main.async {
self.collectionView.reloadData()
if self.messages.count > 0 {
let indexPath = IndexPath(item: self.messages.count - 1, section: 0)
self.collectionView.scrollToItem(at: indexPath, at: .bottom , animated: false)
}
}
}//observeUsersMessagesFor
}//end func
This is my cellForItemAt which dequeues cells
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let message = messages[indexPath.item]
let uid = Auth.auth().currentUser?.uid
if message.fromId == uid {
if message.imageUrl != nil {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ConversationCellImage", for: indexPath) as! ConversationCellImage
cell.configureCell(message: message)
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ConversationCellSender", for: indexPath) as! ConversationCellSender
cell.configureCell(message: message)
return cell
}//end if message.imageUrl != nil
} else {
if message.imageUrl != nil {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ConversationCellImageSender", for: indexPath) as! ConversationCellImageSender
cell.configureCell(message: message)
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ConversationCell", for: indexPath) as! ConversationCell
cell.configureCell(message: message)
return cell
}
}//end if uid
}//end func
This is my ConversationCell class which configures a custom cell for dequeueing by cellForItemAt (note: in addition there another ConversationCellImage custom cell class which configures an image message):
class ConversationCell: UICollectionViewCell {
#IBOutlet weak var chatPartnerProfileImg: CircleImage!
#IBOutlet weak var messageLbl: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
chatPartnerProfileImg.isHidden = false
}//end func
func configureCell(message: Message){
messageLbl.text = message.message
let partnerId = message.chatPartnerId()
DataService.run.getUserInfo(forUserId: partnerId!) { (user) in
let url = URL(string: user.profilePictureURL)
self.chatPartnerProfileImg.sd_setImage(with: url, placeholderImage: #imageLiteral(resourceName: "placeholder"), options: [.continueInBackground, .progressiveDownload], completed: nil)
}//end getUserInfo
}//end func
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = 10.0
self.layer.shadowRadius = 5.0
self.layer.shadowOpacity = 0.3
self.layer.shadowOffset = CGSize(width: 5.0, height: 10.0)
self.clipsToBounds = false
}//end func
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
//toggles auto-layout
setNeedsLayout()
layoutIfNeeded()
//Tries to fit contentView to the target size in layoutAttributes
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
//Update layoutAttributes with height that was just calculated
var frame = layoutAttributes.frame
frame.size.height = ceil(size.height) + 18
layoutAttributes.frame = frame
return layoutAttributes
}
}//end class
Time Profile results:
Edit: Flowlayout code
if let flowLayout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout,
let collectionView = collectionView {
let w = collectionView.frame.width - 40
flowLayout.estimatedItemSize = CGSize(width: w, height: 200)
}// end if-let
Edit: preferredLayoutAttributesFitting function in my custom cell class
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
//toggles auto-layout
setNeedsLayout()
layoutIfNeeded()
//Tries to fit contentView to the target size in layoutAttributes
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
//Update layoutAttributes with height that was just calculated
var frame = layoutAttributes.frame
frame.size.height = ceil(size.height) + 18
layoutAttributes.frame = frame
return layoutAttributes
}
SOLUTION:
extension ConversationVC: UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var height: CGFloat = 80
let message = messages[indexPath.item]
if let text = message.message {
height = estimateFrameForText(text).height + 20
} else if let imageWidth = message.imageWidth?.floatValue, let imageHeight = message.imageHeight?.floatValue{
height = CGFloat(imageHeight / imageWidth * 200)
}
let width = collectionView.frame.width - 40
return CGSize(width: width, height: height)
}
fileprivate func estimateFrameForText(_ text: String) -> CGRect {
let size = CGSize(width: 200, height: 1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
return NSString(string: text).boundingRect(with: size, options: options, attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 16)], context: nil)
}
}//end extension
First thing first, let's try finding the exact location where this problem is arising.
Try 1:
comment this line
//self.chatPartnerProfileImg.sd_setImage(with: url, placeholderImage: #imageLiteral(resourceName: "placeholder"), options: [.continueInBackground, .progressiveDownload], completed: nil)
And run your app to see the results.
Try 2:
Put that line in async block to see the results.
DispatchQueue.main.async {
self.chatPartnerProfileImg.sd_setImage(with: url, placeholderImage: #imageLiteral(resourceName: "placeholder"), options: [.continueInBackground, .progressiveDownload], completed: nil)
}
Try 3: Comment the code for setting corner radius
/*self.layer.cornerRadius = 10.0
self.layer.shadowRadius = 5.0
self.layer.shadowOpacity = 0.3
self.layer.shadowOffset = CGSize(width: 5.0, height: 10.0)
self.clipsToBounds = false*/
Share your results for Try 1, 2 and 3 and then we can get the better idea about where the problem lies.
Hope this way we can get the reason behind flickering.
Always make sure that the data like image or GIF shouldn't download on the main thread.
This is the reason why your scrolling is not smooth. Download the data in separate thread in background use either GCD or NSOperation queue. Then show the downloaded image always on main thread.
use AlamofireImage pods, it will automatically handle the downloaded task in background.
import AlamofireImage
extension UIImageView {
func downloadImage(imageURL: String?, placeholderImage: UIImage? = nil) {
if let imageurl = imageURL {
self.af_setImage(withURL: NSURL(string: imageurl)! as URL, placeholderImage: placeholderImage) { (imageResult) in
if let img = imageResult.result.value {
self.image = img.resizeImageWith(newSize: self.frame.size)
self.contentMode = .scaleAspectFill
}
}
} else {
self.image = placeholderImage
}
}
}
I think the choppiness you are seeing is because the cells are given a size and then override the size they were given which causes the layout to shift around. What you need to do is do the calculation during the creation of the layout first time through.
I have a function that I have used like this...
func height(forWidth width: CGFloat) -> CGFloat {
// do the height calculation here
}
This is then used by the layout to determine the correct size first time without having to change it.
You could have this as a static method on the cell or on the data... or something.
What it needs to do is create a cell (not dequeue, just create a single cell) then populate the data in it. Then do the resizing stuff. Then use that height in the layout when doing the first layout pass.
Yours is choppy because the collection lays out the cells with a height of 20 (for example) and then calculates where everything needs to be based on that... then you go... "actually, this should be 38" and the collection has to move everything around now that you've given it a different height. This then happens for every cell and so causes the choppiness.
I might be able to help a bit more if I could see your layout code.
EDIT
Instead of using that preferredAttributes method you should implement the delegate method func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize.
Do something like this...
This method goes into the view controller.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let message = messages[indexPath.item]
let height: CGFloat
if let url = message.imageURL {
height = // whatever height you want for the images
} else {
height = // whatever height you want for the text
}
return CGSize(width: collectionView.frame.width - 40, height: height)
}
You may have to add to this but it will give you an idea.
Once you've done this... remove all your code from the cell to do with changing the frames and attributes etc.
Also... put your shadow code into the awakeFromNib method.

Swift 3 - CollectionView data source did not return a valid cell

I am using this code: https://www.youtube.com/watch?v=bNtsekO51iQ , but when I implement my data and use collectionView.reloadData() it crashes with error code *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the collection view's data source did not return a valid cell from -collectionView:cellForItemAtIndexPath: for index path <NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}'
class ChatLogController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var userId:Int?
var position:Int = 0
var otherAvatar:UIImage = UIImage(named: "defaultAvatar")!
var otherName:String = ""
var otherSex:String = ""
var otherBanned:Int = 0
var otherBlocked:Int = 0
var messagesDates:[String] = []
var messagesText:[String] = []
var messagesIds:[String] = []
var messagesPics:[UIImage?] = []
var messagesSeen:[Int] = []
var messagesWhoSendIt:[Int] = []
private let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.register(ChatLogMessageCell.self, forCellWithReuseIdentifier: cellId)
collectionView!.isPrefetchingEnabled = false
loadChatsFor(position: position)
} override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return messagesIds.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath as IndexPath) as! ChatLogMessageCell
cell.messageTextView.text = messagesText[indexPath.row]
cell.profileImageView.image = UIImage(named: "defaultAvatar")!
let size = CGSize(width:250,height:1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
let estimatedFrame = NSString(string: messagesText[indexPath.row]).boundingRect(with: size, options: options, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 18)], context: nil)
cell.messageTextView.frame = CGRect(x:48 + 8, y:0, width:estimatedFrame.width + 16, height:estimatedFrame.height + 20)
cell.textBubbleView.frame = CGRect(x:48, y:0, width:estimatedFrame.width + 16 + 8, height:estimatedFrame.height + 20)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let size = CGSize(width:250,height:1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
let estimatedFrame = NSString(string: messagesText[indexPath.row]).boundingRect(with: size, options: options, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 18)], context: nil)
return CGSize(width:view.frame.width, height:estimatedFrame.height + 20)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(8, 0, 0, 0)
}
}
class ChatLogMessageCell: BaseCell {
let messageTextView: UITextView = {
let textView = UITextView()
textView.font = UIFont.systemFont(ofSize: 18)
textView.text = "Sample message"
textView.backgroundColor = UIColor.clear
return textView
}()
let textBubbleView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 0.95, alpha: 1)
view.layer.cornerRadius = 15
view.layer.masksToBounds = true
return view
}()
let profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.layer.cornerRadius = 15
imageView.layer.masksToBounds = true
return imageView
}()
override func setupViews() {
super.setupViews()
addSubview(textBubbleView)
addSubview(messageTextView)
addSubview(profileImageView)
addConstraintsWithFormat(format:"H:|-8-[v0(30)]", views: profileImageView)
addConstraintsWithFormat(format:"V:[v0(30)]|", views: profileImageView)
profileImageView.backgroundColor = UIColor.red
}
}
extension UIView {
func addConstraintsWithFormat(format: String, views: UIView...) {
var viewsDictionary = [String: UIView]()
for (index, view) in views.enumerated() {
let key = "v\(index)"
viewsDictionary[key] = view
view.translatesAutoresizingMaskIntoConstraints = false
}
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(), metrics: nil, views: viewsDictionary))
}
}
class BaseCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
}
}
In loadChatsFor I get the array data from web and I use collectionView.reloadData(), but when this function is performed it crashes my app. I've searched for answer, but unsuccessfully. I've added IOS 10 function collectionView!.isPrefetchingEnabled = false in view did load from this answer UICollectionView exception in UICollectionViewLayoutAttributes from iOS7, but also not working. Even the method collectionViewLayout invalidateLayout before reloadData and after reloadData doesn't stop the crash. So what else I can do to make it work ?
I am coming in this CollectionViewController from UITableViewCell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let layout = UICollectionViewFlowLayout()
let controller = ChatLogController(collectionViewLayout: layout)
controller.userId = chatUserIds[indexPath.row]
navigationController?.pushViewController(controller, animated: true)
}
I've added UICollectionViewDelegateFlowLayout in the class of the tableview
You are not implementing correct cellForItemAt method of UICollectionViewDataSource. Signature of this method is changed in Swift 3 like this.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath as IndexPath) as! ChatLogMessageCell
cell.messageTextView.text = messagesText[indexPath.row]
cell.profileImageView.image = UIImage(named: "defaultAvatar")!
let size = CGSize(width:250,height:1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
let estimatedFrame = NSString(string: messagesText[indexPath.row]).boundingRect(with: size, options: options, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 18)], context: nil)
cell.messageTextView.frame = CGRect(x:48 + 8, y:0, width:estimatedFrame.width + 16, height:estimatedFrame.height + 20)
cell.textBubbleView.frame = CGRect(x:48, y:0, width:estimatedFrame.width + 16 + 8, height:estimatedFrame.height + 20)
return cell
}

TableView Reload data is not calling cellForRowAtIndexPath

I am Using UITableView For Display some data. But I have Seperated the Datasource and Delegate Methods to another class. So my TableViewController is not having Any delegate Methods. They are in Seperate Class.
So when the tableview loads for the First Time, It loads the values. but when i use tableView.reloadData on a button click of a cell , It does not calls the cellForRawAtIndexPath Method. But it calls numberOfRawsInSection and other methods.
Here is my Controller Class
class AdvancedSearch: UITableViewController , PopOverViewDelegate{
#IBOutlet var model: AdvancedSearchDataModel!
let dataModel = AdvancedSearchDataModel()
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerNib(UINib(nibName: "AgeCell", bundle: nil), forCellReuseIdentifier: "AgeCell")
tableView.registerNib(UINib(nibName: "ExperienceCell", bundle: nil), forCellReuseIdentifier: "ExperienceCell")
tableView.registerNib(UINib(nibName: "CityCell", bundle: nil), forCellReuseIdentifier: "CityCell")
tableView.registerNib(UINib(nibName: "StateCell", bundle: nil), forCellReuseIdentifier: "StateCell")
tableView.registerNib(UINib(nibName: "DateTimeCell", bundle: nil), forCellReuseIdentifier: "DateTimeCell")
tableView.registerNib(UINib(nibName: "GenderCell", bundle: nil), forCellReuseIdentifier: "GenderCell")
tableView.registerNib(UINib(nibName: "ResultButtonCell", bundle: nil), forCellReuseIdentifier: "ResultButtonCell")
//tableView.dataSource = model
//tableView.delegate = model
tableView.separatorColor = UIColor.grayColor()
tableView.allowsSelection = false
tableView.separatorStyle = UITableViewCellSeparatorStyle.None
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
tableView.reloadData()
}
// MARK: - DropDown PopOver Delegates
func valueOfTheFieldWhenSelect(tableViewCell: UITableViewCell, value: String, indexPath: NSIndexPath) {
let data = AdvancedSearchDataModel()
data.buttonTitle = value
self.tableView.delegate = data
self.tableView.dataSource = data
self.tableView.reloadData()
}
Here is my Datasource and Delegates in Seperate Class
class AdvancedSearchDataModel: NSObject , UITableViewDataSource , UITableViewDelegate , AdvanceSearchDropDownButtonDelegate , UIPopoverPresentationControllerDelegate {
let data = ["Age","Experience","City" , "State" , "Gender" , "Date and Time"]
// set this proprty in PopOverViewDelegate method
var buttonTitle : String?
// MARK: - TableView Datasource
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("Count : \(data.count)")
return data.count + 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier("AgeCell", forIndexPath: indexPath) as! AgeCell
applyStyleForButton(cell.selectAge)
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
if buttonTitle != nil {
cell.selectAge.setTitle(buttonTitle, forState: .Normal)
}
cell.indexPath = indexPath
cell.dropDownDelegate = self
return cell
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("ExperienceCell", forIndexPath: indexPath) as! ExperienceCell
applyStyleForButton(cell.selectExperinceBtn)
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
return cell
case 2:
let cell = tableView.dequeueReusableCellWithIdentifier("CityCell", forIndexPath: indexPath) as! CityCell
applyStyleForButton(cell.cityButton)
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
return cell
case 3:
let cell = tableView.dequeueReusableCellWithIdentifier("StateCell", forIndexPath: indexPath) as! StateCell
applyStyleForButton(cell.stateButton)
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
return cell
case 4:
let cell = tableView.dequeueReusableCellWithIdentifier("GenderCell", forIndexPath: indexPath) as! GenderCell
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
return cell
case 5:
let cell = tableView.dequeueReusableCellWithIdentifier("DateTimeCell", forIndexPath: indexPath) as! DateTimeCell
applyStyleForButton(cell.datebutton)
applyStyleForButton(cell.timeButton)
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
return cell
case 6:
let cell = tableView.dequeueReusableCellWithIdentifier("ResultButtonCell", forIndexPath: indexPath) as! ResultButtonCell
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
return cell
default:
return UITableViewCell()
}
}
// MARK: - TableView Delegates
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 5 {
return 150
}else{
return 94
}
}
// MARK: - Styling
func applyStyleForButton(button : UIButton){
button.layer.borderColor = UIColor.grayColor().CGColor
button.layer.borderWidth = 1
button.layer.cornerRadius = 5
button.backgroundColor = UIColor.clearColor()
}
// MARK: - DropDown Delegates
func openAgeDropDown(by button: UIButton, and cell: AgeCell,indexPath : NSIndexPath)
{
print("Age opened")
let tableViewController = DropDownController(style: .Plain, menuItems: ["10","20","30"],cell: cell , index: indexPath)
tableViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
tableViewController.preferredContentSize = CGSizeMake(button.frame.width, button.frame.width)
// assigning the delegate in tableView to fill the textfield
tableViewController.delegate = AdvancedSearch()
let popoverPresentationController = tableViewController.popoverPresentationController
popoverPresentationController?.permittedArrowDirections = .Any
popoverPresentationController?.delegate = self
popoverPresentationController?.sourceView = button
popoverPresentationController?.sourceRect = button.bounds
UIApplication.sharedApplication().keyWindow?.rootViewController!.presentViewController(tableViewController, animated: true, completion: nil)
}
// MARK: - PopOver Delegates
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}}
Please Guide me
The methods is not calling because everytime you are creating a new object of AdvancedSearchDataModel. instead this assign delegate in viewDidLoad. don't need to create new object of AdvancedSearchDataModel
in viewDidLoad
...
tableView.separatorColor = UIColor.grayColor()
tableView.allowsSelection = false
tableView.separatorStyle = UITableViewCellSeparatorStyle.None
tableView.delegate = self.model
tableView.dataSource = self.model
and in valueOfTheFieldWhenSelect
func valueOfTheFieldWhenSelect(tableViewCell: UITableViewCell, value: String, indexPath: NSIndexPath) {
self.model.buttonTitle = value
self.tableView.reloadData()
}

Preserve Image Aspect Ratio in UICollectionViewCell

Problem: Reloaded cached UIImageView in a UICollectionViewCell (during scrolling or switching between UICollectionViewController) are not preserving the correct contentMode.
I tried using .sizeToFit() on the UIImageView and resetting .contentMode = UIViewContentMode.ScaleAspectFit on every load, but that wasn't helping.
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> MyCollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("myCell", forIndexPath: indexPath) as! MyCollectionViewCell
if ( indexPath.item < self.the_array?.count ){
if ( images_cache[self.the_array![indexPath.item].src!] != nil ){
// calling this here doesn't work
cell.myImage.contentMode = UIViewContentMode.ScaleAspectFit
// calling this here doesn't work either
cell.myImage.sizeToFit()
cell.myImage.image = images_cache[self.the_array![indexPath.item].src!]! as UIImage
}
else{
if let url = NSURL(string: "https:" + (self.the_array![indexPath.item].src)!), data = NSData(contentsOfURL: url) {
let the_image = UIImage( data: data )
cell.myImage.image = the_image
images_cache[self.the_array![indexPath.item].src!] = the_image!
}
}
}
return cell
}
Solution: Set the .frame of the UIImage based on the size of the cell!
cell.myImage.frame = CGRect(x: 0, y: 0, width: cell.frame.width, height: cell.frame.height)
I put that line where I had .sizeToFit() and / or .contentMode and now it preserves the images correctly.