Is there any way to get click event of the table view section indexing?
I have researched lots but not got any appropriate suggestion.
does anyone know how to get click event action of indexing?
I want to get click event of this blue marked indexing in the below image.
You can use the tableView(_:sectionForSectionIndexTitle:at:) method to return the appropriate section index when a index title is clicked.
let sectionArr = ["a","a","b","c","d","d"]
func numberOfSections(in tableView: UITableView) -> Int {
return sectionArr.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionArr[section]
}
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return Array(Set(sectionArr))//["a","b","c","d"]
}
func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
if let index = sectionArr.firstIndex(where: { $0 == title }) {
return index//0 for a, 2 for b, 3 for c, 4 for d
}
return 0
}
You can use a custom view as the index view of the UITableView as shown in below reference :
Custom UITableView section index
This is in Objective-c but I think it is a great reference as that has the touchesBegan, touchesMoved, touchesEnded and touchesCancelled events and you can set the user experience with these as you would like. Also it would be very easy to add customised behaviours in this custom indexing view.
Hope this helps.
Related
I have to make a dynamic datasource for a table, that satisfies the criteria:
we do not know exact number of sections
we do not know exact title for header in section
we do not now how many rows it will be in each section each time
To detect number of rows per section I have the following code:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let header = tableView.headerView(forSection: section)
return self.servicesData?.filter({ $0.clubName == header?.textLabel?.text }).count ?? 0
}
where servicesData is the object array that is to be filtered by the header title aka clubName. Titles are gathered from the object array.
For some reason I always get nil when try to access the header. So far I tried calling tableView(_:titleForHeaderInSection:) directly in numberOfRowsInSection but obviously with no luck.
Feedback much appreciated.
It is nil because it is not created at that moment. You should not use tableView.headerView(forSection: section) in numberOfRows. You should use the model from where you get the title to use it to filter in the array.
You should fetch all of your data before populating the table view and first. Then you should implement:
func numberOfSections(in tableView: UITableView) -> Int {
return headerModels.count
}
where headerModels it's an array of objects with your title and it's items like:
class HeaderModel {
let title: String
let items: [YourItem]
}
and then:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return headerModels[section].items.count
}
So, as per #shurtugal 's solution it is possible to pass-in an array of objects to populate the table. I thought that creating a utility class for this very case may be too much. So here's the slightly altered way:
Consider a dictionary var servicesData = [String: [CustomObject]]() that is populated each time the ViewController shows up. The dictionary can have indefinite number of keys and indefinite number of values inside each key. Algorithm of populating the dictionary is taken from this answer.
Thereby, UITableViewDatasource methods can be defined like this:
func numberOfSections(in tableView: UITableView) -> Int {
self.servicesData.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Array(self.servicesData.values)[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
/* cell creation code code */
/// sample line
cell?.someLabel.text = Array(self.servicesData.values)[indexPath.section][indexPath.row]
return cell
}
Hi guys inside my tableView class i have following enum
enum tabelSecion {
case action
case drama
case comedy
}
i need to use this enum to have 3 different section header. also i created a nib to represents a custom sectionHeaderCell which has only a label inside it.how can i show section headers?
appreciate for your help
You can do it by extending your enum with a dynamic var SectionTitle.
enum TabelSection: Int, CaseIterable {
case action
case drama
case comedy
var sectionTitle: String {
switch self {
case action: return "Action"
...
}
}
}
By making you enum an Int, it is possible to init it with a rawValue. The rawValue to init it is the section it you get from the TableView Method.
The CaseIterable is also quit nice so you can get the number cases (=sections) from it for the numberOfSections Method.
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return TabelSection(rawValue: section)?.sectionTitle
}
Edit:
To display a headerView for each section of the tableView change the TableViewstyle to Grouped
In your code just provide the tableView with the correct amount of sections.
override func numberOfSections(in tableView: UITableView) -> Int {
return TabelSection.allCases.count
}
If you really need a custom HeaderView you may use the following Method to do so
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
...
}
I'm trying to adopt the new iOS 13 UITableViewDiffableDataSource and I've hit a snag; I can't work how to implement
func sectionIndexTitles(for tableView: UITableView) -> [String]?
That's a data source method, not a delegate method. So, now that the data source is the UITableViewDiffableDataSource, it needs to implement that method. But it doesn't.
I tried subclassing UITableViewDiffableDataSource and adding an implementation of sectionIndexTitles, but my implementation was never called:
class MyDataSource : UITableViewDiffableDataSource<String,String> {
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return self.snapshot().sectionIdentifiers // not called
}
}
Has anyone solved this one? I'll file it as a bug just in case.
You need to subclass UITableViewDiffableDataSource and then overwrite
func sectionIndexTitles(for tableView: UITableView)
by yourself.
To enable the index' functionality though, you have to also overwrite
func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int)
Here is an example how I implemented it:
import UIKit
import MediaPlayer
class TableViewDiffableDataSource: UITableViewDiffableDataSource<String, MPMediaItemCollection> {
var sectionTitles = [String]()
override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return sectionTitles
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionTitles[section]
}
override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
return sectionTitles.firstIndex(of: title) ?? 0
}
}
Credits go to Steve Breen, who led me in the right direction.
After you init self.dataSource to UITableViewDiffableDataSource (which sets itself to the tableView.dataSource) set the tableView.dataSource back to self, i.e. the UITableViewController subclass. Now in your numberOfSectionsInTableView and numberOfRowsInSection methods forward those to self.dataSource and return its info (this is the composition pattern). Now your UITableViewController just implements its section titles as normal since it is the table's data source.
I believe UITableViewDiffableDataSource should not be setting itself as the dataSource if one is already set but I guess they designed it to work in the least error prone way because with UITableViewController added to a storyboard it's set as the dataSource and delegate by default.
I need an advice with ViewContoller's scheme. I should create a view with Billing addresses. There can be no address at all, or some addresses. If there no one, there should be only a button "Add New". And if there are addresses, each should have buttons Edit, Remove, and "Add New" too.
I have data for this VC as JSON, parsed and saved to plist.
So what is logic to make this View looks different depends on 1) if there are addresses or not? and 2) if there 1, or 2, or maybe 20 billing addresses?
Thanks a lot!
I solved issues like this with UITableVIew and the UITableViewDataSource and UITableViewDelegate:
setup the table view for one section (adresses)
func numberOfSections(in tableView: UITableView) -> Int {return 1;}
return the address arrays length in the delegate method
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return adresses.count
}
set the view for footer if the arrays length is 0
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
if adresses.count == 0 {
let vw = YourViewClass()
//I use blockskit library here (vw.bk_) to recognize a tap, but you can add a button by yourself
vw.bk_(whenTapped: {
//Create and present your next viewcontroller to
})
return vw
}
return nil
}
set the footers height to 0 if there are addresses
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
if addresses.count > 0 {
return YOUR_DESIRED_FOOTER_HEIGHT_FOR_INPUT
}
return 0
}
create row for each address
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let address = addresses[indexPath.row]
let tableViewCell = UITableViewCell() //maybe you have to create your own if the layout does not fit
//set tableViewCell's title / description to show address values
return tableViewCell
}
In this case, the footer view (you can do the same in the header if you want) with the add button is shown when no addresses are available, and it is hidden, when addresses are available.
As I am new in Swift I got stuck in a situation. I am working on a app in which I want show side index section like in a contact app. I have used this code in my app
func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int{
print(sections.index(of:title)!)
return sections.index(of:title)!
}
But this method never get called, And the TableView is not showing the side index section. I am using Swift 3. Any help will be appreciated.
I have a tableview in which country list is there now i want to focus particular section with selection of section index (A..Z). I have implemented the above code but section index is not showing.
After a long research got the solution i was doing a silly mistake. To focus on selected section we need to scroll the tableView at selected section with this code.
You can see complete code here :https://github.com/ipraba/EPContactsPicker/blob/master/Pods/EPContactsPicker.swift
override open func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
// if resultSearchController.isActive { return 0 }
tableView.scrollToRow(at: IndexPath(row: 0, section: index), at: UITableViewScrollPosition.top , animated: false)
return sections.index(of: title)!
}