Coder Social home page Coder Social logo

mikewlange / stevia Goto Github PK

View Code? Open in Web Editor NEW

This project forked from freshos/stevia

0.0 2.0 0.0 20.54 MB

:leaves: Elegant view layout for iOS

License: MIT License

Objective-C 12.49% Swift 75.80% Ruby 0.47% C 0.06% Makefile 11.14% Shell 0.03%

stevia's Introduction

Stevia

Stevia

Language: Swift2 and 3 Platform: iOS 8+ Carthage compatible CocoaPods compatible Build Status Join the chat at https://gitter.im/s4cha/Stevia License: MIT Release version

Reason - Example - Live Reload - Installation - Documentation

Visual Layout Api

layout(
    100,
    |-email-| ~ 80,
    8,
    |-password-forgot-| ~ 80,
    >=20,
    |login| ~ 80,
    0
)

Chainable Api

email.top(100).left(8).right(8).width(200).height(44)
alignHorizontally(password, forgot)
image.fillContainer()
button.centerInContainer().size(50%)
equalWidths(email, password)
image.width(>=80)

Equation-Based Api

email.Top == 100
password.CenterY == forgot.CenterY
login.Top >= password.Bottom + 20
login.Width == 75 % Width

All Generate native NSLayoutConstraints ๐ŸŽ‰

Try it!

Stevia is part of freshOS iOS toolset. Try it in an example App ! Download Starter Project

Reason

Why

Because nothing holds more truth than pure code ๐Ÿค“
Xibs and storyboards are heavy, hard to maintain, hard to merge.
They split the view concept into 2 separate files making debugging a nightmare
There must be a better way

How

By creating a tool that makes Auto layout code finally readable by a human being.
By coupling it with live code injection such as injectionForXcode we can design views in real time
View layout becomes fun, concise, maintainable and dare I say, beautiful โค๏ธ

What

  • Auto Layout DSL
  • Pure Swift
  • Simple, this is just NSLayoutConstraint shortcuts, pure UIKit code, no voodoo magic
  • Chainable api

Advantages of Stevia

  • No more constraints hell in Interface builder.
  • No more debugging in Interface builder toggling checkboxes.
  • The view code is not split between 2 files anymore
  • What you see is what you get, your view code is in one place, there is no hidden logic elsewere (in the xib)
  • No more referencing Storyboards or Xibs by their names "ProfileStoryboard". We all know strings are bad identifiers.
  • Clear view Hierarchy
  • Live reload, WHAT YOU SEE IS WHAT YOU GET
  • Events are a breeze
  • Code views Faster
  • No more XML (Thank God!)
  • Better readability 1000lines XML file vs. 30lines code
  • Readable constraints (they actually look like the layout itself \o/)
  • Horizontal & vertical layout can be described at the same time
  • Styles are well separated, concise, reusable and can be composed
  • Content like text, placeholders are easier to visualize

Login View Example

alt text

Before (Native Autolayout)

class LoginViewNative:UIView {

    let email = UITextField()
    let password = UITextField()
    let login = UIButton()

    convenience init() {
        self.init(frame:CGRect.zero)
        backgroundColor = .whiteColor()

        addSubview(email)
        addSubview(password)
        addSubview(login)

        email.translatesAutoresizingMaskIntoConstraints = false
        password.translatesAutoresizingMaskIntoConstraints = false
        login.translatesAutoresizingMaskIntoConstraints = false

        addConstraint(NSLayoutConstraint(
                item: email,
                attribute: .Left,
                relatedBy: .Equal,
                toItem: self,
                attribute: .Left,
                multiplier: 1,
                constant: 8)
        )
        addConstraint(NSLayoutConstraint(
                item: email,
                attribute: .Right,
                relatedBy: .Equal,
                toItem: self,
                attribute: .Right,
                multiplier: 1,
                constant: -8)
        )
        addConstraint(NSLayoutConstraint(
            item: password,
            attribute: .Left,
                relatedBy: .Equal,
                toItem: self,
                attribute: .Left,
                multiplier: 1,
                constant: 8)
        )
        addConstraint(NSLayoutConstraint(
            item: password,
            attribute: .Right,
            relatedBy: .Equal,
            toItem: self,
            attribute: .Right,
            multiplier: 1,
            constant: -8)
        )
        addConstraint(NSLayoutConstraint(
            item: login,
            attribute: .Left,
            relatedBy: .Equal,
            toItem: self,
            attribute: .Left,
            multiplier: 1,
            constant: 0)
        )
        addConstraint(NSLayoutConstraint(
            item: login,
            attribute: .Right,
            relatedBy: .Equal,
            toItem: self,
            attribute: .Right,
            multiplier: 1,
            constant: 0)
        )
        for b in [email, password, login] {
            addConstraint(NSLayoutConstraint(
                item: b,
                attribute: .Height,
                relatedBy: .Equal,
                toItem: nil,
                attribute: .NotAnAttribute,
                multiplier: 1,
                constant: 80)
            )
        }
        addConstraint(NSLayoutConstraint(
            item: email,
            attribute: .Top,
            relatedBy: .Equal,
            toItem: self,
            attribute: .Top,
            multiplier: 1,
            constant: 100)
        )
        addConstraint(NSLayoutConstraint(
            item:email,
            attribute: .Bottom,
            relatedBy: .Equal,
            toItem: password,
            attribute: .Top,
            multiplier: 1,
            constant: -8)
        )
        addConstraint(NSLayoutConstraint(
            item: login,
            attribute: .Bottom,
            relatedBy: .Equal,
            toItem: self,
            attribute: .Bottom,
            multiplier: 1,
            constant: 0)
        )

        email.placeholder = "Email"
        email.borderStyle = .RoundedRect
        email.autocorrectionType = .No
        email.keyboardType = .EmailAddress
        email.font = UIFont(name: "HelveticaNeue-Light", size: 26)
        email.returnKeyType = .Next

        password.placeholder = "Password"
        password.borderStyle = .RoundedRect
        password.font = UIFont(name: "HelveticaNeue-Light", size: 26)
        password.secureTextEntry = true
        password.returnKeyType = .Done

        login.setTitle("Login", forState: .Normal)
        login.backgroundColor = .lightGrayColor()
        login.addTarget(self, action: "loginTapped", forControlEvents: .TouchUpInside)
        login.setTitle(NSLocalizedString("Login", comment: ""), forState: .Normal)
    }

