A pixel perfect replacement for UITableView section index, written in Swift

Overview

MYTableViewIndex

Build Status Version License Platform

MYTableViewIndex is a re-implementation of UITableView section index. This control is usually seen in apps displaying contacts, tracks, and other alphabetically sorted data. MYTableViewIndex completely replicates native iOS section index, but can also display images and has additional customization capabilities.

Features

  • Can display images
  • Fully customizable: use custom fonts, background views, add your own type of items
  • Compatible with any UIScrollView subclass
  • Works properly with UITableViewController and UICollectionViewController
  • Automatic layout, inset management and keyboard avoidance (via TableViewIndexController)
  • Right-to-left languages support
  • Haptic Feedback support
  • Accessibility support

Below are the screenshots for some of the features:

Screenshot0 Screenshot1
Screenshot2 Screenshot3
Screenshot4 Screenshot5

Usage

1. Instantiation

Manual setup

The component is a UIControl subclass and can be used as any other view, simply by adding it to the view hierarchy. This can be done via Interface Builder or in code:

let tableViewIndex = tableViewIndex(frame: CGRect())
view.addSubview(tableViewIndex)

Note that in this case no layout is done automatically and all the required index view alignment is completely up to you.

Using TableViewIndexController

Things get more complicated when dealing with UITableViewController/UICollectionViewController. The root view of these view controllers is a UIScrollView descendant and using it as a superview for TableViewIndex is generally a bad idea, since UIScrollView delays touch delivery by default.

Enter TableViewIndexController. When used, it creates a TableViewIndex instance, adds it to the hierarchy as a sibling of the root view and sets up the layout. The controller also observes UIScrollView insets and updates index view size accordingly. This makes sense when the keyboard shows up, for example.

You can also use the controller to hide TableViewIndex for certain table sections like Apple once did in its Music app:

Screenshot4

Using TableViewIndexController the setup can be done in just one line of code:

let tableViewIndexController = TableViewIndexController(scrollView: tableView)

2. Data source

To feed index view with data, one should simply implement the following method of TableViewIndexDataSource protocol:

func indexItems(for tableViewIndex: TableViewIndex) -> [UIView] {
    return UILocalizedIndexedCollation.currentCollation().sectionIndexTitles.map{ title -> UIView in
        return StringItem(text: title)
    }
}

And attach it to the index view:

tableViewIndexController.tableViewIndex.dataSource = dataSourceObject

Several predefined types of items are available for displaying strings, images, magnifying glass, and truncation symbols. You can provide your own type of item though.

3. Delegate

To respond to index view touches and scroll table to the selected section, one should provide a delegate object and implement the following method:

func tableViewIndex(_ tableViewIndex: TableViewIndex, didSelect item: UIView, at index: Int) -> Bool {
    let indexPath = NSIndexPath(forRow: 0, inSection: sectionIndex)
    tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: false)
    
    return true // return true to produce haptic feedback on capable devices 
}

4. Customization

MYTableViewIndex is fully customizable. See TableViewIndex properties for more details.

Example

To run the example project, clone the repo, and run pod install from the Example directory first.

Requirements

  • iOS 8.0+
  • Swift 5.0

Installation

CocoaPods

MYTableViewIndex is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'MYTableViewIndex'

Manually

Download and drop all .swift files from MYTableViewIndex folder to your project.

Objective-C

All public classes of MYTableViewIndex are exposed to Objective-C, just import the library module:

@import MYTableViewIndex;

And don't forget to enable frameworks in your Podfile:

use_frameworks!

Author

Makarov Yuriy, [email protected]

License

MYTableViewIndex is available under the MIT license. See the LICENSE file for more info.

