How to achieve self sizing collectionViewCells using RxDataSource?
I've tried setting
flowLayout.estimatedItemSize = CGSize(width: 187, height: 102)
But then app crashes when dataSourceObservable changes.
I've tried setting cell size inside
dataSource.configureCell = { [weak self] (dataSource, collectionView, indexPath, _) in
Which is not a good idea, because cells overlap, and it is because I am not using
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
Now, is possible to layout cell sizes properly using only observables? That is not to call something like
dataSourceVar.value[indexPath].cellSize
Inside collectionView sizeForItemAt?
Faced a similar problem, solved in this way
// swiftlint:disable line_length type_name
final class RxCollectionViewSectionedReloadDataSourceAndDelegate<Section: SectionModelType>: RxCollectionViewSectionedReloadDataSource<Section>, UICollectionViewDelegateFlowLayout {
typealias CellSize = (CollectionViewSectionedDataSource<Section>, UICollectionView, UICollectionViewLayout, IndexPath, Item) -> CGSize
typealias SizeViewInSection = (CollectionViewSectionedDataSource<Section>, UICollectionView, UICollectionViewLayout, Int, Section) -> CGSize
private var cellSize: CellSize
private var headerSectionViewSize: SizeViewInSection?
private var footerSectionViewSize: SizeViewInSection?
init(
configureCell: #escaping ConfigureCell,
configureSupplementaryView: ConfigureSupplementaryView? = nil,
moveItem: #escaping MoveItem = { _, _, _ in () },
canMoveItemAtIndexPath: #escaping CanMoveItemAtIndexPath = { _, _ in false },
cellSize: #escaping CellSize,
headerSectionViewSize: SizeViewInSection? = nil,
footerSectionViewSize: SizeViewInSection? = nil
) {
self.cellSize = cellSize
self.headerSectionViewSize = headerSectionViewSize
self.footerSectionViewSize = footerSectionViewSize
super.init(
configureCell: configureCell,
configureSupplementaryView: configureSupplementaryView,
moveItem: moveItem,
canMoveItemAtIndexPath: canMoveItemAtIndexPath
)
}
override func collectionView(
_ collectionView: UICollectionView,
observedEvent: Event<RxCollectionViewSectionedReloadDataSource<Section>.Element>
) {
collectionView.delegate = self
super.collectionView(collectionView, observedEvent: observedEvent)
}
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath
) -> CGSize {
cellSize(self, collectionView, collectionViewLayout, indexPath, self[indexPath])
}
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
referenceSizeForHeaderInSection section: Int
) -> CGSize {
headerSectionViewSize?(self, collectionView, collectionViewLayout, section, sectionModels[section]) ?? .zero
}
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
referenceSizeForFooterInSection section: Int
) -> CGSize {
footerSectionViewSize?(self, collectionView, collectionViewLayout, section, sectionModels[section]) ?? .zero
}
}
// swiftlint:enable line_length type_name
Add collection view to Storyboard. Import RxDataSources as a dependency.
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
class ViewController: UIViewController {
private let disposeBag = DisposeBag()
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var collectionLayout: UICollectionViewFlowLayout! {
didSet {
collectionLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
}
}
private let section = BehaviorRelay(
value: Section(items: [
Item(title: "Lorem ipsum dolor sit amet, consectetur"),
Item(title: "adipiscing elit, sed do eiusmod tempor"),
Item(title: "incididunt ut labore et dolore magna aliqua"),
Item(title: "Ut enim ad minim veniam"),
Item(title: "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."),
Item(title: "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
]
)
)
private lazy var collectionDatasource = {
return RxCollectionViewSectionedReloadDataSource<Section>(
configureCell: { (dataSource, collectionView, indexPath, item) -> UICollectionViewCell in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionCell
cell.titleLabel.text = item.title
cell.layer.borderWidth = 0.5
cell.layer.borderColor = UIColor.lightGray.cgColor
cell.maxWidth = collectionView.bounds.width - 16
return cell
})
}()
override func viewDidLoad() {
super.viewDidLoad()
initCollection()
}
private func initCollection() {
section
.asObservable()
.map({ return [$0] })
.bind(to: collectionView.rx.items(dataSource: collectionDatasource))
.disposed(by: disposeBag)
}
}
Data Model
import Foundation
struct Item {
let title: String
}
Create Section class subclassing SectionModelType
import RxDataSources
struct Section {
var items: [Item]
}
extension Section: SectionModelType {
init(
original: Section,
items: [Item]) {
self = original
self.items = items
}
}
Collection View Cell class
import UIKit
class CollectionCell: UICollectionViewCell {
#IBOutlet weak var titleLabel: UILabel!
// Note: must be strong
#IBOutlet private var maxWidthConstraint: NSLayoutConstraint! {
didSet {
maxWidthConstraint.isActive = false
}
}
var maxWidth: CGFloat? = nil {
didSet {
guard let maxWidth = maxWidth else {
return
}
maxWidthConstraint.isActive = true
maxWidthConstraint.constant = maxWidth
}
}
override func awakeFromNib() {
super.awakeFromNib()
contentView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
contentView.leftAnchor.constraint(equalTo: leftAnchor),
contentView.rightAnchor.constraint(equalTo: rightAnchor),
contentView.topAnchor.constraint(equalTo: topAnchor),
contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
])
}
}
Related
So I have an issue I've been battling with for days now. I have a collectionView which is designed to have large cells (width-wise) which go off screen. The height is fixed. The idea is to basically scroll to the end (see below):
To achieve being able to scroll left and right, I've had to override the width inside collectionViewContentSize in my flowLayout. Like below.
override var collectionViewContentSize: CGSize {
var size = super.collectionViewContentSize
size.width = largeWidth
return size
}
This achieves increasing the horizontal scroll area (which is what I want) but the cells start to disappear once I reach a certain point. It's almost as if the cells are being dequeued when they shouldn't be. Any ideas on this. This is the final straw for my project but I'm out of ideas.
Many thanks
Code snippet can be found below. You should be able to just copy and paste this into any project:
class HomeViewController: UIViewController {
let collectionView: UICollectionView
let collectionViewLayout = CustomCollectionViewFlowLayout()
init() {
collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
super.init(nibName: nil, bundle: nil)
collectionView.backgroundColor = UIColor.red.withAlphaComponent(0.4)
collectionView.register(SomeCell.self, forCellWithReuseIdentifier: "SomeCell")
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
collectionView.delegate = self
collectionView.dataSource = self
}
override func viewDidLoad() {
super.viewDidLoad()
collectionView.frame = view.bounds
view.addSubview(collectionView)
}
}
class SomeCell: UICollectionViewCell {
}
extension HomeViewController: UICollectionViewDataSource,
UICollectionViewDelegate,
UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 150
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SomeCell", for: indexPath) as! SomeCell
cell.backgroundColor = .blue
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 10000, height: 70)
}
}
class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {
override var collectionViewContentSize: CGSize {
var size = super.collectionViewContentSize
size.width = 10000
return size
}
}
In my iOS app I have a textfield with a picker view assigned to it's inputView. On iOS devices the picker view pops up whenever the user taps the textfield. The same code does not do that, however, when I run it as a Mac/Catalyst app. My debug effort so far shows that the picker view methods are not called at all, so if the Mac requires additional textfield delegate methods to take focus away from the Mac's keyboard? Any idea how to make this work on a Mac? A barebones example code is below.
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
#IBOutlet weak var myTextField: UITextField!
var myPickerView : UIPickerView!
var pickerData = ["Alpha" , "Bravo" , "Charlie" , "Delta"]
override func viewDidLoad() {
super.viewDidLoad()
self.myPickerView = UIPickerView(frame:CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 300))
self.myPickerView.delegate = self
self.myPickerView.dataSource = self
self.myTextField.delegate = self
self.myTextField.inputView = self.myPickerView
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return pickerData.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return pickerData[row]
}
}
It looks like a bug in Mac Catalyst. Try using the UIPicker embedded in an UIActionSheet. ActionSheetPicker-3.0 is a ready-made solution. Show the ActionSheetPicker in textFieldDidBeginEditing of your UITextField.
ViewController
class ViewController : UIViewController {
// MARK: - Properties -
var tableView : UITableView?
var currentTextfield : UITextField?
var gendersArray : Array<String> = ["Male", "Female"]
var pickerView : UIPickerView?
// MARK: - Lifecycle -
override func viewDidLoad() {
super.viewDidLoad()
// get the size of the iOS device
let screenRect : CGRect = UIScreen.main.bounds
let screenWidth : CGFloat = screenRect.size.width
let screenHeight : CGFloat = screenRect.size.height
// add the picker view
var pickerViewFrame = CGRect(x: 0.0,
y: screenHeight - 162.0,
width: screenWidth,
height: 162.0)
// set pickerview frame for macOS Catalyst
#if targetEnvironment(macCatalyst)
pickerViewFrame = CGRect(x: 0, y: 0, width: 269, height: 240)
#endif
pickerView = UIPickerView.init(frame: pickerViewFrame)
pickerView?.delegate = self
pickerView?.dataSource = self
// ... set tableview
}
}
UIAlertController Function
// MARK: - UIAlertController -
#objc func textfieldInputAction(pickerView: UIPickerView, textfield: UITextField?) {
print("textfieldInputAction")
// alertController
let alertController = UIAlertController(title: "Title of Action Sheet", message: "", preferredStyle: UIAlertController.Style.actionSheet)
// reload components
pickerView.reloadAllComponents()
// add the picker to the alert controller
alertController.view.addSubview(pickerView)
// set height of Action sheet
let height : NSLayoutConstraint = NSLayoutConstraint(item: alertController.view!, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 350)
alertController.view.addConstraint(height)
// okAction
let okAction = UIAlertAction(title: "Done", style: .default, handler: {
(alert: UIAlertAction!) -> Void in
// end editing
DispatchQueue.main.async {
textfield?.resignFirstResponder()
DispatchQueue.main.async {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
})
alertController.addAction(okAction)
// popoverController
if let popoverController = alertController.popoverPresentationController {
popoverController.sourceView = textfield //to set the source of your alert
popoverController.sourceRect = textfield?.bounds ?? CGRect(x: 0, y: 0, width: 0, height: 0 )
popoverController.permittedArrowDirections = [.down, .up]
}
// present alertController
self.present(alertController, animated: true, completion: nil)
}
TableView
// MARK: - Tableview -
extension ViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : TextFieldCell = tableView.dequeueReusableCell(withIdentifier: "TextFieldCell", for: indexPath) as! TextFieldCell
// textfield
cell.textField?.delegate = self
cell.textField?.inputView = pickerView
return cell
}
}
UITextField Delegate
// MARK: - UITextField -
extension ViewController : UITextFieldDelegate {
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
print("textFieldShouldBeginEditing")
#if targetEnvironment(macCatalyst)
if textField.inputView == self.pickerView {
self.currentTextfield = textField
self.textfieldInputAction(pickerView: self.pickerView!, textfield: self.currentTextfield!)
return false
}
#endif
return true
}
}
UIPickerView Delegate
// MARK: - PickerView Delegates -
extension ViewController : UIPickerViewDelegate, UIPickerViewDataSource {
// components
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
// rows
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
print("numberOfRowsInComponent")
return gendersArray.count
}
// title
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return gendersArray[row]
}
// select row
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
print("pickerView: didSelectRow: \(row)")
currentTextfield?.text = gendersArray[row]
self.tableView?.reloadData()
}
}
This is a bit of a hack, but let me share anyway. If you listen for the NSNotification UIKeyboardWillChangeFrameNotification
this will fire before -(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
so you can set a BOOL to see if this method fires. If it doesn't, you can tell that you don't have a software keyboard, and then can show an alert controller or context menu, or however you want to handle it differently.
On UIPickerViewMioPicker.swift
class UIPickerViewMio : NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
private var uiTextField : UITextField?
private var oggetto = ["Uno", "Due", "Tre", "Quattro", "Cinque"]
required init(uiTextField : UITextField?) {
self.uiTextField = uiTextField
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return 5
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
if let textField = self.uiTextField {
textField.text = self.oggetto[row]
textField.tag = row
}
}
... omissis ...}
On UIViewController
#IBOutlet var textMioText : UITextField?
var uiPickerViewMioPicker : UIPickerViewMioPicker?
override func viewDidLoad() {
... omissis ...
self.uiPickerViewMio = UIPickerViewMioPicker(uiTextField: self.textMioText)
let pickerM = UIPickerView()
pickerM.delegate = self.uiPickerViewMioPicker
pickerM.dataSource = self.uiPickerViewMioPicker
self.textMioText?.inputView = pickerM
... omissis ...
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if textField == self.textMio {
let picker = textField.inputView as! UIPickerView
picker.isHidden = false
if UIDevice.current.systemName == "Mac OS X" {
let alertPicker = UIAlertController(title: "", message: "", preferredStyle: UIAlertController.Style.actionSheet)
alertPicker.view.addSubview(picker)
alertPicker.view.addConstraint(NSLayoutConstraint(item: alertPicker.view!, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: picker.bounds.height * 1.1))
alertPicker.view.addConstraint(NSLayoutConstraint(item: alertPicker.view!, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: picker.bounds.width * 1.1))
if let popoverController = alertPicker.popoverPresentationController {
popoverController.sourceView = textField
popoverController.sourceRect = textField.bounds
popoverController.permittedArrowDirections = [.down, .up]
}
self.present(alertPicker, animated: true, completion: nil)
return false
}
}
return true}
I have a UITableView whose each row must take me to a detail page containing UIWebView .At each item (row) of Tableview there is a local HTML file.
With this code, I support the same HTML file:
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
let localfilePath = NSBundle.mainBundle().URLForResource("yyy", withExtension: "html")
let myRequest = NSURLRequest(URL: localfilePath!)
webView.loadRequest(myRequest)
}
How to assign to each row the HTML file that matches it?
In my TableViewController :
class IntroTableViewController: UITableViewController {
var labelintro = [String]()
var webAddresses = [String]()
override func viewDidLoad() {
super.viewDidLoad()
labelintro = ["Avant-propos", "Zone Sakalava", "Pronontiation", "Conjugaison", "Verbes indispensables","Grammaire & synthaxe","Mots indispensables","Les comptes","Le temps", "Termes de politesse", "La famille", "Se déplacer", "Le commerces", "Les vêtements", "Se loger", "Nourritures, épices & condiments", "Nature & paysages", "Ville, village", "L'école", "La flore", "La faune", "Santé & corps", "Artisanat, tradition & sacré", "Expressions courantes"]
webAddresses = ["xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html"]
}
override func prepareForSegue(segue: UIStoryboardSegue,
sender: AnyObject?) {
if segue.identifier == "gotodetail" {
_ = segue.destinationViewController
as! DetailIntroViewController
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return labelintro.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("texteintrocell", forIndexPath: indexPath) as! IntroTableViewCell
let row = indexPath.row
cell.labelIntro.text = labelintro[row]
return cell
}
}
And in my DetailViewController :
class DetailIntroViewController: UIViewController {
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
let localfilePath = NSBundle.mainBundle().URLForResource(self.selectedHTMLFileName, withExtension: "html")
}
}
Make a property selectedHTMLFileName at this viewcontroller where you loading webview. From previous controller having tableview, handle didSelectRowAtIndexPath and set this property to your filename.
let localfilePath = NSBundle.mainBundle().URLForResource(self.selectedHTMLFileName, withExtension: "html")
EDIT:
Something like this can work.
class IntroTableViewController: UITableViewController {
var labelintro = [String]()
var webAddresses = [String]()
int selectedIndex = 0;
override func viewDidLoad() {
super.viewDidLoad()
labelintro = ["Avant-propos", "Zone Sakalava", "Pronontiation", "Conjugaison", "Verbes indispensables","Grammaire & synthaxe","Mots indispensables","Les comptes","Le temps", "Termes de politesse", "La famille", "Se déplacer", "Le commerces", "Les vêtements", "Se loger", "Nourritures, épices & condiments", "Nature & paysages", "Ville, village", "L'école", "La flore", "La faune", "Santé & corps", "Artisanat, tradition & sacré", "Expressions courantes"]
webAddresses = ["xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html","xxx.html", "yyy.html"]
}
override func prepareForSegue(segue: UIStoryboardSegue,
sender: AnyObject?) {
if segue.identifier == "gotodetail" {
var detailIntroVC = segue!.destinationViewController as DetailIntroViewController;
detailIntroVC.selectedHTMLFileName = webAddresses[selectedIndex];
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return labelintro.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("texteintrocell", forIndexPath: indexPath) as! IntroTableViewCell
let row = indexPath.row
cell.labelIntro.text = labelintro[row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedIndex = indexPath.row;
self.performSegueWithIdentifier("gotodetail", sender: self)
}
}
and in DetailViewController :
class DetailIntroViewController: UIViewController {
string selectedHTMLFileName;
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
// Use filename without extension
var fileNameComponents = split(selectedHTMLFileName) {$0 == "."}
selectedHTMLFileName = fileNameComponents[0]
let localfilePath = NSBundle.mainBundle().URLForResource(selectedHTMLFileName, withExtension: "html")
}
}
This code is not tested, but you can check the flow of the process.
Changes made are:
prepareForSegue code updated
Added property selectedIndex
Added didSelectRowAtIndexPath event
Added property selectedHTMLFileName in Detail viewcontroller.
I need horizontal images in collectionview, which is inside every tableview cell. The problem I am facing is tableview gets loaded easily, but collectionview doesn't get loaded before tableview cells, because tableview loads very quickly, and hence the array for collectionview gets changed.
The code I am using for the whole view, is -
import UIKit
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout,NSURLConnectionDelegate {
#IBOutlet var tbl_data: UITableView!
var mutableData: NSMutableData!
var response: NSURLResponse!
var connection: NSURLConnection!
var thedata:NSArray!
var ary_OF_collectionView:NSArray!
override func viewDidLoad() {
super.viewDidLoad()
connection_GetPeopleList()
thedata = NSArray()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return thedata.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
//println("INdex===\(indexPath.row)")
let cell = tableView.dequeueReusableCellWithIdentifier("dTableViewCell", forIndexPath: indexPath) as! dTableViewCell
var c_snippet:String = ""
if let checkC_snip:AnyObject = thedata.objectAtIndex(indexPath.row).valueForKey("c_snippet")
{
c_snippet = checkC_snip as! String
}
var getImageArray:NSArray = (thedata.objectAtIndex(indexPath.row).valueForKey("images") as? NSArray)!
cell.lbl_like.text = c_snippet
cell.co_v.tag = indexPath.row
if(getImageArray.count > 0)
{
if(getImageArray.count == 1)
{
var getimagePath:String = getImageArray.objectAtIndex(0) as! String
if(!getimagePath.isEmpty)
{
ary_OF_collectionView = getImageArray
}else
{
ary_OF_collectionView = NSArray()
}
}else
{
ary_OF_collectionView = getImageArray
}
}else
{
ary_OF_collectionView = NSArray()
}
cell.co_v.dataSource = self
cell.co_v.delegate = self
cell.co_v.reloadData()
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return ary_OF_collectionView.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as! CollectionViewCell
var getImageUrl:String! = ary_OF_collectionView.objectAtIndex(indexPath.row) as! String
println(getImageUrl)
// This is image loader From == https://github.com/natelyman/SwiftImageLoader
ImageLoader.sharedLoader.imageForUrl(getImageUrl, completionHandler:{(image: UIImage?, url: String) in
cell.img.image = image
})
//cell.img.image = UIImage(named: ) as UIImage!
return cell
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
{
println("INinininin===\(indexPath.row)")
// var cell:dTableViewCell = cell as! dTableViewCell
// [cell setCollectionViewDataSourceDelegate:self index:indexPath.row];
}
func scrollViewDidScroll(scrollView: UIScrollView) {
println(scrollView)
// println("INinininin===\(scrollView.tag)")
}
func connection_GetPeopleList()
{
let urlPath: String = "http://carbonchase.com/v1.1/get_jives.php?user_id=3221128362&at=0&newsfeeds&count=10"
println("get_People List == \(urlPath)")
var escapedAddress = urlPath.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
var url: NSURL = NSURL(string: escapedAddress!)!
var request1: NSURLRequest = NSURLRequest(URL: url)
self.connection = NSURLConnection(request: request1, delegate: self, startImmediately: true);
connection.start()
}
func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
self.response = response
self.mutableData = NSMutableData()
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
self.mutableData.appendData(data)
}
func connectionDidFinishLoading(connection: NSURLConnection!)
{
if let jsonResult: NSArray = NSJSONSerialization.JSONObjectWithData(self.mutableData, options: nil, error:nil) as? NSArray {
thedata = jsonResult
self.tbl_data.reloadData();
self.tbl_data.delegate=self;
self.tbl_data.dataSource=self;
}
}
func connection(connection: NSURLConnection, didFailWithError error: NSError) {
println("\(error)")
}
}// END
EDITED
CollectionView is not working
How can I change the UICollectionView cell height?
As you can see, the text just stops with "...". I want the size to get bigger when the label I bigger, I want the cell size to go below the label. How can I do this? Hope you understand my question.. Anyone please?
This answer does not change the cell size at all, but it could be a solution to your problem. In your cellForItemAtIndexPath after you set your cell: let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CollectionViewCell
Try adding this: cell.imageText.adjustsFontSizeToFitWidth = true
This will make the font fit the label size, and the more text the smaller font size. Let me know how this worked for you.
You should make use of a delegate method called collectionView:layout:sizeForItemAtIndexPath from the UICollectionViewDelegateFlowLayout.
Now, the actual implementation will depend on your specific case (is it local content, if it is downloaded over the network, how many custom cells you have, etc.), but here's a copy of a very simple UICollectionViewController which works.
It makes use of a single custom cell of the type MyAwesomeCell which has a single label outlet called myAwesomeLabel.
I have not made any changes in the storyboard concerning Preferred Width, Content Compression Resistance Priority, etc. The only important change I have made is setting the lines property to 0 for the label, which means unlimited amount of lines.
PS, it's been written in Swift 2.
//
// ViewController.swift
// CollectionCell
//
// Created by Stefan Veis Pennerup on 21/09/15.
// Copyright © 2015 Kumuluzz. All rights reserved.
//
import UIKit
class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
// MARK: - Constants
struct Constants {
static let ReuseIdentifierMyAwesomeCell = "myAwesomeCell"
}
// MARK: - Models
let myAwesomeCells = [
"Lorem ipsum dolor sit amet.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed massa leo, mollis id tortor at posuere.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque semper vitae mi vel hendrerit. Suspendisse et feugiat mi. Donec quis sollicitudin quam, non porttitor nulla. Phasellus in luctus lorem, sed auctor enim. Suspendisse potenti. Ut maximus pharetra diam, ac laoreet est dignissim eu nullam."
]
var cellSizes: [CGSize]!
// MARK: - Lifecycle methods
override func viewDidLoad() {
super.viewDidLoad()
// Gives the size array an initial value since collectionView:layout:sizeForItemAtIndexPath
// is called before collectionView:cellForItemAtIndexPath
cellSizes = myAwesomeCells.map({ _ in return CGSize(width: 200, height: 50) })
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// Now that the collection view has appeared, then all the cells have been initialized
// with their appropiate content. The view should then be reloaded with the newly
// calculated sizes as well.
collectionView?.reloadData()
}
// MARK: - UICollectionViewDataSource
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
NSLog("\(self), collectionView:numberOfItemsInSection")
return myAwesomeCells.count
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
NSLog("\(self), collectionView:cellForItemAtIndexPath")
// Configures the cell
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(Constants.ReuseIdentifierMyAwesomeCell, forIndexPath: indexPath) as! MyAwesomeCell
cell.myAwesomeLabel.text = myAwesomeCells[indexPath.item]
// Calculates the height
cell.setNeedsLayout()
cell.layoutIfNeeded()
cellSizes[indexPath.item] = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
// Returns the new cell
return cell
}
// MARK: - UICollectionViewDelegate
// MARK: - UICollectionViewDelegateFlowLayout
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
NSLog("\(self), collectionView:layout:sizeForItemAtIndexPath")
return cellSizes[indexPath.item]
}
}
Try creating a fake Label with the same text, call sizetofit on it and then see the actual size of the label with full text.
Then, once you get the heigth, you can set it into your collectionViewLayout itemSize property.
I believe this way all your collectionview cell will be bigger but maybe it can be a starting point for a better solution...