Code Monkey home page Code Monkey logo

lbtatools's Introduction

Version License Platform

The cure for boring UI code

Do you suffer from ugly layout code and boring UICollectionViewController boilerplate code? Yes, we've all been there. I'm not the only one that has written monstrous view setup functions that look like beasts from hell.

Now, there is a solution to this problem: LBTATools.

There are 3 main issues I want to tackle with this library:

  1. Use UIStackView to layout everything in a single line.
  2. Create quick vertical and horizontal lists, but skip the boring cell registration, numItemsForSection, cellForItemAt code.
  3. Generate a UILabel, UIButton, UIView, etc.. with one line of code.

This library contains extensions and classes that speed up development for my client work. Hopefully, you can take advantage of some of these techniques.

1. Stack vertically and horizontally

Layouts can usually be broken down into some combination of horizontal and vertical UIStackViews. The following examples illustrate usage of stack and hstack for common layout patterns.

Example 1: Simple Vertical Layout

Example Layout 1

stack(imageView, nameLabel)
Example 2: Horizontal then vertical with center alignment

Example Layout 2

hstack(imageView,
       stack(nameLabel, messageLabel, spacing: 4),
       spacing: 16, alignment: .center)
// The key is to use stackView.alignment = .center   
Example 3: Embedded stacking with layoutMargins.

Example Layout 3

stack(imageView,
      stack(titleLabel, 
      	    descriptionLabel, 
      	    UIView(), 
      	    exploreLabel, spacing: 16)).withMargins(.allSides(16)
// Using stackView.layoutMargins allows for easy padding manipulation

2. Fast and Easy ListController

Writing iOS apps will almost always involve lists, lots and lots of lists. Most of these will be vertical but horizontal ones are quite common too. Only works for single cell type lists.

Tinder Messages List Example

Tinder Messages List


Using LBTAListController, you can build this common pattern with just a few lines. First, let's simplify the view into one vertical list and a header that contains a horizontal list:

Simplified List Header View

Building this list is very easy now:

class GreenCell: LBTAListCell<UIColor> {
    override var item: UIColor! { didSet { backgroundColor = item }}
}

class SimpleListController: LBTAListController<GreenCell, UIColor, SimpleHeader> {
    override func viewDidLoad() {
        super.viewDidLoad()
        items = [.green, .green, .green, .green]
    }
    // sizing methods
}

The header also contains a ListController component:

class SimpleHeader: UICollectionReusableView {
    
    class BlueCell: LBTAListCell<UIColor> {
        override var item: UIColor! { didSet { backgroundColor = item }}
    }
    class HeaderHorizontalController: LBTAListController<BlueCell,
        UIColor> {
        override func viewDidLoad() {
            super.viewDidLoad()
            items = [.blue, .blue, .blue, .blue]
        }
    }
    
    let blueCellsHorizontalController = HeaderHorizontalController(scrollDirection: .horizontal)
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        stack(blueCellsHorizontalController.view)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError()
    }
}

Run the example project in this repository to see the code in its entirety. LBTAListController uses the power of Generics to handle dynamics cell and header classes.

3. One line UI elements

One major issue with creating UI elements is the amount of properties we have to set during the setup phase. Here's a very common, and ugly, chunk of code that we want to avoid:

let nameLabel: UILabel = {
    let label = UILabel()
    label.text = "Name"
    label.textColor = .black
    label.textAlignment = .center
    label.font = .boldSystemFont(ofSize: 16)
    label.numberOfLines = 2
    return label
}()

In total, this is 9 lines of code and gets out of control when creating multiple labels, buttons, etc. So instead, let's make this simple and elegant with one line:

let nameLabel = UILabel(text: "Name", font: .boldSystemFont(ofSize: 16), textColor: .black, 
	textAlignment: .center, numberOfLines: 2)

All of the above parameters are optional, this means you can also use:

let nameLabel = UILabel(text: "Name", numberOfLines: 2)

Creating UIButtons also fall into this category of code from hell, so let's make it easy with another one-liner:

let nextButton = UIButton(title: "Next", titleColor: .black, font: .boldSystemFont(ofSize: 18), 
	backgroundColor: .white, target: self, action: #selector(handleNext))

Video Tutorials

Although this library is very easy to use, I recognize that a lot of you want some visual examples so below are some video tutorials:

Using stack and hstack

Installation

Cocoapods

CocoaPods is an easy to use dependency manager . To install LBTATools, simply add the following line to your Podfile:

pod 'LBTATools'

Swift Package Manager with Xcode 11

Follow this doc

Author

Brian Voong @buildthatapp YouTube

License

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

lbtatools's People

Contributors

artemmartus avatar bhlvoong avatar michaelversus avatar sereisoglu avatar weitieda avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lbtatools's Issues

outdated podspec - still pointing to 1.0.12

pod install won't get latest (even when pointing to github with tag 1.0.17)

s.version          = '1.0.12
s.source           = { :git => 'https://github.com/bhlvoong/LBTATools.git', :tag => s.version.to_s }

can you update LBTATools.podspec please?

Underlined textfield

Hi,

First of all thank you for this lib !

Just wanted to know if UITextfield could be underlined in your form controller ?
I used the function below in some projects and it was working fine but as soon as it's embedded in the FormController stack, there is not underline anymore.

extension UITextField {
	func underlined(){
		let border = CALayer()
		let lineWidth = CGFloat(1)
		border.borderColor = UIColor.black.cgColor
		border.frame = CGRect(x: 0, y: self.frame.size.height - lineWidth, width:  self.frame.size.width, height: self.frame.size.height)
		border.borderWidth = lineWidth
		self.layer.addSublayer(border)
		self.layer.masksToBounds = true
	}
}

Here is the setup, I removed some fields, buttons and stuff in the description below easier to see for you I guess:

[name, address1 ...].forEach(applyTextFieldStyle)
formContainerStackView.stack(name, nameError, ...), spacing: 8).withMargins(.init(top: 16, left: 8, bottom: 16, right: 8))

Here is the function to setup my textfields:

	private func applyTextFieldStyle(textfield: UITextField) {
		textfield.constrainHeight(40)
		textfield.delegate = self
		textfield.textColor = .black
		textfield.backgroundColor = .clear
		textfield.font = .systemFont(ofSize: 13)
		textfield.underlined()
	}

Would be really nice if someone could find my miss in there, I'm stuck on that and I'd really love to use this lib.

Regards

UIView anchor isActive option

Was wondering about possibly modifying the anchor method to have an additional property at the end. Add in a isActive: Bool = true. That way we can make multiple sets of constraints and activate and deactivate as needed.

Example would be a set of default constraints and a set of constraints for Accessibility text sizes.

Like this:

    @discardableResult
    open func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero, isActive: Bool = true) -> AnchoredConstraints {
        
        translatesAutoresizingMaskIntoConstraints = false
        var anchoredConstraints = AnchoredConstraints()
        
        if let top = top {
            anchoredConstraints.top = topAnchor.constraint(equalTo: top, constant: padding.top)
        }
        
        if let leading = leading {
            anchoredConstraints.leading = leadingAnchor.constraint(equalTo: leading, constant: padding.left)
        }
        
        if let bottom = bottom {
            anchoredConstraints.bottom = bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom)
        }
        
        if let trailing = trailing {
            anchoredConstraints.trailing = trailingAnchor.constraint(equalTo: trailing, constant: -padding.right)
        }
        
        if size.width != 0 {
            anchoredConstraints.width = widthAnchor.constraint(equalToConstant: size.width)
        }
        
        if size.height != 0 {
            anchoredConstraints.height = heightAnchor.constraint(equalToConstant: size.height)
        }
        
        [anchoredConstraints.top, anchoredConstraints.leading, anchoredConstraints.bottom, anchoredConstraints.trailing, anchoredConstraints.width, anchoredConstraints.height].forEach{ $0?.isActive = isActive }
        
        return anchoredConstraints
    }

