Nice library to show placeholders and Empty States for any UITableView/UICollectionView in your project

Overview

HGPlaceholders

Backers on Open Collective Sponsors on Open Collective CI Status Version License Language Supports Platform

Twitter: @GhazouaniHamza codebeat badge Documentation Readme Score

Example

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

Requirements

  • iOS 8.0+
  • Xcode 9.2

You also may like

  • HGCircularSlider - A custom reusable circular slider control for iOS application.
  • HGRippleRadarView - A beautiful radar view to show nearby users with ripple animation, fully customizable

Installation

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

pod 'HGPlaceholders'

HGPlaceholders is also available through Carthage. To install it, simply add the following line to your Cartfile:

github "HamzaGhazouani/HGPlaceholders"

Usage

  1. Inherit your UITableView class from TableView Or inherit UICollectionView from CollectionView
  2. Call the placeholder to show
  • tableView.showLoadingPlaceholder() or collectionView.showLoadingPlaceholder()
  • tableView.showNoResultsPlaceholder() or collectionView.showNoResultsPlaceholder()
  • tableView.showErrorPlaceholder() or collectionView.showErrorPlaceholder()
  • tableView.showNoConnectionPlaceholder() or collectionView.showNoConnectionPlaceholder()

Customization

If you want to change only images, just set them in your asset with this names (the framework check firstly in the main bundle):

  • loading : "hg_default-loading"
  • no_connection : "hg_default-no_connection"
  • no_results : "hg_default-no_results"
  • error : "hg_default-error"

The framework contains different defaults placeholders:

  • Basic :

tableView.placeholdersProvider = .basic or collectionView.placeholdersProvider = .basic

  • Default :

tableView.placeholdersProvider = .default or collectionView.placeholdersProvider = .default

  • Default2 :

tableView.placeholdersProvider = .default2 or collectionView.placeholdersProvider = .default2

  • Hallowen :

tableView.placeholdersProvider = .halloween or collectionView.placeholdersProvider = .halloween // for fun :)`

If you want to change the default palceholders for all table views in your project:

class ProjectNameTableView: TableView {

    override func customSetup() {
        placeholdersProvider = .basic
    }
}
class ProjectNameCollectionView: CollectionView {

    override func customSetup() {
        placeholdersProvider = .basic
    }
}

You can also add new placeholders fully customizable, you should keep in mind that the view will take table view frame, and placeholder can have only one action, please check the example project

Creating a new theme from scratch

static var summer: PlaceholdersProvider {
        
        var commonStyle = PlaceholderStyle()
        commonStyle.backgroundColor = UIColor(red: 1.0, green: 236.0/255, blue: 209.0/255.0, alpha: 1.0)
        commonStyle.actionBackgroundColor = .black
        commonStyle.actionTitleColor = .white
        commonStyle.titleColor = .black
        commonStyle.isAnimated = false
        
        commonStyle.titleFont = UIFont(name: "AvenirNextCondensed-HeavyItalic", size: 19)!
        commonStyle.subtitleFont = UIFont(name: "AvenirNextCondensed-Italic", size: 19)!
        commonStyle.actionTitleFont = UIFont(name: "AvenirNextCondensed-Heavy", size: 19)!
        
        var loadingStyle = commonStyle
        loadingStyle.actionBackgroundColor = .clear
        loadingStyle.actionTitleColor = .gray
        
        var loadingData: PlaceholderData = .loading
        loadingData.image = #imageLiteral(resourceName: "summer-hat")
        let loading = Placeholder(data: loadingData, style: loadingStyle, key: .loadingKey)
        
        var errorData: PlaceholderData = .error
        errorData.image = #imageLiteral(resourceName: "summer-ball")
        let error = Placeholder(data: errorData, style: commonStyle, key: .errorKey)
        
        var noResultsData: PlaceholderData = .noResults
        noResultsData.image = #imageLiteral(resourceName: "summer-cocktail")
        let noResults = Placeholder(data: noResultsData, style: commonStyle, key: .noResultsKey)
        
        var noConnectionData: PlaceholderData = .noConnection
        noConnectionData.image = #imageLiteral(resourceName: "summer-beach-slippers")
        let noConnection = Placeholder(data: noConnectionData, style: commonStyle, key: .noConnectionKey)
        
        let placeholdersProvider = PlaceholdersProvider(loading: loading, error: error, noResults: noResults, noConnection: noConnection)
        
        let xibPlaceholder = Placeholder(cellIdentifier: "CustomPlaceholderCell", key: PlaceholderKey.custom(key: "XIB"))
        
        placeholdersProvider.add(placeholders: xibPlaceholder)
        
        return placeholdersProvider
    }

