Swiftpack.co - Package - pavankataria/SwiftDataTables

Swift DataTables

Twitter: @pavan_kataria

SwiftDataTables allows you to display grid-like data sets in a nicely formatted table for iOS. The main goal for the end-user is to be able to obtain useful information from the table as quickly as possible with the following features: ordering, searching, and paging; and to provide an easy implementation with extensible options for the developer.

Major Features include:

  • ☑ Tested on iOS 8.0, 9, 10, 11, and 12 onwards.
  • ☑ Full Swift 5 support
  • ☑ Mobile friendly. Tables adapt to the viewport size.
  • ☑ Instant search. Filter results by text search.
  • [X] Fixed/frozen columns support for both left and right sides.
  • ☑ Continued support and active development!
  • ☑ Full Datasource and delegate support!
  • ☑ Demo project available show casing all types of customisations
  • ☑ Or easy plugin configuration object can be passed with default values for your swift data table's visual presentation.
  • ☑ Can filter your datasource by scanning all fields.
  • ☑ Can sort various types of data in your grid, smartly, detecting numbers and strings
  • ☑ Width columns and height rows configurable or fall back to automatic proportion scaling depending on content
  • ☑ Beautiful alternating colours for rows and column selections.
  • ☑ Fully configurable header and footer labels including search view too.
  • ☑ and beautiful clean presentation.

Install

Carthage

  • Add the following to your Cartfile: github "pavankataria/SwiftDataTables"
  • Then run carthage update
  • Follow the current instructions in Carthage's README for up to date installation instructions.

CocoaPods

  • Add the following to your Podfile: pod 'SwiftDataTables'
  • You will also need to make sure you're opting into using frameworks: use_frameworks!
  • Then run pod install.

Demo Project Included