issue with target iOS 13 Xcode 11.4

I just installed the pod on a project targeting iOS 13 and received the following error. XCode 11.4

'shared' is unavailable in application extensions for iOS: Use view controller based solutions where appropriate instead.

LBTAFormController.swift
@objc fileprivate func handleKeyboardShow(notification: Notification) {
...

   if alignment == .center {
            scrollView.contentInset.bottom += UIApplication.shared.statusBarFrame.height
   }
...
}

how to add button inside the cell with index path.item

hi...
thanks a lot for your efforts you are great man ...
i saw all your video in youtube ..

really I have two question

  1. I add button for cell but how can addtarget according the indexpath.item to do my func..

  2. can you tell us if we can swap between views lick your youtube app and put in the top tow button to swap between it..

LBTAListHeaderController keep giving fatalError

I follow the instruction running the basic LBTAListController<MessageCell,UIColor> but keep getting

required public init?(coder aDecoder:NSCoder) {
fatalError()
}
Thread 1: Fatal Error

under the LBListHeaderController class pod file

Multiple custom cells

How can I create multiple custom cells type in single UICollectionViewController using LBTATools ?

like this :
Screenshot 2023-03-04 at 17 04 00

Problem with Pod Installation

@bhlvoong

This problem show only I use my real device

Hi I'm trying to insert LBTA Tools using the pod 'LBTATools'

As soon as the pod is installed and I start my app, my app crashes with this error .. where am I wrong?

this is the error

dyld: Library not loaded: @rpath/LBTATools.framework/LBTATools
Referenced from: /private/var/containers/Bundle/Application/5A3136F6-7A0B-4FFC-8080-49A73122A0D2//
Reason: no suitable image found. Did find:
/private/var/containers/Bundle/Application/5A3136F6-7A0B-4FFC-8080-49A73122A0D2//Frameworks/LBTATools.framework/LBTATools: code signature invalid for '/private/var/containers/Bundle/Application/5A3136F6-7A0B-4FFC-8080-49A73122A0D2//Frameworks/LBTATools.framework/LBTATools'

/private/var/containers/Bundle/Application/5A3136F6-7A0B-4FFC-8080-49A73122A0D2//Frameworks/LBTATools.framework/LBTATools: stat() failed with errno=25
/private/var/containers/Bundle/Application/5A3136F6-7A0B-4FFC-8080-49A73122A0D2//Frameworks/LBTATools.framework/LBTATools: code signature invalid for '/private/var/containers/Bundle/Application/5A3136F6-7A0B-4FFC-8080-49A73122A0D2//Frameworks/LBTATools.framework/LBTATools'

/private/var/containers/Bundle/Application/5A3136F6-7A0B-4FFC-8080-49A73122A0D2//Frameworks/LBTATools.framework/LBTATools: stat() failed with errno=1
/private/var/containers/Bundle/Application/5A3136F6-7A0B-4FFC-8080-49A73122A0D2//Frameworks/LBTATools.framework/LBTATools: code signature invalid for '/private/var/containers/Bundle/Application/5A3136F6-7A0B-4FFC-8080-49A73122A0D2//Frameworks/LBTATools.framework/LBTATools'

/private/var/containers/Bundle/Application/5A3136F6-7A0B-4FFC-8080-49A73122A0D2//Frameworks/LBTATools.framework/LBTATools: stat() failed with errno=1

Animation within stacks

Dear Brian,

first of all thanks for these tools! They are quite awesome and give swift a bit of a swiftui touch :) I started using stacks and was wondering if it possible to change the width or height of elements within the stack using an animation. I tried it but I guess this does not play with all the constraints. Can you tell me if it is possible and if so, how? Thanks for the help and keep up the good work!

pod 'LBTATools' doesn't add all the files

I've added pod 'LBTATools' in my Podfile. But it only adds following files :

Screenshot 2019-05-21 at 12 10 10 PM

Many extensions and other files are missing.

I'm using LBTAToolsVersionNumber: 1.0

and while pod install it was showing Installing LBTATools (0.1.4)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.