Adding a custom placeholder to an existing theme

   private static var starWarsPlaceholder: Placeholder {
       var starwarsStyle = PlaceholderStyle()
       starwarsStyle.backgroundColor = .black
       starwarsStyle.actionBackgroundColor = .clear
       starwarsStyle.actionTitleColor = .white
       starwarsStyle.titleColor = .white
       starwarsStyle.isAnimated = false
       
       var starwarsData = PlaceholderData()
       starwarsData.title = NSLocalizedString("\"This is a new day, a\nnew beginning\"", comment: "")
       starwarsData.subtitle = NSLocalizedString("Star Wars", comment: "")
       starwarsData.image = #imageLiteral(resourceName: "star_wars")
       starwarsData.action = NSLocalizedString("OK!", comment: "")
       
       let placeholder = Placeholder(data: starwarsData, style: starwarsStyle, key: PlaceholderKey.custom(key: "starWars"))
       
       return placeholder
   }
   
   let provider = PlaceholdersProvider.summer 
   provider.addPlaceholders(MyUtilityClass.starWarsPlaceholder) 

Documentation

Full documentation is available on CocoaDocs.
You can also install documentation locally using jazzy.

Author

Hamza Ghazouani, [email protected]

License

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

Comments
  • How do I change placeholder's title and subtitle when I am calling showNoConnectionPlaceholder() and others?

    How do I change placeholder's title and subtitle when I am calling showNoConnectionPlaceholder() and others?

    I have a simple question, sorry for being a ios newbie.

    How do I change the title and sub title wording as I am displaying the placeholders?

    I found out that the wordings are in PlaceholderData.swift, in public struct PlaceholderData.

    Lets say I do not wish to hard code them here, but set it to something when I am calling tableView.showNoConnectionPlaceholder(), how do I do it?

    I also found the file PlaceholdersProvider.swift, which I set it to be :

    var noConnectionData: PlaceholderData = .noConnection
            noConnectionData.image = #imageLiteral(resourceName: "hg_default-error")
            noConnectionData.title = "Testing no connection title"
            noConnectionData.subtitle = "Testing no connection sub title"
            let noConnection = Placeholder(data: noConnectionData, style: commonStyle, key: .noConnectionKey)
    

    But the message is still the same

    How do I do it?

    Thanks

    question 
    opened by junweimah 12
  • Crash on iOS 9+ when used within UICollectionView

    Crash on iOS 9+ when used within UICollectionView

    Hi @HamzaGhazouani,

    Good job on this awesome library! I love it!

    I have noticed that a crash occurs on iOS 9.x (tested on iOS 9.3.5) if you use HGPlaceholders for a UICollectionView that has a header and/or footer. You can reproduce this issue by simply running your latest Example project (that you have pushed ~2 hours ago).

    The issue is related to not updating the defaultLayout with the proper layout after the dataSource changes.

    Could you please take a look?

    Also, I think it is also wise to declare the PlaceholderCollectionViewCell as open, since this is already the case for PlaceholderTableViewCell. I think most devs would like to subclass it eventually.

    Looking forward to your feedback. Keep up the good work!

    Cheers, Sasho

    bug 
    opened by sasojadrovski 12
  • Action button is not visible, but tapping on the white space is printing logs.

    Action button is not visible, but tapping on the white space is printing logs.

    Hi,

    I played around the example project and found that the placeholder has a button "try again", and user can tap that.

    However in my project, there is no action button, but I can tap on the white space below the subtitle and the log is printing "Placeholder action button tapped"

    How and where do I set the action button to visible?

    Thanks

    question 
    opened by junweimah 9
  • Crashing on changing orientation while UISearchController is active

    Crashing on changing orientation while UISearchController is active

    Hi, I tried using your library, it's looking very nice, but has a little problem when changing the device orientation while the navigationItem.searchController.isActive = true. This is the error I'm getting in the console:

    *** Assertion failure in -[HGPlaceholders.TableView _classicHeightForRowAtIndexPath:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKitCore/UIKit-3698.84.16/UITableView.m:15329
    *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid row height provided by table delegate. Value must be at least 0.0, or UITableViewAutomaticDimension.'
    

    After some debugging I'v noticed that the hight from the delegate is -119: image So I tried the most obvious thing, I'v added tableViewHeight = tableViewHeight >= 0.0 ? tableViewHeight : UITableView.automaticDimension before the method return (line 154), but guess what? Somehow the value is still -119 😓 So I thought maybe the UITableView.automaticDimension is also returning -119? so let's try just tableViewHeight = 0. No, it didn't worked, tableViewHeight was still -119. 😧

    Hope you'll be able to reproduce and detect how to solve this problem. I didn't understand yet how is that possible to change the value by this way (tableViewHeight = 0) and it won't change, like this line doesn't exists. 😨

    Thanks, Ido.

    bug to investigate 
    opened by Idomo 8
  • [Suggestion] The placeholders should not disable the scrolling functionality?

    [Suggestion] The placeholders should not disable the scrolling functionality?

    Hi @HamzaGhazouani,

    I was thinking whether it would be nice to have the option to choose whether the placeholders should disable the scrolling functionalities of UITableViews and UICollectionViews.

    One good example why I think that sometimes we need to have that one enabled is let's say you want to check for new data by triggering a pull to refresh action. Currently, if an empty state is visible, there is no way you can trigger this action, since the scrolling is disabled.

    What are your thoughts on this?

    Best regards, Sasho

    feature proposal discussion 
    opened by sasojadrovski 8
  • Placeholders not showing

    Placeholders not showing

    Hey I'm writing the follow code on my tableView

    ` import UIKit import HGPlaceholders

    class SentMemesTVC: UITableViewController{

    var placeholderTableView: TableView?
    
    var memes = [Meme]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.clearsSelectionOnViewWillAppear = false
        
        reloadTable()
      
        NotificationCenter.default.addObserver(self, selector: #selector(reloadTable), name: NSNotification.Name(rawValue: NOTIF_RELOAD_TABLE), object: nil)
        
        
        
        placeholderTableView = tableView as? TableView
        placeholderTableView?.placeholderDelegate = self as PlaceholderDelegate
        
        
        placeholderTableView?.placeholdersProvider = .basic
        placeholderTableView?.showErrorPlaceholder()
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == TO_MEME_EDITOR{
            if let memeEditor = segue.destination as? MemeMainVC{
                if let meme = sender as? Meme{
                    memeEditor.meme = meme
                }
            }
        }
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return memes.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: "MemeTableCell", for: indexPath) as? MemeTableCell{
            let memeCell = memes[indexPath.row]
            cell.configureCell(meme: memeCell)
            return cell
        }
        return UITableViewCell()
    }
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let meme: Meme = memes[indexPath.row]
        performSegue(withIdentifier: TO_MEME_EDITOR, sender: meme)
    }
    
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 114
    }
    
    @objc func reloadTable(){
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        memes = appDelegate.memes
        self.tableView.reloadData()
    }
    
    @IBAction func toMemeEditor(_ sender: Any){
        performSegue(withIdentifier: TO_MEME_EDITOR, sender: nil)
    }
    

    }

    extension SentMemesTVC: PlaceholderDelegate {

    func view(_ view: Any, actionButtonTappedFor placeholder: Placeholder) {
        print(placeholder.key.value)
        placeholderTableView?.showDefault()
    }
    

    }

    `

    but nothing is happening

    question 
    opened by andrecrimb 7
  • Archiving project fails when using HGPlaceholders as a Pod

    Archiving project fails when using HGPlaceholders as a Pod

    Hey @HamzaGhazouani,

    I have discovered that if you try to archive the project for distribution (AdHoc), and at the same time you have added and are using this library as a Pod, the archiving fails with an error:

    Symbol(s) not found for architecture arm64

    I have also verified that this is not a case when the library is added to the project manually.

    Please take a look and if you need some additional info, please let me know.

    Cheers, Sasho

    cocoapods 
    opened by sasojadrovski 5
  • 'Placeholder' is ambiguous for type lookup in this context

    'Placeholder' is ambiguous for type lookup in this context

    'The type Method is declared in two imported modules. You have to specify the module from which to use the type. Use Alamofire.Method instead of Method' in one stackoverflow answer. I cannot related struct Placeholder with HGPlaceholders. I also use Kingfisher library which has Placeholder struct in it.

    Loved your library, keep going!

    opened by BatyrOvezdurdyyev 4
  • Could not cast value of type 'UITableView' to 'HGPlaceholders.TableView'

    Could not cast value of type 'UITableView' to 'HGPlaceholders.TableView'

    The cast for me does not work: The error appears here:

    placeholderTableView = notificationTableView as! TableView

    I am not using a UITableViewController, but just a UITableview in a UIViewController.

    I follow the demo project and create the placeholderTableView as my UITableView (notificationTableView) as TableView. Force Cast creates the following issue: Could not cast value of type 'UITableView' to 'HGPlaceholders.TableView'

    Optional cast with ? does not do anything.

    question 
    opened by magicmikek 4
  • use adjustedContentInset instead of contentInset for iOS 11 and later

    use adjustedContentInset instead of contentInset for iOS 11 and later

    opened by jamchen 3
  • UITableView header/footer views are not preserved if set programmatically

    UITableView header/footer views are not preserved if set programmatically

    Hey @HamzaGhazouani,

    I have also discovered that if you have let's say a footer added to the UITableView (one common example is adding a blank UIView inside viewDidLoad (e.g. tableView.tableFooterView = UIView() to the table view's footer view in order to remove the separators if there are only 1 or 2 rows in the table view) which has been added programmatically in viewDidLoad for example, for some reason, the footer view is removed and set to nil.

    This is not the case if you have added it via Storyboard.

    Could you please take a look?

    Cheers, Sasho

    bug enhancement 
    opened by sasojadrovski 3
  • Doesn't work at all (StripNIB issue)

    Doesn't work at all (StripNIB issue)

    https://github.com/marcosgriselli/Sizes/issues/25 I have the same issue but with this pod. Here is an example how did they fix that: https://github.com/marcosgriselli/Sizes/pull/31/commits/ab7105a6a6b98ccfd8e11ec5f561d4f658fdab95

    opened by gerchicov-bp 0
  • How do I set the dynamic title and subtitle which is received from server api.

    How do I set the dynamic title and subtitle which is received from server api.

    Hi @HamzaGhazouani

    Thanks for the great library. I had one question that how do I set the dynamic title and subtitle which is received from server api? Please help me with this.

    opened by hardikamal 1
  • HGPlaceholder + Custom collection view layout == ?

    HGPlaceholder + Custom collection view layout == ?

    When i use your library on UICollection view with custom layout, after removing all items, i got crash here: override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { return cache[indexPath.item] } But, on method prepare, i always clean my cache.

    Helps only invalidation collection view layout after reloadData()

    to investigate 
    opened by semen-sequenia 0
