Search in Grouped Uitableview

Swift grouped UITableView best practices

Even though it feels wasteful, it's more intuitive and less convoluted to have (segues to) different view controllers.

Your detail view controller has to

  • display options
  • return the selected option
  • save state

So, there are three points where you'd end up with large blocks of conditional code to determine which group of options you're dealing with, while displaying, unwinding, or preserving/restoring details.

If you added more options, a monolithic approach would only continue to grow more and more complex.

A monolithic approach is also the least flexible, if you ever needed to support a second (non-check mark) type of selection in the future.

Separating responsibilities into different (subclassed) detail view controllers means each controller can clearly and simply handle its own details. Your code will be easier to understand, maintain, and update down the road.

How to make different search field for every sections in UITableview?

I got the solution for it. please find below code for it. As i am using autolayout & storyboard for my view controller i have to take it as iboutlets and as of now i have only 2 secitions so i make it static, you can make this by creating dynamic views if you have number of sections dynamic.

// define in your .h file and take layout for the views and make it saperate from your main view container (outside of main view controller).

@property(strong,nonatomic)IBOutlet UITextField * txtSearchSection1;
@property(strong,nonatomic)IBOutlet UITextField * txtSearchSection2;

@property (strong, nonatomic) IBOutlet UIView *viewSection1;
@property (strong, nonatomic) IBOutlet UIView *viewSection2;

// Implement in your .m file
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 2;
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 40.0f;
}
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (section==1) {
return _viewSection1;
}else{
return _viewSection2;
}
}

Grouped TableView

This is a good tutorial on customising a grouped UITableView, although it does assume that you are proficient with an image editor to create the various custom images.

How do you do you group sections in tableview?

found my solution

import Foundation

struct Items {
let store: String
let productName: String
let productImage: UIImage
let quantity: String
let price: String
}

extension Items: Comparable {
static func < (lhs: Items, rhs: Items) -> Bool {
if lhs.store < rhs.store { return true }
else { return lhs.store == rhs.store && lhs.productName < rhs.productName }
}
}