Comments
  • Touches moves not detected

    Touches moves not detected

    Hi and thank you for the great job on that library,

    I'm having an issue with what should be a default behavior of the index:

    When I tap an item, tableViewIndex(tableViewIndex, didSelectItem, atIndex) is called, but not if I swipe through the index bar. It seems like touchesBegan is called, but not touchesMoved.

    Most of my code is copied from the demo example which works perfectly fine, so I don't really know where to investigate.

    Do you by any chance have an idea of what causes the issue?

    Let me know if you need more info

    Thanks!

    opened by CKzu 7
  • Calling tableViewIndex.reloadData() the second time causes infinite loop in TableViewIndex's layoutSubviews()

    Calling tableViewIndex.reloadData() the second time causes infinite loop in TableViewIndex's layoutSubviews()

    Everything works fine if I call the following code for the first time:

    self.tableView.reloadData()
    self.tableIndexController.tableViewIndex.reloadData()
    

    but after I update data source of the table view, that code makes the app freeze because layoutSubviews() gets called infinitely in TableViewIndex. But I need to update the index view, what should I do?

    opened by 4tuneTeller 2
  • Labels sometimes disappear

    Labels sometimes disappear

    I'm seeing an issue where the labels sometimes disappear, have you seen that before?

    It occurs for me in a few different scenarios, like when I bring up the keyboard on iPad in portrait (which doesn't cause the truncation to occur because they all fit on screen) then rotate to landscape (where not all fit on screen so it has to truncate). A lot of the labels disappear, but their frame is preserved so there's space for each but they're not all visible. When I then dismiss the keyboard it expands out to show all but a few labels are not visible. What's interesting is the View Debugger shows the missing labels don't exist as subviews, they're not there at all.

    I've been trying to debug it but haven't been able to figure out why this is occurring. It seems to be an issue when the height changes, it calls layoutSubviews in the index view a few times with different heights, but the last one is always correct, yet it ends up not properly creating all the subviews it seems. Or maybe a race condition removing and re-adding? I'm not sure. Hoping you might know where the problem may lie.

    img_0336 img_0337 img_0338

    opened by hipwelljo 2
  • Take less horizontal space

    Take less horizontal space

    This is a bit of a nit pick but in my case it had serious implications. In order to tap outside of the section index to hit a table view row, you have to tap pretty far to the left. You can compare this to the native Contacts app to see the difference. For example, it interferes with the X in the screen shotted view. I tried to handle this through the indexInset property but that did not work. img_4799

    opened by tamoyal 2
  • Some public var-s of TableViewIndex not visible from Objective-C

    Some public var-s of TableViewIndex not visible from Objective-C

    Hi,

    Thanks for the nice library!

    I would like to report one small issue that I found while integrating the lib into an Objective-C project. The problem is that indexInset, indexOffset and itemSpacing var-s are missing in auto-generated header and can not be accessed from Objective C. At the same time, when you edit library code and try to specify a different name for any of those properties via @objc(...), compiler starts showing "Property cannot be marked @objc because its type cannot be represented in Objective-C" error.

    I made a small investigation and found that indexInset and indexOffset were visible correctly until 510e329ac18bba7c4900150aa2988f94ff1e3721. So, the problem appeared as soon as those struct-s became implicitly unwrapped optionals. If I now simply change them back in a way that they wouldn't be optionals anymore, the problem disappears. If on your opinion this is ok (maybe there is a better solution...), I'll do a merge request.

    opened by dgarkusha 2
  • iOS 13: UITableView in modal presentation conflicts with dismiss gesture

    iOS 13: UITableView in modal presentation conflicts with dismiss gesture

    Here is a new one coming with iOS 13 - when a UITableView is being presented as a modal, the index can't be dragged because it causes rubber banding as that modal's dismissal takes priority.

    Just starting to digging into this, but it looks like there's going to need to be some sort of callback to hook into to disable that gesture recognizer during MYTVI touches (see: https://stackoverflow.com/questions/56718552/disable-gesture-to-pull-down-form-page-sheet-modal-presentation).

    opened by Nemesisprime 1
  • Add support for left TableViewIndex

    Add support for left TableViewIndex

    The TableViewIndex is always displayed on the Right side of the tableView. Since I have Arabic text inside table view which has text from right to left it is so I need the TableViewIndex on the left side

    opened by imran20487 1
  • Manual installation issue

    Manual installation issue

    On manual installation, XCode throws error: "Redeclaration of BackgroundView class" As it is declared in Examples.swift and also a separate file named BackgroundView.swift having BackgroundView

    opened by imran20487 1
  • Xcode 10, Swift 4.3 support required

    Xcode 10, Swift 4.3 support required

    I am using this library and it's working great. But it's yet not build with Swift 4.3 as it's required for Xcode 10 now. Please add support for Swift 4.3 so that we can continue using it.

    opened by asifbilal786 1
  • Configurable minWidth and styling in constructor

    Configurable minWidth and styling in constructor

    This PR adds configurable minWidth instead of hardcoded 44 points, and extends the TableViewIndexController constructor with styling options so that you don't have to do styling like this: tableViewIndexController.tableViewIndex.font = UIFont.boldSystemFont(ofSize: 12.0)

    opened by woko666 1
  • Version 0.2.0 is not available via Cocoapods

    Version 0.2.0 is not available via Cocoapods

    Hi, Sir! Thanks for such an awesome library.

    The issue is basically described in title, so it looks like 0.2.0 version podspec is not pushed to CocoaPods master repo :)

    opened by Austinate 1
  • Didselect on country name

    Didselect on country name

    Hi there, I have implement your library in a project and i need click even of tableview cell where listed country name. Can you please help from where i can find that.

    opened by Sourav2617 0
  • Pin TableViewIndex to Specific Sections

    Pin TableViewIndex to Specific Sections

    It would be nice to have the built in feature described in the title. This is how I did it in the meantime, and here was the result. Result - TableViewIndex pinned to 3rd section pinnedindexbar

     func scrollViewDidScroll(_ scrollView: UIScrollView) {
            let contentOffsetY = scrollView.contentOffset.y
            if scrollView == tableView && searchBar.text == "" {
                if let visibleRows = tableView.indexPathsForVisibleRows {
                    let visibleSections = visibleRows.map({$0.section})
                    if let allStopsIndex = sections.index(where: {$0.type == SectionType.AllStops}), let firstAllStopCellIndexPath = visibleRows.filter({$0.section == allStopsIndex && $0.row == 1}).first {
                        let secondCell = tableView.cellForRow(at: firstAllStopCellIndexPath)
                        let newYPosition = view.convert(tableViewIndexController.tableViewIndex.indexRect(), from: tableView).minY
                        if ((newYPosition * -1.0) < (secondCell?.frame.minY)! - view.bounds.midY) {
                            let offset = (secondCell?.frame.minY)! - initialTableViewIndexMidY - contentOffsetY
                            tableViewIndexController.tableViewIndex.indexOffset = .init(horizontal: 0.0, vertical: offset)
                            tableViewIndexController.setHidden(!visibleSections.contains(allStopsIndex), animated: true)
                        }
                    }
                }
            }
        } 
    
    opened by AAAstorga 0