Releases(0.3.0)
  • 0.3.0(Jan 5, 2018)

    Add more properties for customization: titleFont, subtitleFont and actionTitleFont Add the property placeholdersAlwaysBounceVertical to allow/disable vertical bouncing when the placeholder is shown Start supporting iOS 8 Add ability to show/Hide tableHeader & tableFooter when the placeholders are shown Use adjustedContentInset instead of contentInset for iOS 11 and later (compatibility iPhone X)

    Source code(tar.gz)
    Source code(zip)
Owner
Hamza Ghazouani
Hamza Ghazouani
WLEmptyState is an iOS based component that lets you customize the view when the dataset of a UITableView or a UICollectionView is empty.

Table of Content Overview Running an Example Project Installing WLEmptyState Configuring WLEmptyState Using WLEmptyState Customizing WLEmptyState Cont

Wizeline 315 Dec 5, 2022
ListPlaceholder is a swift library allows you to easily add facebook style animated loading placeholder to your tableviews or collection views.

ListPlaceholder ListPlaceholder Facebook news feed style animation Features ListPlaceholder is a swift library allows you to easily add facebook style

Moayad Al Kouz 628 Dec 19, 2022
PJFDataSource is a small library that provides a simple, clean architecture for your app to manage its data sources while providing a consistent user interface for common content states (i.e. loading, loaded, empty, and error).