extension Items {
static let retail: [Items] = [
.init(store: "Amazon",
productName: "Care Bear",
productImage: #imageLiteral(resourceName: "Bear"),
quantity: "4",
price: "156"),
.init(....
]
}

import Foundation

class ItemDataSource: NSObject {
var sections: [String: [Items]] = [:]

var items: [String] {
return sections.keys.sorted()
}

var indexes: [String] {
return items
.map { String($0.first!) }
.reduce(into: Set<String>(), { $0.insert($1) })
.sorted()
}

init(stores: [Items]) {
for store in retail.sorted(by: <) {
let items = store.items
if var stores = sections[items] {
stores.append(store)
sections[items] = stores
} else {
sections[items] = [store]
}
}
}
}

class StoreHeader: UITableViewCell {

@IBOutlet weak var dispensaryName: UILabel!

var store: String? {
didSet { storeName.text = "Store: \(store!)" }
}

}

class StoreCell: UITableViewCell {

@IBOutlet weak var productImage: UIImageView!
@IBOutlet weak var productQty: UILabel!
@IBOutlet weak var productPrice: UILabel!
@IBOutlet weak var productName: UILabel!

var product: String? {
didSet { productName.text = product }
}
var quantity: String? {
didSet { productQty.text = "Qty: \(quantity!)" }
}
var price: String? {
didSet { productPrice.text = "$\(price!)" }
}
var img: UIImage? {
didSet { productImage.image = img }
}

}

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

let dataSource: ItemDataSource = .init(stores: Items.stores)

@IBOutlet weak var tableView: UITableView!

func numberOfSections(in tableView: UITableView) -> Int {
return dataSource.sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let store = dataSource.items[section]
return dataSource.sections[store]?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let storeCell = tableView.dequeueReusableCell(withIdentifier: "StoreCell") as! StoreCell
let store = dataSource.items[indexPath.section]
let storeItem = dataSource.sections[store]?[indexPath.row]

storeCell.product = storeItem?.productName
storeCell.price = storeItem?.price
storeCell.quantity = storeItem?.quantity
storeCell.img = storeItem?.productImage

return storeCell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let storeHeader = tableView.dequeueReusableCell(withIdentifier: "StoreHeader") as! StoreHeader
storeHeader.store = dataSource.items[section]
return storeHeader
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}

Implement Search bar and search display for the table view with sections

I have made the following changes and got the desired output.

I am storing my string array in the Core Data with a flag for POPUlAR FOOD in the Core Data and fetching these details and storing in different arrays according to alphabets.

Created a switch case to show the sections in the table view.

var distinctstring = [String]()
var arr = [String]()
var arrA = [String]()
var arrB = [String]()
var arrC = [String]()
var arrD = [String]()
var arrE = [String]()
var arrF = [String]()
var arrG = [String]()
var arrH = [String]()
var arrI = [String]()
var arrJ = [String]()
var arrK = [String]()
var arrL = [String]()
var arrM = [String]()
var arrN = [String]()
var arrV = [String]()
var arrX = [String]()
var arrZ = [String]()
var arrP = [String]()
var arrO = [String]()
var arrY = [String]()
var arrU = [String]()
var arrT = [String]()
var arrR = [String]()
var arrW = [String]()
var arrQ = [String]()
var arrS = [String]()

var poparr = [String]()
var filteredTableData = [String]()
var resultSearchController = UISearchController()
let collation = UILocalizedIndexedCollation.currentCollation()
as! UILocalizedIndexedCollation

override func viewDidLoad() {
super.viewDidLoad()
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
distinctstring.append("POPULAR FoodS")
var context: NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Food")
var request1 = NSFetchRequest(entityName: "Food")
if var resultsFood = context.executeFetchRequest(request, error: nil) as? [Food]
{
//println("\n Food Results in Table view : \(resultsFood)")
for resultsb in resultsFood
{

if (resultsFood.count > 0)
{
println("\(resultsb.Food_name) : \(resultsb.popularity) ")

if (resultsFood.count > 0)
{
var firstchar = resultsb.Food_name.substringToIndex(resultsb.Food_name.startIndex.successor())
distinctstring.append(firstchar)
println("firstchar : \(firstchar)")
switch firstchar {

case "A" :

arrA.append(resultsb.Food_name)

case "B" :

arrB.append(resultsb.Food_name)

case "C" :

arrC.append(resultsb.Food_name)

case "D" :

arrD.append(resultsb.Food_name)

case "E" :

arrE.append(resultsb.Food_name)

case "F" :

arrF.append(resultsb.Food_name)

case "G" :

arrG.append(resultsb.Food_name)

case "H" :

arrH.append(resultsb.Food_name)

case "I" :

arrI.append(resultsb.Food_name)

case "J" :

arrJ.append(resultsb.Food_name)

case "K" :

arrK.append(resultsb.Food_name)

case "L" :

arrL.append(resultsb.Food_name)

case "M" :

arrM.append(resultsb.Food_name)

case "N" :

arrN.append(resultsb.Food_name)

case "O" :

arrO.append(resultsb.Food_name)

case "P" :

arrP.append(resultsb.Food_name)

case "Q" :

arrQ.append(resultsb.Food_name)

case "R" :

arrR.append(resultsb.Food_name)

case "S" :

arrS.append(resultsb.Food_name)

case "T" :

arrT.append(resultsb.Food_name)

case "U" :

arrU.append(resultsb.Food_name)

case "V" :

arrV.append(resultsb.Food_name)

case "W" :

arrW.append(resultsb.Food_name)

case "X" :

arrX.append(resultsb.Food_name)

case "Y" :

arrY.append(resultsb.Food_name)

case "Z" :

arrZ.append(resultsb.Food_name)

default:
println("No present")
}
arr.append(resultsb.Food_name)
}
}
else
{
println("No rows found")

}

}
println("array A = \(arrA)")
println("array B = \(arrB)")
println("array C = \(arrC)")
println("array D = \(arrD)")
println("array E = \(arrE)")
println("array F = \(arrF)")
println("array G = \(arrG)")
println("array H = \(arrH)")
println("array I = \(arrI)")
println("array J = \(arrJ)")
println("array K = \(arrK)")
println("array L = \(arrL)")
println("array M = \(arrM)")
println("array N = \(arrN)")
println("array O = \(arrO)")
println("array P = \(arrP)")
println("array Q = \(arrQ)")
println("array R = \(arrR)")
println("array S = \(arrS)")
println("array T = \(arrT)")
println("array U = \(arrU)")
println("array V = \(arrV)")
println("array W = \(arrW)")
println("array X = \(arrX)")
println("array Y = \(arrY)")
println("array Z = \(arrZ)")

distinctstring = uniq(distinctstring)

}

if var resultsFood1 = context.executeFetchRequest(request1, error: nil) as? [Food]
{
//println("\n Food Results in Table view : \(resultsFood)")
for resultsb in resultsFood1
{

if (resultsFood1.count > 0)
{

//println("\n Table view Results ")
//println("Value of Foodname Array : \(resultsb)")
if (resultsFood1.count > 0)
{
if (resultsb.popularity == 1)
{ println("Value of pop Foodname Array \(resultsb.Food_name) : \(resultsb.popularity) ")
poparr.append(resultsb.Food_name)
}
}
}
else
{
println("No rows found")

}

}
println("poparr = \(poparr)")

}

self.Foodtable.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")

Foodtable.dataSource = self
Foodtable.delegate = self
//searchBar.delegate = self

self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
controller.searchBar.placeholder = "Search by Food name"
self.Foodtable.tableHeaderView = controller.searchBar

return controller
})()