Releases(0.8.0)
Owner
Yury
Yury
Simple and beautiful stacked UIView to use as a replacement for an UITableView, UIImageView or as a menu

VBPiledView simple but highly effective animation and interactivity! By v-braun - viktor-braun.de. Preview Description Very simple and beautiful stack

Viktor Braun 168 Jan 3, 2023
A simple way to create a UITableView for settings in Swift.

QuickTableViewController A simple way to create a table view for settings, including: Table view cells with UISwitch Table view cells with center alig

Cheng-Yao Lin 525 Dec 20, 2022
INTUZ is presenting an interesting a Multilevel Expand/Collapse UITableView App Control to integrate inside your native iOS-based application

INTUZ is presenting an interesting a Multilevel Expand/Collapse UITableView App Control to integrate inside your native iOS-based application. MultilevelTableView is a simple component, which lets you use the tableview with multilevel tree view in your project.

INTUZ 3 Oct 3, 2022
A PageView, which supporting scrolling to transition between a UIView and a UITableView

YXTPageView ##A Page View, which support scrolling to transition between a UIView and a UITableView UIView (at the top) UITableView (at the bottom) In

Hanton Yang 68 May 25, 2022
A declarative api for working with UITableView.

⚡️ Lightning Table Lightning Table provides a powerful declarative API for working with UITableView's. Table views are the foundation of almost every