PJFDataSource PJFDataSource is a small library that provides a simple, clean architecture for your app to manage its data sources while providing a co

Square 88 Jun 30, 2022
A drop-in UITableView/UICollectionView superclass category for showing empty datasets whenever the view has no content to display

DZNEmptyDataSet Projects using this library Add your project to the list here and provide a (320px wide) render of the result. The Empty Data Set Patt

Ignacio Romero Zurbuchen 12.1k Jan 8, 2023
WLEmptyState is an iOS based component that lets you customize the view when the dataset of a UITableView or a UICollectionView is empty.

Table of Content Overview Running an Example Project Installing WLEmptyState Configuring WLEmptyState Using WLEmptyState Customizing WLEmptyState Cont

Wizeline 315 Dec 5, 2022
Placeholder views based on content, loading, error or empty states

StatefulViewController A protocol to enable UIViewControllers or UIViews to present placeholder views based on content, loading, error or empty states

Alexander Schuch 2.1k Dec 8, 2022
A UIControl subclass that makes it easy to create empty states.

AZEmptyState Making empty state simple. Screenshots Installation Cocoa Pods: pod 'AZEmptyState' Manual: Simply drag and drop the Sources folder to you

Antonio Zaitoun 88 Oct 2, 2022
Placeholder views based on content, loading, error or empty states