To run the example project do the following:

  1. Download or clone the repo (git clone https://github.com/pavankataria/SwiftDataTables)
  2. Change directory into the DemoSwiftDataTables/Example folder (cd SwiftDataTables/Example)
  3. With Xcode 9 installed, as normal, open the SwiftDataTables.xcodeproj project
  4. Build and Run.

If you have any questions or wish to make any suggestions, please open an issue with the appropriate label, and I'll get back to you right away. Thank you

Configuration

There's a configuration object that can be set on the data table for quick option settings. Or you can use the delegate methods for dynamic option changes.

Data Source methods.

This is an optional data source implementation, you can also initialiase your SwiftDataTable with a static data set as shown in the Demo project so you can avoid conforming to the data source. But for those who want to show more dynamic content, use the following SwiftDataTableDataSource protocol.


public protocol SwiftDataTableDataSource: class {
    
    /// The number of columns to display
    func numberOfColumns(in: SwiftDataTable) -> Int
    
    /// Return the total number of rows that will be displayed in the table
    func numberOfRows(in: SwiftDataTable) -> Int
    
    /// Return the data for the given row
    func dataTable(_ dataTable: SwiftDataTable, dataForRowAt index: NSInteger) -> [DataTableValueType]
    
    /// The header title for the column position to be displayed
    func dataTable(_ dataTable: SwiftDataTable, headerTitleForColumnAt columnIndex: NSInteger) -> String
}

Delegate for maximum customisation

An optional delegate for further customisation. Default values will be used retrieved from the SwiftDataTableConfiguration file. This will can be overridden and passed into the SwiftDataTable constructor incase you wish not to use the delegate.


@objc public protocol SwiftDataTableDelegate: class {
    /// Fired when a cell is selected.
    ///
    /// - Parameters:
    ///   - dataTable: SwiftDataTable
    ///   - indexPath: the index path of the row selected
    @objc optional func didSelectItem(_ dataTable: SwiftDataTable, indexPath: IndexPath)

    /// Fired when a cell has been deselected
    ///
    /// - Parameters:
    ///   - dataTable: SwiftDataTable
    ///   - indexPath: the index path of the row deselected
    @objc optional func didDeselectItem(_ dataTable: SwiftDataTable, indexPath: IndexPath)

    /// Specify custom heights for specific rows. A row height of 0 is valid and will be used.
    @objc optional func dataTable(_ dataTable: SwiftDataTable, heightForRowAt index: Int) -> CGFloat

    /// Specify custom widths for columns. This method once implemented overrides the automatic width calculation for remaining columns and therefor widths for all columns must be given. This behaviour may change so that custom widths on a single column basis can be given with the automatic width calculation behaviour applied for the remaining columns.
    @objc optional func dataTable(_ dataTable: SwiftDataTable, widthForColumnAt index: Int) -> CGFloat
    
    /// Column Width scaling. If set to true and the column's total width is smaller than the content size then the width of each column will be scaled proprtionately to fill the frame of the table. Otherwise an automatic calculated width size will be used by processing the data within each column.
    /// Defaults to true.
    @objc optional func shouldContentWidthScaleToFillFrame(in dataTable: SwiftDataTable) -> Bool
    
    /// Section Header floating. If set to true headers can float and remain in view during scroll. Otherwise if set to false the header will be fixed at the top and scroll off view along with the content.
    /// Defaults to true
    @objc optional func shouldSectionHeadersFloat(in dataTable: SwiftDataTable) -> Bool
    
    /// Section Footer floating. If set to true footers can float and remain in view during scroll. Otherwise if set to false the footer will be fixed at the top and scroll off view along with the content.
    /// Defaults to true.
    @objc optional func shouldSectionFootersFloat(in dataTable: SwiftDataTable) -> Bool
    
    
    /// Search View floating. If set to true the search view can float and remain in view during scroll. Otherwise if set to false the search view will be fixed at the top and scroll off view along with the content.
    //  Defaults to true.
    @objc optional func shouldSearchHeaderFloat(in dataTable: SwiftDataTable) -> Bool
    
    /// Disable search view. Hide search view. Defaults to true.
    @objc optional func shouldShowSearchSection(in dataTable: SwiftDataTable) -> Bool
    
    /// The height of the section footer. Defaults to 44.
    @objc optional func heightForSectionFooter(in dataTable: SwiftDataTable) -> CGFloat
    
    /// The height of the section header. Defaults to 44.
    @objc optional func heightForSectionHeader(in dataTable: SwiftDataTable) -> CGFloat
    
    /// The height of the search view. Defaults to 44.
    @objc optional func heightForSearchView(in dataTable: SwiftDataTable) -> CGFloat
    
    /// Height of the inter row spacing. Defaults to 1.
    @objc optional func heightOfInterRowSpacing(in dataTable: SwiftDataTable) -> CGFloat
    
    /// Control the display of the vertical scroll bar. Defaults to true.
    @objc optional func shouldShowVerticalScrollBars(in dataTable: SwiftDataTable) -> Bool
    
    /// Control the display of the horizontal scroll bar. Defaults to true.
    @objc optional func shouldShowHorizontalScrollBars(in dataTable: SwiftDataTable) -> Bool
    
    /// Control the background color for cells in rows intersecting with a column that's highlighted.
    @objc optional func dataTable(_ dataTable: SwiftDataTable, highlightedColorForRowIndex at: Int) -> UIColor
    
    /// Control the background color for an unhighlighted row.
    @objc optional func dataTable(_ dataTable: SwiftDataTable, unhighlightedColorForRowIndex at: Int) -> UIColor

    /// Return the number of fixed columns
    @objc optional func fixedColumns(for dataTable: SwiftDataTable) -> DataTableFixedColumnType
    
    /// Return `true` to support RTL layouts by flipping horizontal scroll on `CollectionViewFlowLayout`, if the current interface direction is RTL.
    @objc optional func shouldSupportRightToLeftInterfaceDirection(in dataTable: SwiftDataTable) -> Bool
}

Getting involved

  • If you want to contribute please feel free to submit pull requests.
  • If you have a feature request please open an issue.
  • If you found a bug check older issues before submitting an issue.
  • If you need help or would like to ask general question, create an issue.

Before contribute check the CONTRIBUTING file for more info.

If you use SwiftDataTables in your app We would love to hear about it! Drop me a line on twitter.

Author

Pavan Kataria

👨‍💻 Contributors

Sebastien Senechal Hais Daekin

License

SwiftDataTables is available under the MIT license. See the LICENSE file for more info. This package was inspired by JQuery's DataTables plugin.

Github

link
Stars: 222

Dependencies

Used By

Total: 0

Releases

- 2019-08-29 02:04:45

Summary:

  • You will now automatically truly support right-to-left (RTL) language users.

Technical:

  • Previously only the text within the data table would be flipped RTL for RTL languages but the content within the scrollview - such as columns - would remain in left-to-right. This release introduces the fix and ensures the layout direction is also along with the text giving a true RTL experience to RTL language users.

In practise

How do I opt in and ensure my users can benefit from this feature?

The package automatically enables this feature for you.

How can I manage this feature myself?

You can choose to opt out or opt in for certain data tables in two ways:

Via Delegate method

Simply adopt the SwiftDataTable's delegate method with the following signature:

    func shouldSupportRightToLeftInterfaceDirection() -> Bool {
        // and return true or false here. True will allow the data table to detect if a RTL language is being used and will flip the entire layout appropriately and display content correctly.
        // false will leave the layout direction and only flip the text which would happen regardless anyway without this feature.
        return true 
    }

Via Configuration

var configuration = DataTableConfiguration()
// The default is true
configuration.shouldSupportRightToLeftInterfaceDirection: Bool = false // set to false incase you don't want to use this feature

Fixed Columns are here! Freeze those columns! - 2019-06-19 04:25:07

Summary:

  • You can now have fixed columns on both left and right hand sides! It's as easy as either specifying the fixedColumns property in the configuration object, or by implementing the fixedColumns delegate method.

Technical:

  • Due to objective-c delegate requirements the type you return in the fixedColumns delegate method is a class instead of Swift's struct type.
  • Tests have been added to ensure the new DataTableFixedColumnType initialises as expected.
  • The leftColumn and rightColumn arguments in the initialiser are one-index based. That is they start at 1. This is to create a natural declaration of the fixed columns. For example, DataTableFixedColumnType.init(leftColumns: 2, rightColumns: 2) would fix the first 2 columns (from the left) and the last 2 columns (from the right).
  • As usual the delegate method will take priority. So the fixedColumns object will first be fetched from the delegate method and if it's not implemented it will fallback on the configuration object. So if you want the fixedColumn configuration value to be read then you need to make sure to omit the fixedColumns delegate method.

In practise

How to use the new Fixed columns feature!

Here's how you define which columns you want frozen, by using the all new DataTableFixedColumnType class, and using any of the initialisers like so

// Example 1 - freeze from the left
DataTableFixedColumnType(leftColumns: 1) // this will freeze the n number of columns from the left of the table. In this case column number 1 - the first columns. This is a one-index based system

// Example 2 .- freeze from the right
DataTableFixedColumnType(rightColumns: 1) // this will freeze n number of columns from the right of the table. In this case the last column. 

// Example 3 - multiple columns
DataTableFixedColumnType(leftColumns: 2, rightColumns1) // You can specify multiple columns to be frozen on both sides. In this case the first 2 columns and the last column.

You can implement fixed columns in your data table in two ways:

Via Delegate method

Simply adopt the SwiftDataTable's delegate method with the following signature:

@objc optional func fixedColumns(for dataTable: SwiftDataTable) -> DataTableFixedColumnType {
    // and return the object here
    return .init(leftColumn: 2) // freeze the first two columns
}

Via Configuration

var configuration = DataTableConfiguration()
configuration.fixedColumns = .init(leftColumns: 2, rightColumns: 1) // freeze both the first two columns, and the last column

Swift 5, beginning of Tests, fixes, and improvements! - 2019-06-18 17:31:32

Summary:

  • Library upgraded to Swift 5
  • Introduction of tests to reduce regression and make the library more bullet proof.
  • Sorting arrow colour can be customised now in the configuration object.
  • Fix: Using a specific initialiser would ignore DataTableConfiguration leading to custom configurations not being used.

Technical:

  • The swift language has been upgraded to swift 5
  • A test target has been added, with an initial tests to ensure initialisation with custom configuration works for a specific initialiser that would previously not initialise with the configuration object.
  • The SwiftDataTableConfiguration and DataTableColumnOrder models now conforms to Equatable
  • The sorting arrow icons now render as template mode enabling a custom colour.

Fixes a crash when datasource is empty and makes datasource rows public - 2019-03-07 22:56:44

Summary:

  • Fixes crash when datasource is empty
  • Demo project updated to show an empty state
  • rows property is now available allowing you to access the current datasource as it is - maintained by SwiftDataTable.
  • There's a new method which allows you to fetch the data value type for a given index path - see technical information for more details.

Technical:

  • There is a new method added allowing you to fetch a data value type for a given index path:
public func data(for indexPath: IndexPath) -> DataTableValueType

This method can be used as a convenience method or you can use the rows property to access the multi-dimensional array manually.

Removal of cocoapods from Demo project - 2019-02-25 22:37:59

Cocoapod dependencies removed from the demo project.

Swift 4.2 support with did select and deselect delegate methods - 2019-02-24 17:44:39

Going forwards the library will support Swift 4.2 support. There's also a new did select and deselect delegate method:

    /// Fired when a cell is selected.
    ///
    /// - Parameters:
    ///   - dataTable: SwiftDataTable
    ///   - indexPath: the index path of the row selected
    @objc optional func didSelectItem(_ dataTable: SwiftDataTable, indexPath: IndexPath)

    /// Fired when a cell has been deselected
    ///
    /// - Parameters:
    ///   - dataTable: SwiftDataTable
    ///   - indexPath: the index path of the row deselected
    @objc optional func didDeselectItem(_ dataTable: SwiftDataTable, indexPath: IndexPath)

Delegate for customisation! - 2018-06-19 22:02:58

Delegate customisation!

Now all these delegate methods are available for customising your swift data table. All these methods are optionals and default values will be provided. This is not a breaking change.

These same properties are also available in the DataTableConfiguration class allowing you to provide more defaults without requiring a delegate. The delegate is useful if you want to customise dynamically. I.e. specifying different row heights for different row indexes.

/// An optional delegate for further customisation. Default values will be used retrieved from the SwiftDataTableConfiguration file. This will can be overridden and passed into the SwiftDataTable constructor incase you wish not to use the delegate. 
@objc public protocol SwiftDataTableDelegate: class {
    /// Specify custom heights for specific rows. A row height of 0 is valid and will be used.
    ///
    /// - Parameters:
    ///   - dataTable: SwiftDataTable
    ///   - index: the index of the row to specify a custom height for.
    /// - Returns: the desired height for the given row index
    @objc optional func dataTable(_ dataTable: SwiftDataTable, heightForRowAt index: Int) -> CGFloat

    /// Specify custom widths for columns. This method once implemented overrides the automatic width calculation for remaining columns and therefor widths for all columns must be given. This behaviour may change so that custom widths on a single column basis can be given with the automatic width calculation behaviour applied for the remaining columns.
    /// - Parameters:
    ///   - dataTable: SwiftDataTable
    ///   - index: the index of the column to specify the width for
    /// - Returns: the desired width for the given column index
    @objc optional func dataTable(_ dataTable: SwiftDataTable, widthForColumnAt index: Int) -> CGFloat
    
    /// Column Width scaling. If set to true and the column's total width is smaller than the content size then the width of each column will be scaled proprtionately to fill the frame of the table. Otherwise an automatic calculated width size will be used by processing the data within each column.
    /// Defaults to true.
    ///
    /// - Parameter dataTable: SwiftDataTable
    /// - Returns: whether you wish to scale to fill the frame of the table
    @objc optional func shouldContentWidthScaleToFillFrame(in dataTable: SwiftDataTable) -> Bool
    
    /// Section Header floating. If set to true headers can float and remain in view during scroll. Otherwise if set to false the header will be fixed at the top and scroll off view along with the content.
    /// Defaults to true
    ///
    /// - Parameter dataTable: SwiftDataTable
    /// - Returns: whether you wish to float section header views.
    @objc optional func shouldSectionHeadersFloat(in dataTable: SwiftDataTable) -> Bool
    
    /// Section Footer floating. If set to true footers can float and remain in view during scroll. Otherwise if set to false the footer will be fixed at the top and scroll off view along with the content.
    /// Defaults to true.
    ///
    /// - Parameter dataTable: SwiftDataTable
    /// - Returns: whether you wish to float section footer views.
    @objc optional func shouldSectionFootersFloat(in dataTable: SwiftDataTable) -> Bool
    
    
    /// Search View floating. If set to true the search view can float and remain in view during scroll. Otherwise if set to false the search view will be fixed at the top and scroll off view along with the content.
    //  Defaults to true.
    ///
    /// - Parameter dataTable: SwiftDataTable
    /// - Returns: whether you wish to float section footer views.
    @objc optional func shouldSearchHeaderFloat(in dataTable: SwiftDataTable) -> Bool
    
    /// Disable search view. Hide search view. Defaults to true.
    ///
    /// - Parameter dataTable: SwiftDataTable
    /// - Returns: whether or not the search should be hidden
    @objc optional func shouldShowSearchSection(in dataTable: SwiftDataTable) -> Bool
    
    /// The height of the section footer. Defaults to 44.
    ///
    /// - Parameter dataTable: SwiftDataTable
    /// - Returns: the height of the section footer
    @objc optional func heightForSectionFooter(in dataTable: SwiftDataTable) -> CGFloat
    
    /// The height of the section header. Defaults to 44.
    ///
    /// - Parameter dataTable: SwiftDataTable
    /// - Returns: the height of the section header
    @objc optional func heightForSectionHeader(in dataTable: SwiftDataTable) -> CGFloat
    
    
    /// The height of the search view. Defaults to 44.
    ///
    /// - Parameter dataTable: SwiftDataTable
    /// - Returns: the height of the search view
    @objc optional func heightForSearchView(in dataTable: SwiftDataTable) -> CGFloat
    
    
    /// Height of the inter row spacing. Defaults to 1.
    ///
    /// - Parameter dataTable: SwiftDataTable
    /// - Returns: the height of the inter row spacing
    @objc optional func heightOfInterRowSpacing(in dataTable: SwiftDataTable) -> CGFloat
    
    
    /// Control the display of the vertical scroll bar. Defaults to true.
    ///
    /// - Parameter dataTable: SwiftDataTable
    /// - Returns: whether or not the vertical scroll bars should be shown.
    @objc optional func shouldShowVerticalScrollBars(in dataTable: SwiftDataTable) -> Bool
    
    /// Control the display of the horizontal scroll bar. Defaults to true.
    ///
    /// - Parameter dataTable: SwiftDataTable
    /// - Returns: whether or not the horizontal scroll bars should be shown.
    @objc optional func shouldShowHorizontalScrollBars(in dataTable: SwiftDataTable) -> Bool
}

Swift 4, Speed x 300, and shouldShowFooter feature! - 2018-06-14 00:39:13

Summary:

  • Library upgraded to Swift 4,
  • Speed optimisations to return layout attributes for a given rect by a factor of 300 during scrolling!
  • A requested feature to enable the hiding of the footer labels
  • Example project updated to reflect the new visual footer hiding configuration.

Technical:

  • Example project storyboard removed in favour of a programmatic menu view controller. Makes it easier to demonstrate variations of the DataTableConfiguration object using a GenericDataTableViewController.
  • The swift language has been upgraded to swift 4 and runs on xcode 9.
  • The DataTableConfiguration object has a new property called shouldShowFooter with a default value of true. This property allows the user to override whether footers should be shown or not.
  • Refactors the layoutAttributesForRect method to use a binary search instead of filtering through all cached layouattributes. This sees a speed factory of 300 during scroll.
  • Aims to increase the prepare layout method in the SwiftDataTableLayout class by preventing unnecessary delegate calls for column widths.

- 2017-04-06 20:07:47

Implements Data Source with bug fix.

Implements DataSource - 2017-04-06 11:31:52

Data source, here we are!! Simply implement the DataTableDataSource protocol and then call the reload method on the data table, and all the views will be initialised for you 👍

Implements filtering with search bar! 🔎 - 2017-03-17 19:56:57

🔎 🔎 Implements a Search Bar for data filtering! 🔎 🔎

Summary

A search bar is automatically added to all data tables to allow the user to filter through the loaded data set without changing any code.

Technicals

  • Swift Data Tables will automatically add a search bar to the data grid.
  • The search will find occurrences in every single data item, efficiently.
  • A row will be returned in the filtering process if even one of it's data items contain the needle.
  • The default filtering algorithm uses a contains matching expression.

Trims project and min iOS deployment set to version 8.0 - 2017-03-15 00:55:03

Trims project and min iOS deployment set to version 8.0

Improved sorting algorithm - Automatically Infer the type of the data passed in! - 2017-03-13 16:10:24

Summary:

  • Improves the sorting algorithm for columns by scanning the data passed into the SwiftDataTable class and automatically infer the type of the data.
  • Changes Cell Row Representable to use A new DataTableValueType that moves away from the [[String]] row construction.

Technical:

  • original initialiser has been moved to a convenience one. users can still inject [[String]] into the SwiftDataTable class: [[String]].
  • Adds a new DataTableValueType.
  • Adds a string representation method for DataTableValueType.
  • Refactors Data Cell and Data CellViewModel to incorporate DataCellTypeValue 724a6f0
  • Adds a comparable implementation for DataTableValueType 29616b2 & c12ea98
  • Adds optional initialiser to DataTableValueType to automatically infer the right value type. f3d9d2c Improves the type detection algorithm for DataTableValueType enum b0254e8

Implements Default Order Feature - 2017-03-11 19:44:58

  • Allows a default ordering feature
  • Configuration file allows you to specify options.
  • Adds default ordering options to configuration file allowing you to specify column index and order type.

Adds scale to fill content view - 2017-03-11 16:19:44

+ Adds feature which resizes columns with weighted distribution across entire width of data table frame if the content is smaller
+ Creates new delegate method allowing the user to decide if they want the content view to automatically scale to fill to the data table frame width

+ Refactors the way content width is calculated
+ Fixes bug where Data Grid would crash if the content width was smaller than the width of the frame
+ Trims row columns to the header count specified