Electric Kangaroo 28 Aug 25, 2021
Easy UITableView drag-and-drop cell reordering

SwiftReorder NOTE: Some users have encountered compatibility issues when using this library with recent versions of iOS. For apps targeting iOS 11 and

Adam Shin 378 Dec 13, 2022
A cells of UITableView can be rearranged by drag and drop.

TableViewDragger This is a demo that uses a TableViewDragger. Appetize's Demo Requirements Swift 4.2 iOS 8.0 or later How to Install TableViewDragger

Kyohei Ito 515 Dec 28, 2022
A subclass of UITableView that styles it like Settings.app on iPad

TORoundedTableView As of iOS 13, Apple has released an official version of this table view style called UITableViewStyleInsetGrouped! Yay! In order to

Tim Oliver 162 Nov 2, 2022
A simpler way to do cool UITableView animations! (╯°□°)╯︵ ┻━┻

TableFlip (╯°□°)╯︵ ┻━┻ ┬──┬ ノ( ゜-゜ノ) Animations are cool. UITableView isn't. So why not make animating UITableView cool? The entire API for TableFlip

Joe Fabisevich 555 Dec 9, 2022
Protocol-oriented UITableView management, powered by generics and associated types.

DTTableViewManager Features Powerful mapping system between data models and cells, headers and footers Automatic datasource and interface synchronizat

Denys Telezhkin 454 Nov 9, 2022
A UITableView extension that enables cell insertion from the bottom of a table view.

ReverseExtension UITableView extension that enabled to insert cell from bottom of tableView. Concept It is difficult to fill a tableview content from

Taiki Suzuki 1.7k Dec 15, 2022
Simple single-selection or multiple-selection checklist, based on UITableView

SelectionList Simple single-selection or multiple-selection checklist, based on UITableView. Usage let selectionList = SelectionList() selectionList.i

Yonat Sharon 111 Oct 6, 2022
A declarative wrapper approach to UITableView

Thunder Table Thunder Table is a useful framework which enables quick and easy creation of table views in iOS, making the process of creating complex

3 SIDED CUBE 20 Aug 25, 2022
Swift package for easily rendering text tables. Inspired by the Python tabulate library.

TextTable Easily print textual tables in Swift. Inspired by the Python tabulate library. Upcoming Changes See details on an upcoming change.

Cristian Filipov 102 Jan 5, 2023
Simple static table views for iOS in Swift.

Simple static table views for iOS in Swift. Static's goal is to separate model data from presentation. Rows and Sections are your “view models” for yo

Venmo 1.3k Nov 19, 2022
A Swift library for swipeable table cells

BWSwipeRevealCell Using the library **Note: Use version 1.0.1 for Swift 2.3 support and version 2.0.0 or higher for Swift 3 support ** There are two m

Kyle Newsome 67 May 11, 2022
A no-nonsense way to write cleaner UITableViewDelegate and UITableViewDataSource in Swift.

CascadingTableDelegate A no-nonsense way to write cleaner UITableViewDelegate and UITableViewDataSource. Why is this library made? In common iOS devel

Ricardo Pramana Suranta 920 Dec 14, 2022
Swipeable UITableViewCell/UICollectionViewCell based on the stock Mail.app, implemented in Swift.

SwipeCellKit Swipeable UITableViewCell/UICollectionViewCell based on the stock Mail.app, implemented in Swift. About A swipeable UITableViewCell or UI

null 6k Jan 7, 2023
TableViews - Emoji Table View For iOS With Swift

TableViews Hello! This is EmojiTableView. Let me introduce you my first app when

null 0 Jan 2, 2022