// Reload the table
self.Foodtable.reloadData()
// Do any additional setup after loading the view.
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// 2
if (self.resultSearchController.active) {
return self.filteredTableData.count
}
else {

switch distinctstring[section]
{

case "POPULAR FOOD" :

return self.poparr.count

case "A" :

return self.arrA.count

case "B" :

return self.arrB.count

case "C" :

return self.arrC.count

case "D" :

return self.arrD.count

case "E" :

return self.arrE.count

case "F" :

return self.arrF.count

case "G" :

return self.arrG.count

case "H" :

return self.arrH.count

case "I" :

return self.arrI.count

case "J" :

return self.arrJ.count

case "K" :

return self.arrK.count

case "L" :

return self.arrL.count

case "M" :

return self.arrM.count

case "N" :
return self.arrN.count
case "O" :
return self.arrO.count
case "P" :
return self.arrP.count
case "Q" :
return self.arrQ.count
case "R" :
return self.arrR.count
case "S" :
return self.arrS.count
case "T" :
return self.arrT.count
case "U" :
return self.arrU.count
case "V" :
return self.arrV.count
case "W" :
return self.arrW.count
case "X" :
return self.arrX.count
case "Y" :
return self.arrY.count
case "Z" :
return self.arrZ.count

default:

return self.arr.count

}

}
}

func uniq<S: SequenceType, E: Hashable where E==S.Generator.Element>(source: S) -> [E] {
var seen: [E:Bool] = [:]
return filter(source) { seen.updateValue(true, forKey: $0) == nil }
}

///////////////////////////////////////Section

func numberOfSectionsInTableView(tableView: UITableView) -> Int {

return (distinctstring.count)

}

///////////////////////////////////////Section

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
tableView.deselectRowAtIndexPath(indexPath, animated: true)

var dishes = ""
if (self.resultSearchController.active) {

dishes = filteredTableData[indexPath.row]

}
else {
println("distinctLetters : \(distinctstring[indexPath.section])")
switch (distinctstring[indexPath.section]) {

case "POPULAR FOOD" :

dishes = poparr[indexPath.row]

case "A" :

dishes = arrA[indexPath.row]

case "B":

dishes = arrB[indexPath.row]

case "C":

dishes = arrC[indexPath.row]

case "D" :

dishes = arrD[indexPath.row]

case "E":

dishes = arrE[indexPath.row]

case "F":

dishes = arrF[indexPath.row]

case "G" :

dishes = arrG[indexPath.row]

case "H":

dishes = arrH[indexPath.row]

case "I":

dishes = arrI[indexPath.row]

case "J" :

dishes = arrJ[indexPath.row]

case "K":

dishes = arrK[indexPath.row]

case "L":

dishes = arrL[indexPath.row]

case "M" :

dishes = arrM[indexPath.row]

case "N":

dishes = arrN[indexPath.row]

case "O":

dishes = arrO[indexPath.row]

case "P" :

dishes = arrP[indexPath.row]

case "Q":

dishes = arrQ[indexPath.row]

case "R":

dishes = arrR[indexPath.row]

case "S" :

dishes = arrS[indexPath.row]

case "T":

dishes = arrT[indexPath.row]

case "U":

dishes = arrU[indexPath.row]

case "V" :

dishes = arrV[indexPath.row]

case "W":

dishes = arrW[indexPath.row]

case "X":

dishes = arrX[indexPath.row]

case "Y" :

dishes = arrY[indexPath.row]

case "Z":

dishes = arrZ[indexPath.row]
//return sectionHeaderView
default:

dishes = arr[indexPath.row]
}

}
println("row selected : \(dishes)")
}