StatefulViewController A protocol to enable UIViewControllers or UIViews to present placeholder views based on content, loading, error or empty states

Alexander Schuch 2.1k Dec 8, 2022
Swiftui-pressed-states-example - Examples of Pressed States in SwiftUI

Examples of Pressed States in SwiftUI pressed-states.mp4

Philip Davis 6 Nov 15, 2022
Mahmoud-Abdelwahab 5 Nov 23, 2022
Carbon🚴 A declarative library for building component-based user interfaces in UITableView and UICollectionView.

A declarative library for building component-based user interfaces in UITableView and UICollectionView. Declarative Component-Based Non-Destructive Pr

Ryo Aoyama 1.2k Jan 5, 2023
🚴 A declarative library for building component-based user interfaces in UITableView and UICollectionView.

A declarative library for building component-based user interfaces in UITableView and UICollectionView. Declarative Component-Based Non-Destructive Pr

Ryo Aoyama 1.2k Jan 5, 2023
NiceAlertView is a Swift framework that can increase time of development and show nice custom AlertsViews

NiceAlertView Nice and beautiful AlertView for your iOS project NiceAlertView is a Swift framework that can increase time of development and show nice

Daniel Beltrami 0 Nov 24, 2021
A Swift package that provides convenient Lorem Ipsum text, images, colors and other placeholders for rapidly prototyping, building and testing your iOS applications.

Lorem Introducing Lorem, a placeholder generator library for iOS to help you rapidly prototype, build and test your iOS applications. By leveraging Sw

Thirdfort Limited 10 Dec 5, 2022
HoverConversion realized vertical paging with UITableView. UIViewController will be paged when reaching top or bottom of UITableView contentOffset.

HoverConversion ManiacDev.com referred. https://maniacdev.com/2016/09/hoverconversion-a-swift-ui-component-for-navigating-between-multiple-table-views

Taiki Suzuki 166 Feb 1, 2022
An iOS drop-in UITableView, UICollectionView and UIScrollView superclass category for showing a customizable floating button on top of it.

MEVFloatingButton An iOS drop-in UITableView, UICollectionView, UIScrollView superclass category for showing a customizable floating button on top of

Manuel Escrig 298 Jul 17, 2022
Automates prefetching of content in UITableView and UICollectionView

Automates preheating (prefetching) of content in UITableView and UICollectionView. Deprecated on iOS 10. This library is similar to UITableViewDataSou

Alexander Grebenyuk 633 Sep 16, 2022
Netflix and App Store like UITableView with UICollectionView, written in pure Swift 4.2

GLTableCollectionView Branch Status master develop What it is GLTableCollectionView is a ready to use UITableViewController with a UICollectionView fo

Giulio 708 Nov 17, 2022
Incremental update tool to UITableView and UICollectionView

EditDistance is one of the incremental update tool for UITableView and UICollectionView. The followings show how this library update UI. They generate

Kazuhiro Hayashi 90 Jun 9, 2022
A generic stretchy header for UITableView and UICollectionView

GSKStretchyHeaderView, by gskbyte GSKStretchyHeaderView is an implementation of the stretchy header paradigm as seen on many apps, like Twitter, Spoti

Jose Alcalá Correa 1.7k Dec 30, 2022