I am trying to create UITableview with cells, identical to the iPhone settings screenshot.
It is part of my homework so i have to do it all in UITableview.
this is what I did with my code, but everything is red and full with errors. I tried to do it following the samples from lessons but it kinda looks all wrong.
Please, help me understand how this thing works and what is wrong.
import UIKit
struct Lines{
var image: [UIImage] = []
var title: [String] = []
}
class Titles {
static func titles() -> [Lines]{
return [
Lines(image: UIImage[ systemName: "airplane" ,"wifi.square.fill", "bitcoinsign.circle.fill", "iphone.homebutton.radiowaves.left.and.right", "personalhotpot" ], title: ["Авиарежим" , "Wi-fi", "Bluetooth", "Сотовая связь", "Режим модема"]),
Lines(image: UIImage[ systemName: "bell.badge.fill" ,"speaker.wave.3.fill", "moon.fill", "iphone.homebutton.radiowaves.left.and.right", "clock.fill" ], title: ["Уведомления", "Звуки,тактильные сигналы", "Не беспокоить", "Экранное время"]),
Lines(image: UIImage[ systemName: "gear" ,"switch.2", "display" ] , title: ["Общие", " Control Centre", "Экран и яркость"])
]
}
}
class SecondTableViewController: UITableViewController {
var lines = Titles.titles()
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension SecondTableViewController: UITableViewDataSource, UITableViewDelegate{
func numberOfSections(in tableView: UITableView) -> Int {
return titles.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles[section].title.count
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "SectionCell") as! TableViewCell
let title = titles[section]
cell.image = Lines.image
cell.titleLabel.text = Lines.title
return cell
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SecondTableViewCell") as! TableViewCell
let name = titles[indexPath.section].title[indexPath.row]
cell.image = Lines.image
cell.titleLabel.text = Lines.title
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
Thank you!
You use the wrong property name :
func numberOfSections(in tableView: UITableView) -> Int {
// titles is not defined
return titles.count
}
You must use :
func numberOfSections(in tableView: UITableView) -> Int {
return lines.count
}
Same for the other methods. In cellForRow :
let name = titles[indexPath.section].title[indexPath.row]
Let image = titles[indexPath.section].image[indexPath.row]
Should be replaced by :
let name = lines[indexPath.section].title[indexPath.row]
For viewFirHeader you use a cell which is usually not what is done. You have no title for each lines array. You may have to think again what you want to use. The way you organise your data may also be rethink as you have 2 different array for images and titles.
Related
I'm trying to make a table from the dictionary I have, but got an error. Since I just learning Swift I don't understand how to fix it. Could you help me please? Thank you for advance.
import UIKit
class TableViewController: UITableViewController {
var DictionaryList = dictionary() {
didSet {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
GIDSignIn.sharedInstance()?.presentingViewController = self
GIDSignIn.sharedInstance()?.restorePreviousSignIn()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return DictionaryList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let entry = DictionaryList[indexPath.row]
var key = Array<String>(self.dictionary.keys)[indexPath.row]
var value = Array<String>(self.dictionary.values)[indexPath.row]
cell.textLabel?.text = key
cell.detailTextLabel?.text = value
return cell
}
var dictionary: Dictionary = [
"line1:" : "description",
"line2:" : "description",
"line3:" : "description",
]
}
You can try like this:
class TableViewController: UITableViewController {
var DictionaryList: Dictionary<String, String> = [:] {
didSet {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.DictionaryList = [
"line1:":"description",
"line2:":"description",
"line3:":"description",
]
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return DictionaryList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
var key = Array<String>(self.DictionaryList.keys)[indexPath.row]
var value = Array<String>(self.DictionaryList.values)[indexPath.row]
cell?.textLabel?.text = key
cell?.detailTextLabel?.text = value
return cell!
}
}
This is never going to work. Dictionaries are unordered - there is no guarantee by a dictionary that keys is going to preserve the ordering each time it is called. There isn't even a guarantee that values is going to return the values in the same order that it returns the keys.
You will need to re-design your model to turn the dictionary into an ordered collection of some kind.
I'm new to Swift and i've been working on an app for a couple of day now. Now I'm trying to fill up my tableview, but for some reason it stays empty. I've checked if my data comes through (by doing a print of my drinks in the updateUi function), and it seems so be there but my view just doesn't get filled. Anyone has a clue what could be wrong?
Thanks a lot!
import UIKit
class SearchResultsTableViewController: UITableViewController {
let cocktailController = CocktailController()
var drinks = [Drink]()
var drink: String!
override func viewDidLoad() {
super.viewDidLoad()
title = drink.capitalized
cocktailController.fetchDrinks(forDrink: drink)
{ (drinks) in
if let drinks = drinks {
self.updateUI(with: drinks)
}
}
}
func updateUI(with drinks: [Drink]) {
DispatchQueue.main.async {
self.drinks = drinks
self.tableView.reloadData()
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return drinks.count
}
override func tableView(_ tableView: UITableView, cellForRowAt
indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:
"DrinkCellIdentifier", for: indexPath)
configure(cell, forItemAt: indexPath)
return cell
}
func configure(_ cell: UITableViewCell, forItemAt indexPath:
IndexPath) {
let drinkItem = drinks[indexPath.row]
cell.textLabel?.text = drinkItem.strDrink
}
}
Instead of number of sections, you should use number of rows in section to return the tableview row count.
func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
return drinks.count
}
What I'm trying to do is separate my cells into sections by their Brand
what Ive been able to do so far is pass data of selected items from HomeVC to populate the cells of the CartVC
I am trying to separate the sections by brand, the brand data is a part of the model Items Class (name, brand, imageUrl, price, & weight) and the Items class retrieves data from CloudFirestore to populate the cells of the HomeVC
How would I be able to to separate the cells into sections by their brand, when passed into the CartVC.
So far what I've done seems to fail, because once I pass an item from the HomeVC to the CartVC I only get one header cell, with the brand name of the first item I passed into the CartVC. When I pass more data into the the CartVC all the cells stay in the section of the first item passed when im trying to section off all my CartCells by their brand
extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell") as? HomeCell else { return UITableViewCell() }
let item = itemSetup[indexPath.row]
cell.configure(withItems: item)
cell.addActionHandler = { (option: Int) in
print("Option selected = \(option)")
self.tray.append(Tray(cart: item))
item.selectedOption = option
}
return cell
}
}
class CartViewController: UIViewController {
var items: ProductList!
var sectionModel: [SectionModel] = []
var tray: [Tray] = []
var groupedItems: [String: [Tray]] = [:]
var brandNames: [String] = []
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
groupedItems = Dictionary(grouping: tray, by: {$0.cart.brand})
brandNames = groupedItems.map{$0.key}.sorted()
}
}
extension CartViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell
let cart = tray[indexPath.row]
cell.configure(withItems: cart.cart)
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cartHeader = tableView.dequeueReusableCell(withIdentifier: "CartHeader") as! CartHeader
cartHeader.storeName.text = "Brand: \(tray[section].cart.brand)"
return cartHeader
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
}
class Tray {
var cart: ProductList!
init(cart: ProductList) {
self.cart = cart
}
}
just set your your tableview functions like and you'll have no problem setting things up by section
func numberOfSections(in tableView: UITableView) -> Int {
return brandNames.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let brand = brandNames[section]
return groupedItems[brand]!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cartCell = tableView.dequeueReusableCell(withIdentifier: "CartCell") as! CartCell
let brand = brandNames[indexPath.section]
let itemsToDisplay = groupedItems[brand]![indexPath.row]
cartCell.configure(withItems: itemsToDisplay.cart)
return cartCell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cartHeader = tableView.dequeueReusableCell(withIdentifier: "CartHeader") as! CartHeader
let headerTitle = brandNames[section]
cartHeader.brandName.text = "Brand: \(headerTitle)"
return cartHeader
}
I'm developing a IOS app and I want to show the array Strings from all document fields in table view.
this is my struct for the array.
struct Test{
var car: Array<String>
var dictionary: [String: Any] {
return [
"car":car
]
}
}
extension Test{
init?(dictionary: [String : Any]) {
guard let car = dictionary["car"] as? Array<String>
else { return nil }
self.init(car:car)
}
}
This is my code for fetching the data.
func loadData(){
let db = Firestore.firestore()
db.collection("test").getDocuments(){
querySnapshot, error in
if let error = error {
print("\(error.localizedDescription)")
}else{
self.testArray = querySnapshot!.documents.compactMap({Test(dictionary: $0.data())})
print(self.testArray)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
And this my tableView code.
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return testArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let item = testArray[indexPath.row].car[indexPath.row]
cell.textLabel!.text = ("\(item)")
return cell
Everything seems fine but when run the app, the tableview shows the [0] from the 1st document in the first line, the [1] from the 2nd document in the second line etc. I want to show the whole array from first document then the whole array from 2nd document etc.
You need multiple sections
override func numberOfSections(in tableView: UITableView) -> Int {
return testArray.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return testArray[section].car.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel!.text = testArray[indexPath.section].car[indexPath.row]
return cell
}
I'm fetching data from a Realm database and I want to populate a tableview with 2 sections: Autobots and Decepticons. But section property from TableView is returning just the position 0 from the array. Please help me, Thank you.
import UIKit
import RealmSwift
class ViewController: UIViewController, UITableViewDataSource {
let sections = ["Autobots","Decepticons"]
var autobotsNames : [String] = []
var decepticonsNames : [String] = []
var allTransformersNames = [[String]]()
override func viewDidLoad() {
super.viewDidLoad()
print(Realm.Configuration.defaultConfiguration.fileURL!)
let transformers = Transformers()
let transformersData = transformers.TransformersData()
for data in transformersData {
if data.group == "A" {
autobotsNames.append(data.name)
}
else {
decepticonsNames.append(data.name)
}
}
allTransformersNames.append(autobotsNames)
allTransformersNames.append(decepticonsNames)
print(autobotsNames)
print(decepticonsNames)
print(allTransformersNames)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.allTransformersNames[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Transformers", for: indexPath)
cell.textLabel?.text = self.allTransformersNames[indexPath.section][indexPath.row]
return cell
}
}
Print Results
TableView showing 1 section