func tableView(tableView: UITableView,titleForHeaderInSection section: Int) -> String?{

if (self.resultSearchController.active) {

return ""
}
else {
return "\(distinctstring[section])"
}

}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell;
cell.textLabel!.font = UIFont(name: "Gotham", size: 13)

//println("distinctLetters in cell : \(distinctLetters[indexPath.section]) ")
cell.textLabel!.numberOfLines = 2;
if (self.resultSearchController.active) {
cell.textLabel?.text = filteredTableData[indexPath.row]

return cell
}
else {

switch (distinctstring[indexPath.section]) {

case "POPULAR FOOD" :

cell.textLabel?.text = poparr[indexPath.row]
case "A" :

cell.textLabel?.text = arrA[indexPath.row]

case "B":

cell.textLabel?.text = arrB[indexPath.row]

case "C":

cell.textLabel?.text = arrC[indexPath.row]

case "D" :

cell.textLabel?.text = arrD[indexPath.row]

case "E":

cell.textLabel?.text = arrE[indexPath.row]

case "F":

cell.textLabel?.text = arrF[indexPath.row]

case "G" :

cell.textLabel?.text = arrG[indexPath.row]

case "H":

cell.textLabel?.text = arrH[indexPath.row]

case "I":

cell.textLabel?.text = arrI[indexPath.row]

case "J" :

cell.textLabel?.text = arrJ[indexPath.row]

case "K":

cell.textLabel?.text = arrK[indexPath.row]

case "L":

cell.textLabel?.text = arrL[indexPath.row]

case "M" :

cell.textLabel?.text = arrM[indexPath.row]

case "N":

cell.textLabel?.text = arrN[indexPath.row]

case "O":

cell.textLabel?.text = arrO[indexPath.row]

case "P" :

cell.textLabel?.text = arrP[indexPath.row]

case "Q":

cell.textLabel?.text = arrQ[indexPath.row]

case "R":

cell.textLabel?.text = arrR[indexPath.row]

case "S" :

cell.textLabel?.text = arrS[indexPath.row]

case "T":

cell.textLabel?.text = arrT[indexPath.row]

case "U":

cell.textLabel?.text = arrU[indexPath.row]

case "V" :

cell.textLabel?.text = arrV[indexPath.row]

case "W":

cell.textLabel?.text = arrW[indexPath.row]

case "X":

cell.textLabel?.text = arrX[indexPath.row]

case "Y" :

cell.textLabel?.text = arrY[indexPath.row]

case "Z":

cell.textLabel?.text = arrZ[indexPath.row]
//return sectionHeaderView
default:

cell.textLabel?.text = arr[indexPath.row]
}

return cell
}Food
//return cell;
}

func updateSearchResultsForSearchController(searchController: UISearchController)
{
filteredTableData.removeAll(keepCapacity: false)

let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %@", searchController.searchBar.text)
let array = (arr as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]

self.Foodtable.reloadData()
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prefersStatusBarHidden() -> Bool {
return true
}

}

Grouped UITableView from array of objects

Typically you would create an array of dictionaries, each dictionary would have the group name and an array of members.

Another alternative is to build your dictionary of groups, just as you are, and then pull the keys into an array and use that array as your group names:

let groupNames = tableData.keys.sort()

Save the group names as a property on the VC and then you can use them to get back to the correct group when you need the user data:

let user = tableData[groupNames[indexPath.section]][indexPath.row]


Related Topics



Leave a reply



Submit