    func loginTapped() {
        //Do something
    }
}

With Stevia ๐Ÿƒ

class LoginViewStevia:UIView {

    let email = UITextField()
    let password = UITextField()
    let login = UIButton()

    convenience init() {
        self.init(frame:CGRect.zero)
        backgroundColor = .whiteColor()

        sv(
            email.placeholder("Email").style(fieldStyle), //.style(emailFieldStyle),
            password.placeholder("Password").style(fieldStyle).style(passwordFieldStyle),
            login.text("Login").style(buttonStyle).tap(loginTapped)
        )

        layout(
            100,
            |-email-| ~ 80,
            8,
            |-password-| ~ 80,
            "",
            |login| ~ 80,
            0
        )
    }

    func fieldStyle(f:UITextField) {
        f.borderStyle = .RoundedRect
        f.font = UIFont(name: "HelveticaNeue-Light", size: 26)
        f.returnKeyType = .Next
    }

    func passwordFieldStyle(f:UITextField) {
        f.secureTextEntry = true
        f.returnKeyType = .Done
    }

    func buttonStyle(b:UIButton) {
        b.backgroundColor = .lightGrayColor()
    }

    func loginTapped() {
        //Do something
    }
}

Number of lines From 144 -> 57 ( ~ divided by 2.5)
Number of characters From 4231 -> 1338 ( ~ divided by 3)

Write 3 times less code that is actually 10X more expressive and maintainable <3

Live Reload

You can even enable LiveReload during your development phase! ๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰

Stevia + InjectionForXcode = <3 (WhoNeedsReactNative??) ๐Ÿš€

Output sample

  • Download InjectionForXcode

  • Install it, Launch it and Go to File>Install Plugins (cmd+i)

  • Restart Xcode and make sure to click Load bundles on the popup

In order to support live reload with InjectionForXcode, we simply need to tell our ViewController to rebuild a view after an injection occured.

in viewDidLoad() add :

on("INJECTION_BUNDLE_NOTIFICATION") {
    self.view = MyView()
}

Currently InjectionForXcode doesn't seem to swizzle init methods for some reason. So we have to move our view code in another methods

convenience init() {
    self.init(frame:CGRect.zero)
    //View code
}

Becomes

convenience init() {
    self.init(frame:CGRect.zero)
    render()
}

func render() {
  //View code
}

And Voila :)

Now you can launch the app and modify whatever you want in the render() method. simply hit ^= or Product>Inject source and you'll see your changes Live ! ๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰

Installation

CocoaPods

pod 'SteviaLayout'
use_frameworks!

Carthage

github "s4cha/Stevia"
  • Create a Cartfile file at the root of your project folder

  • Add github "s4cha/Stevia" to your Cartfile

  • Run carthage update

  • Drag and drop Stevia.framework from /Carthage/Build/iOS/ to Linked frameworks and libraries in Xcode (Project>Target>General>Linked frameworks and libraries)

  • Add new run script (Project>Target>Build Phases>+> New run script phase) /usr/local/bin/carthage copy-frameworks

  • Add Input files $(SRCROOT)/Carthage/Build/iOS/Stevia.framework

There you go!

Manual

Copy Stevia source files to your Xcode project

Documentation

  1. View Hierarchy
  2. Layout
  3. Sizing
  4. Centering
  5. Filling
  6. Aligning
  7. Following another view
  8. Horizontal layout
  9. Vertical layout
  10. Flexible Margins
  11. Percentage-Based Layout
  12. Equations
  13. Priorities
  14. Styling
  15. Content
  16. Button taps
  17. Changing constraints
  18. Simple Changes
  19. Complex Changes
  20. Animating Changes
  21. TableView Cells & CollectionView Cells
  22. Getting views from the controller
  23. Complex/Nested layouts
  24. Known issues

Rationale behind the project

On the Yummypets app, we needed to deal with looooooots of views.
After trying different methods for building views (Xibs, Storyboards, Splitting Storyboards, React Native even(!).
We found that coding views programmatically was the best solution for us. But coding views programmatically had its issues too: UIKit exposes an imperative, verbose API, and it's really easy to create a mess with it. That's why we created Stevia.

Contributors

YannickDot, S4cha, Damien, Snowcraft, Mathieu-o

Swift Version

Swift 2 -> version 2.3.0
Swift 3 -> version 3.1.2

stevia's People

Contributors

gitter-badger avatar khaelou avatar liberty4me avatar mickmaccallum avatar orta avatar philiptrauner avatar pjambet avatar s4cha avatar sai-prasanna avatar szotp avatar tmcw avatar waternotwords avatar yannickdot avatar

Watchers

 avatar  avatar

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.