GithubHelp home page GithubHelp logo

layoutbox / flexlayout Goto Github PK

View Code? Open in Web Editor NEW
1.9K 34.0 223.0 17.46 MB

FlexLayout adds a nice Swift interface to the highly optimized facebook/yoga flexbox implementation. Concise, intuitive & chainable syntax.

License: MIT License

Ruby 1.80% Swift 73.27% Objective-C 3.94% Objective-C++ 9.34% C 7.09% C++ 4.57%
swift ios ios-swift layout layout-engine flexbox flex-layout flexbox-container css-flexbox flex-container

flexlayout's Introduction

FlexLayout


FlexLayout adds a nice Swift interface to the highly optimized Yoga flexbox implementation. Concise, intuitive & chainable syntax.

Flexbox is an incredible improvement over UIStackView. It is simpler to use, much more versatile and amazingly performant.

Yoga is a multiplatform CSS Flexbox implementation (iOS/Android/...). Yoga is also the layout engine of React Native.

Requirements

  • iOS 12.0+
  • Xcode 12.0+
  • Swift Swift 4.0

Content


πŸ“Œ FlexLayout is actively updated. So please come often to see latest changes. You can also Star it to be able to retrieve it easily later.


FlexLayout + PinLayout

FlexLayout

FlexLayout is a companion of PinLayout. They share a similar syntax and method names. PinLayout is a layout framework greatly inspired by CSS absolute positioning, it is particularly useful for greater fine control and animations. It gives you full control by layouting one view at a time (simple to code and debug).

  • A view can be layouted using FlexLayout, PinLayout, or both!
  • PinLayout can layout anything, but in situations where you need to layout many views but don't require PinLayout's finest control nor complex animations, FlexLayout is best fitted.
  • A view layouted using PinLayout can be embedded inside a FlexLayout's container and reversely. You choose the best layout framework for your situation.

FlexLayout Introduction examples

Example 1:

This example will layout multiples views using column and row flexbox containers.

Two steps to use a flexbox container:

  1. Setup the container: Initialize your flexbox structure. Note that it is also possible to alter it later.
  2. Layout the container: The layout of the container should be done from layoutSubviews() (or willTransition(to: UITraitCollection, ...) and viewWillTransition(to: CGSize, ...)).
    1. First you must layout the flexbox container, i.e. position it and optionally set its size.
    2. Then layout the flexbox children using Flex method layout().

FlexLayout example

fileprivate let rootFlexContainer = UIView()

init() {
   super.init(frame: .zero)
   
   addSubview(rootFlexContainer)
   ...

   // Column container
   rootFlexContainer.flex.direction(.column).padding(12).define { (flex) in
        // Row container
        flex.addItem().direction(.row).define { (flex) in
            flex.addItem(imageView).width(100).aspectRatio(of: imageView)
            
            // Column container
            flex.addItem().direction(.column).paddingLeft(12).grow(1).define { (flex) in
                flex.addItem(segmentedControl).marginBottom(12).grow(1)
                flex.addItem(label)
            }
        }
        
        flex.addItem().height(1).marginTop(12).backgroundColor(.lightGray)
        flex.addItem(bottomLabel).marginTop(12)
    }
}

override func layoutSubviews() {
    super.layoutSubviews() 

    // 1) Layout the flex container. This example use PinLayout for that purpose, but it could be done 
    //    also by setting the rootFlexContainer's frame:
    //       rootFlexContainer.frame = CGRect(x: 0, y: 0, 
    //                                        width: frame.width, height: rootFlexContainer.height)
    rootFlexContainer.pin.top().left().width(100%).marginTop(topLayoutGuide)

    // 2) Then let the flexbox container layout itself. Here the container's height will be adjusted automatically.
    rootFlexContainer.flex.layout(mode: .adjustHeight)
}

πŸ“Œ This example is available in the Examples App. See complete source code


Example 2:

The example implements the Ray Wenderlich Yoga Tutorial screen using FlexLayout.

init() {
   ...

   rootFlexContainer.flex.define { (flex) in
        // Image
        flex.addItem(episodeImageView).grow(1).backgroundColor(.gray)
        
        // Summary row
        flex.addItem().direction(.row).padding(padding).define { (flex) in
            flex.addItem(summaryPopularityLabel).grow(1)
            
            flex.addItem().direction(.row).justifyContent(.spaceBetween).grow(2).define { (flex) in
                flex.addItem(yearLabel)
                flex.addItem(ratingLabel)
                flex.addItem(lengthLabel)
            }
            
            flex.addItem().width(100).height(1).grow(1)
        }
        
        // Title row
        flex.addItem().direction(.row).padding(padding).define { (flex) in
            flex.addItem(episodeIdLabel)
            flex.addItem(episodeTitleLabel).marginLeft(20)
        }
        
        // Description section
        flex.addItem().paddingHorizontal(paddingHorizontal).define { (flex) in
            flex.addItem(descriptionLabel)
            flex.addItem(castLabel)
            flex.addItem(creatorsLabel)
        }
        
        // Action row
        flex.addItem().direction(.row).padding(padding).define { (flex) in
            flex.addItem(addActionView)
            flex.addItem(shareActionView)
        }
        
        // Tabs row
        flex.addItem().direction(.row).padding(padding).define { (flex) in
            flex.addItem(episodesTabView)
            flex.addItem(moreTabView)
        }
        
        // Shows TableView
        flex.addItem(showsTableView).grow(1)
    }
}

override func layoutSubviews() {
    super.layoutSubviews() 

    // 1) Layout the contentView & rootFlexContainer using PinLayout
    contentView.pin.top().bottom().left().right()
    rootFlexContainer.pin.top().left().right()

    // 2) Let the flexbox container layout itself and adjust the height
    rootFlexContainer.flex.layout(mode: .adjustHeight)
    
    // 3) Adjust the scrollview contentSize
    contentView.contentSize = rootFlexContainer.frame.size
}

πŸ“Œ This example is available in the Examples App. See complete source code


FlexLayout principles and philosophy

  • Flexbox layouting is simple, powerful and fast.
  • FlexLayout syntax is concise and chainable.
  • FlexLayout/yoga is incredibly fast, it's even faster than manual layout. See Performance.
  • The source code structure matches the flexbox structure, making it easier to understand and modify. Flex containers are defined on one line, and its items (children) are imbricated. This makes the flexbox structure much more visual and easy to understand.
  • Supports left-to-right (LTR) and right-to-left (RTL) languages.

NOTE: FlexLayout wraps facebook/yoga implementation and expose all its features. So note that on this documentation we will refer to FlexLayout, but this also applies to Yoga.


FlexLayout's Performance

FlexLayout's performance has been measured using the Layout Framework Benchmark. FlexLayout and PinLayout has been added to this benchmark to compare their performance.

As you can see in the following chart, FlexLayout and PinLayout's performance are faster or equal to manual layouting. FlexLayout and PinLayout are between 8x and 12x faster than UIStackViews, and this for all types of iPhone (5S/6/6S/7/8/X)

See here more complete details, results and explanation of the benchmark.


Variation from CSS flexbox

  • In many CSS methods and properties name, the keyword flex was added to control name conflicts. FlexLayout removed this keyword for being more concise and removed this unecessary keyword:

    FlexLayout Name CSS Name React Native Name
    direction flex-direction flexDirection
    wrap flex-wrap flexWrap
    grow flex-grow flexGrow
    shrink flex-shrink flexShrink
    basis flex-basis flexBasis
    start flex-start flexStart
    end flex-end flexEnd
  • FlexLayout default properties are sligthly different from CSS flexbox. This table resume these difference:

    Property FlexLayout default value CSS default value React Native default value
    direction column row column
    justifyContent start start start
    alignItems stretch stretch stretch
    alignSelf auto auto auto
    alignContent start stretch start
    grow 0 0 0
    shrink 0 1 0
    basis 0 auto 0
    wrap noWrap nowrap noWrap
  • FlexLayout additions:

    • addItem()
    • define()
    • layout()
    • isIncludedInLayout()
    • markDirty()
    • intrinsicSize
    • sizeThatFits()

NOTE: FlexLayout doesn't support the flexbox order property. The order is determined by the flex container's UIView.subviews array.


Documentation

Flexbox is pretty easy and straightforward to use. The defining aspect of the flexbox is the ability to alter its items, width, height to best fill the available space on any display device. A flex container expands its items to fill the available free space or shrinks them to prevent overflow.

The flex layout is constituted of parent container referred as flex container and its immediate children which are called flex items. A flex item can also be a flex container, i.e. it is possible to add other flex items to it.

Axes

When working with StackViews you need to think in terms of two axes β€” the main axis and the cross axis. The main axis is defined by StackView's direction property, and the cross axis runs perpendicular to it.

StackView direction Axes
column (default)
row
Sections

In the following sections we will see:

  1. How to create, modify and defines flex containers and items.
  2. Flexbox container's properties
  3. Flexbox item's properties

πŸ“Œ This document is a guide that explains how to use FlexLayout. You can also checks the FlexLayout's API documentation.


1. Creation, modification and definition of flexbox items

addItem(:UIView)

  • Applies to: flex containers
  • Returns: FlexLayout interface of the newly added flex item.

Method:

  • addItem(_: UIView) -> Flex
    This method adds a flex item (UIView) to a flex container. Internally this method adds the UIView as a subview and enables flexbox.
Usage examples:
  view.flex.addItem(imageView).width(100).aspectRatio(1)

addItem()

  • Applies to: flex containers
  • Returns: FlexLayout interface of the newly created flex item.

Method:

  • addItem() -> Flex
    This method is similar to addItem(: UIView) except that it also creates the flex item's UIView. Internally the method creates a UIView, adds it as a subview and enables flexbox. This is useful to add a flex item/container easily when you don't need to refer to it later.
Usage examples:
  view.flex.addItem().direction(.row).padding(10)

define()

  • Applies to: flex containers
  • Parameter: Closure of type (flex: Flex) -> Void

Method:

  • define(_ closure: (_ flex: Flex) -> Void)
    This method is used to structure your code so that it matches the flexbox structure. The method has a closure parameter with a single parameter called flex. This parameter is in fact the view's flex interface. It can be used to adds other flex items and containers.
Usage examples:
  view.flex.addItem().define { (flex) in
      flex.addItem(imageView).grow(1)
		
      flex.addItem().direction(.row).define { (flex) in
          flex.addItem(titleLabel).grow(1)
          flex.addItem(priceLabel)
      }
  }

The same results can also be obtained without using the define() method, but the result is not as elegant:

  let columnContainer = UIView()
  columnContainer.flex.addItem(imageView).grow(1)
  view.flex.addItem(columnContainer)
		
  let rowContainer = UIView()
  rowContainer.flex.direction(.row)
  rowContainer.flex.addItem(titleLabel).grow(1)
  rowContainer.flex.addItem(priceLabel)
  columnContainer.flex.addItem(rowContainer)

Advantages of using define():

  • The source code structure matches the flexbox structure, making it easier to understand and modify.
    • Changing a flex item order, it's just moving up/down its line/block that defines it.
    • Moving a flex item from one container to another is just moving line/block that defines it.
  • The structure looks more similar to how HTML and React Native defines it.
  • Inside the define's closure, you can do whatever you want to fill the flexbox container. You can use for loops, iterate arrays of data, call functions, ...

Accessing flex item's UIView

It is possible to access the flex items's UIView using flex.view. This is particularly useful when using flex.define() method.

Example:

This example creates a flexbox container and sets its alpha to 0.8.

    view.flex.direction(.row).padding(20).alignItems(.center).define { (flex) in
        flex.addItem().width(50).height(50).define { (flex) in
            flex.view?.alpha = 0.8
        }
    }

Another possible solution:

    view.flex.direction(.row).padding(20).alignItems(.center).define { (flex) in
        let container = UIView()
        container.alpha = 0.8
        
        flex.addItem(container).width(50).height(50)
    }

layout()

  • Applies to: flex containers
  • Values: fitContainer / adjustWidth / adjustHeight
  • Default value: fitContainer

Method:

  • layout(mode: LayoutMode = . fitContainer)
    The method will layout the flex container's children.

    Layout modes:

    • fitContainer: This is the default mode when no parameter is specified. Children are layouted inside the container's size (width and height).
    • adjustHeight: In this mode, children are layouted using only the container's width. The container's height will be adjusted to fit the flexbox's children
    • adjustWidth: In this mode, children are layouted using only the container's height. The container's width will be adjusted to fit the flexbox's children
Usage examples:
  rootFlexContainer.flex.layout(mode: .adjustHeight)

2. Flexbox containers properties

This section describes all flex container's properties.

direction()

  • Applies to: flex containers
  • Values: column / columnReverse / row / rowReverse
  • Default value: column
  • CSS name: flex-direction

Property:

  • direction: Direction?

Method:

  • direction(_: Direction)
    The direction property establishes the main-axis, thus defining the direction flex items are placed in the flex container.

    The direction property specifies how flex items are laid out in the flex container, by setting the direction of the flex container’s main axis. They can be laid out in two main directions, like columns vertically or like rows horizontally.

    Note that row and row-reverse are affected by the layout direction (see layoutDirection property) of the flex container. If its text direction is LTR (left to right), row represents the horizontal axis oriented from left to right, and row-reverse from right to left; if the direction is rtl, it's the opposite.

Value Result Description
column (default) Top to bottom
columnReverse Bottom to top
row Same as text direction
rowReverse opposite to text direction
Usage examples:
  view.flex.direction(.column)  // Not required, default value. 
  view.flex.direction(.row)
Example 1:

This example center three buttons with a margin of 10 pixels between them.
Example source code

    rootFlexContainer.flex.justifyContent(.center).padding(10).define { (flex) in
        flex.addItem(button1)
        flex.addItem(button2).marginTop(10)
        flex.addItem(button3).marginTop(10)
    }

justifyContent()

  • Applies to: flex containers
  • Values: start / end / center / spaceBetween / spaceAround / spaceEvenly
  • Default value: start
  • CSS name: justify-content

Method:

  • justifyContent(_: JustifyContent)
    The justifyContent property defines the alignment along the main-axis of the current line of the flex container. It helps distribute extra free space leftover when either all the flex items on a line have reached their maximum size. For example, if children are flowing vertically, justifyContent controls how they align vertically.
direction(.column) direction(.row)
start (default) Items are packed at the beginning of the main-axis.
end Items are packed at the end of the main-axis.
center items are centered along the main-axis.
spaceBetween Items are evenly distributed in the main-axis; first item is at the beginning, last item at the end.
spaceAround Items are evenly distributed in the main-axis with equal space around them.
spaceEvenly Items are evenly distributed in the main-axis with equal space around them.
Usage examples:
  view.flex.justifyContent(.start)  // default value. 
  view.flex.justifyContent(.center)

alignItems()

  • Applies to: flex containers
  • Values: stretch / start / end / center / baseline
  • Default value: stretch
  • CSS name: align-items

Method:

  • alignItems(_: AlignItems)
    The alignItems property defines how flex items are laid out along the cross axis on the current line. Similar to justifyContent but for the cross-axis (perpendicular to the main-axis). For example, if children are flowing vertically, alignItems controls how they align horizontally.
direction(.column) direction(.row)
stretch (default)
start
end
center

alignSelf()

  • Applies to: flex containers
  • Values: auto / stretch / start / end / center / baseline
  • Default value: auto
  • CSS name: align-self

Method:

  • alignSelf(_: AlignSelf)
    The alignSelf property controls how a child aligns in the cross direction, overriding the alignItems of the parent. For example, if children are flowing vertically, alignSelf will control how the flex item will align horizontally.

The auto value means use the flex container alignItems property. See alignItems for documentation of the other values.


wrap()

  • Applies to: flex containers
  • Values: noWrap / wrap / wrapReverse
  • Default value: noWrap
  • CSS name: flex-wrap

Method:

  • wrap(_: Wrap)
    The wrap property controls whether the flex container is single-lined or multi-lined, and the direction of the cross-axis, which determines the direction in which the new lines are stacked in.

By default, the flex container fits all flex items into one line. Using this property we can change that. We can tell the container to lay out its items in single or multiple lines, and the direction the new lines are stacked in

Reminder: the cross axis is the axis perpendicular to the main axis. Its direction depends on the main axis direction.

direction(.column) direction(.row) Description
noWrap (default) Single-line which may cause the container to overflow. NEW: Flex items are displayed in one row and by default they are shrunk to fit the flex container’s width
wrap Multi-lines, direction is defined by direction(). NEW: Flex items are displayed in multiple rows if needed from left-to-right and top-to-bottom
wrapReverse Multi-lines, opposite to direction defined by direction(). NEW: Flex items are displayed in multiple rows if needed from left-to-right and bottom-to-top
Usage examples:
  view.flex.wrap(.nowrap)  // Not required, default value. 
  view.flex.wrap(.wrap)

alignContent()

  • Applies to: flex containers
  • Values: start / end / center / stretch / spaceBetween / spaceAround
  • Default value: start
  • CSS name: align-content

Method:

  • alignContent(_: AlignContent)
    The align-content property aligns a flex container’s lines within the flex container when there is extra space in the cross-axis, similar to how justifyContent aligns individual items within the main-axis.

Note, alignContent has no effect when the flexbox has only a single line.

direction(.column) direction(.row)
start (default)
end
center
stretch
spaceBetween
spaceAround

layoutDirection()

FlexLayout supports left-to-right (LTR) and right-to-left (RTL) languages.

Using start or end properties, you can position views without having to think about whether your item will show up on the left or the right side of the screen (depending on the person’s language

Method:

  • layoutDirection(_: LayoutDirection)
    The layoutDirection property controls the flex container layout direction.

    Values:

    • .inherit
      Direction defaults to Inherit on all nodes except the root which defaults to LTR. It is up to you to detect the user’s preferred direction (most platforms have a standard way of doing this) and setting this direction on the root of your layout tree.
    • .ltr: Layout views from left to right. (Default)
    • .rtl: Layout views from right to left.

3. Flexbox items properties

This section describe all flex items's properties.

πŸ“Œ Remembers that flex containers are also flex items, so all these properties also apply to containers.

grow

  • Applies to: flex items
  • Default value: 0
  • CSS name: flex-grow

Method:

  • grow(_: CGFloat)
    The grow property defines the ability for a flex item to grow if necessary. It accepts a unitless value that serves as a proportion. It dictates what amount of the available space inside the flex container the item should take up.

    A grow value of 0 (default value) keeps the view's size in the main-axis direction. If you want the view to use the available space set a grow value > 0.

For example, if all items have grow set to 1, every child will set to an equal size inside the container. If you were to give one of the children a value of 2, that child would take up twice as much space as the others.


shrink

  • Applies to: flex items
  • Default value: 0
  • CSS name: flex-shrink

Method:

  • shrink(_: CGFloat)
    It specifies the "flex shrink factor", which determines how much the flex item will shrink relative to the rest of the flex items in the flex container when there isn't enough space on the main-axis.

    When omitted, it is set to 0 and the flex shrink factor is multiplied by the flex basis when distributing negative space.

    A shrink value of 0 keeps the view's size in the main-axis direction. Note that this may cause the view to overflow its flex container.

    Shrink is about proportions. If an item has a shrink of 3, and the rest have a shrink of 1, the item will shrink 3x as fast as the rest.


basis

  • Applies to: flex items
  • Default value: 0
  • CSS name: flex-basis

Method:

  • basis(_ : CGFloat?)
    This property takes the same values as the width and height properties, and specifies the initial size of the flex item, before free space is distributed according to the grow and shrink factors.

    Specifying nil set the basis as auto, which means the length is equal to the length of the item. If the item has no length specified, the length will be according to its content

  • basis(_ : FPercent)
    This property takes the same values as the width and height properties, and specifies the initial size of the flex item, before free space is distributed according to the grow and shrink factors.


gap

  • Applies to: flex containers
  • CSS name: gap

Method:

  • columnGap(_ value: CGFloat) This property set distance between columns.

  • rowGap(_ value: CGFloat) This property set distance between rows.

  • gap(_ value: CGFloat) This property set distance between both of rows and columns.


isIncludedInLayout()

  • Applies to: flex items

Method:

  • isIncludedInLayout(_ value: Bool)
    This property controls dynamically if a flexbox's UIView is included or not in the flexbox layouting. When a flexbox's UIView is excluded, FlexLayout won't layout the view and its children views.

FlexLayout automatically includes the UIView when:

  • The first time UIView.flex property is accessed
  • When a child view is added to a flexbox container using addItem(:UIView) or addItem()

display

  • Applies to: flex items

Method:

  • display(_: Display)

Set the item display or not, with none value, the item will be hidden and not included in the layout.


markDirty()

  • Applies to: flex items

Method:

  • markDirty()
    The framework is so highly optimized, that flex items are layouted only when a flex property is changed and when flex container size change. In the event that you want to force FlexLayout to do a layout of a flex item, you can mark it as dirty using markDirty().

    Dirty flag propagates to the root of the flexbox tree ensuring that when any item is invalidated its whole subtree will be re-calculated.

Usage examples:

In the case where a UILabel's text is updated, it is needed to mark the label as dirty and relayout the flex container.

    // 1) Update UILabel's text
    label.text = "I love FlexLayout"
     
    // 2) Mark the UILabel as dirty
    label.flex.markDirty()
    
    // 3) Then force a relayout of the flex container.
    rootFlexContainer.flex.layout()
    OR
    setNeedsLayout()

sizeThatFits()

  • Applies to: flex items

Method:

  • sizeThatFits()
    Returns the item size when layouted in the specified frame size.
Usage Example:

Get the size of view when layouted in a container with a width of 200 pixels.

    let layoutSize = viewA.flex.sizeThatFits(size: CGSize(width: 200, height: CGFloat.greatestFiniteMagnitude))

intrinsicSize

  • Applies to: flex items

Property:

  • intrinsicSize
    Item natural size, considering only properties of the view itself. Independent of the item frame.

4. Absolute positioning

  • Applies to: flex items
  • Parameter: CGFloat

Method:

  • position(_: Position)
    The position property tells Flexbox how you want your item to be positioned within its parent. Position values:
    • relative (default)
    • absolute: The view is positioned using properties: top(), bottom(), left(), right(), start(), end().
Usage examples:
  view.flex.position(.absolute).top(10).left(10).size(50)

top(), bottom(), left(), right(), start(), end(), vertically(), horizontally(), all()

A flex item which is position is set to .absolute is positioned absolutely in regards to its parent. This is done through the following methods:

Methods:

  • top(: CGFloat) / top(: FPercent):
    Controls the distance a child’s top edge is from the parent’s top edge.
  • bottom(: CGFloat) / bottom(: FPercent):
    Controls the distance a child’s bottom edge is from the parent’s bottom edge.
  • left(: CGFloat) / left(: FPercent):
    Controls the distance a child’s left edge is from the parent’s left edge.
  • right(: CGFloat) / right(: FPercent):
    Controls the distance a child’s right edge is from the parent’s right edge.
  • start(: CGFloat) / start(: FPercent):
    Controls the distance a child’s start edge is from the parent’s start edge. In left-to-right direction (LTR), it corresponds to the left() property and in RTL to right() property.
  • end(: CGFloat) / end(: FPercent):
    Controls the distance a child’s end edge is from the parent’s end edge. In left-to-right direction (LTR), it corresponds to the right() property and in RTL to left() property.
  • vertically(: CGFloat) / vertically(: FPercent):
    Controls the distance child’s top and bottom edges from the parent’s edges. Equal to top().bottom().
  • horizontally(: CGFloat) / horizontally(: FPercent):
    Controls the distance child’s left and right edges from the parent’s edges. Equal to left().right().
  • all(: CGFloat) / all(: FPercent):
    Controls the distance child’s edges from the parent’s edges. Equal to top().bottom().left().right().

Using these properties you can control the size and position of an absolute item within its parent. Because absolutely positioned children don’t affect their sibling's layout. Absolute position can be used to create overlays and stack children in the Z axis.

Usage examples:
  view.flex.position(.absolute).top(10).right(10).width(100).height(50)
  view.flex.position(.absolute).left(20%).right(20%)

πŸ“Œ See the "Yoga C" example in the Examples App. Source code


5. Adjusting the size

Width and height and size

FlexLayout has methods to set the view’s height and width.

Methods:

  • width(_ width: CGFloat?)
    The value specifies the view's width in pixels. The value must be non-negative. Call width(nil) to reset the property.
  • width(_ percent: FPercent)
    The value specifies the view's width in percentage of its container width. The value must be non-negative. Call width(nil) to reset the property.
  • height(_ height: CGFloat?)
    The value specifies the view's height in pixels. The value must be non-negative. Call height(nil) to reset the property.
  • height(_ percent: FPercent)
    The value specifies the view's height in percentage of its container height. The value must be non-negative. Call height(nil) to reset the property.
  • size(_ size: CGSize?)
    The value specifies view's width and the height in pixels. Values must be non-negative. Call size(nil) to reset the property.
  • size(_ sideLength: CGFloat?)
    The value specifies the width and the height of the view in pixels, creating a square view. Values must be non-negative. Call size(nil) to reset the property.
Usage examples:
  view.flex.width(100)	
  view.flex.width(50%)	
  view.flex.height(200)
	
  view.flex.size(250)

minWidth(), maxWidth(), minHeight(), maxHeight()

FlexLayout has methods to set the view’s minimum and maximum width, and minimum and maximum height.

Using minWidth, minHeight, maxWidth, and maxHeight gives you increased control over the final size of items in a layout. By mixing these properties with grow, shrink, and alignItems(.stretch), you are able to have items with dynamic size within a range which you control.

An example of when Max properties can be useful is if you are using alignItems(.stretch) but you know that your item won’t look good after it increases past a certain point. In this case, your item will stretch to the size of its parent or until it is as big as specified in the Max property.

Same goes for the Min properties when using shrink. For example, you may want children of a container to shrink to fit on one row, but if you specify a minimum width, they will break to the next line after a certain point (if you are using wrap(.wrap).

Another case where Min and Max dimension constraints are useful is when using aspectRatio.

Methods:

  • minWidth(_ width: CGFloat?)
    The value specifies the view's minimum width of the view in pixels. The value must be non-negative. Call minWidth(nil) to reset the property.
  • minWidth(_ percent: FPercent)
    The value specifies the view's minimum width of the view in percentage of its container width. The value must be non-negative. Call minWidth(nil) to reset the property..
  • maxWidth(_ width: CGFloat?)
    The value specifies the view's maximum width of the view in pixels. The value must be non-negative. Call maxWidth(nil) to reset the property.
  • maxWidth(_ percent: FPercent)
    The value specifies the view's maximum width of the view in percentage of its container width. The value must be non-negative. Call maxWidth(nil) to reset the property.
  • minHeight(_ height: CGFloat?)
    The value specifies the view's minimum height of the view in pixels. The value must be non-negative. Call minHeight(nil) to reset the property.
  • minHeight(_ percent: FPercent)
    The value specifies the view's minimum height of the view in percentage of its container height. The value must be non-negative. Call minHeight(nil) to reset the property.
  • maxHeight(_ height: CGFloat?)
    The value specifies the view's maximum height of the view in pixels. The value must be non-negative. Call maxHeight(nil) to reset the property.
  • maxHeight(_ percent: FPercent)
    The value specifies the view's maximum height of the view in percentage of its container height. The value must be non-negative. Call maxHeight(nil) to reset the property.
Usage examples:
  view.flex.maxWidth(200)
  view.flex.maxWidth(50%)
  view.flex.width(of: view1).maxWidth(250)
	
  view.flex.maxHeight(100)
  view.flex.height(of: view1).maxHeight(30%)

aspectRatio()

AspectRatio is a property introduced by Yoga that don't exist in CSS. AspectRatio solves the problem of knowing one dimension of an element and an aspect ratio, this is very common when it comes to images, videos, and other media types. AspectRatio accepts any floating point value > 0, the default is undefined.

  • AspectRatio is defined as the ratio between the width and the height of a node e.g. if a node has an aspect ratio of 2 then its width is twice the size of its height.
  • AspectRatio respects the Min and Max dimensions of an item.
  • AspectRatio has higher priority than grow.
  • If AspectRatio, Width, and Height are set then the cross dimension is overridden
  • Call aspectRatio(nil) to reset the property.
Usage examples:
  imageView.flex.aspectRatio(16/9)

6. Margins

By applying Margin to an item you specify the offset a certain edge of the item should have from it’s closest sibling or parent.

Methods:

  • marginTop(_ value: CGFloat), marginTop(_ percent: FPercent)
    Top margin specify the offset the top edge of the item should have from it’s closest sibling (item) or parent (container).
  • marginLeft(_ value: CGFloat), marginLeft(_ percent: FPercent)
    Left margin specify the offset the left edge of the item should have from it’s closest sibling (item) or parent (container).
  • marginBottom(_ value: CGFloat), marginBottom(_ percent: FPercent)
    Bottom margin specify the offset the bottom edge of the item should have from it’s closest sibling (item) or parent (container)
  • marginRight(_ value: CGFloat), marginRight(_ percent: FPercent)
    Right margin specify the offset the right edge of the item should have from it’s closest sibling (item) or parent (container).
  • marginStart(_ value: CGFloat), marginStart(_ percent: FPercent)
    Set the start margin. In LTR direction, start margin specify the left margin. In RTL direction, start margin specify the right margin.
  • marginEnd(_ value: CGFloat), marginEnd(_ percent: FPercent)
    Set the end margin. In LTR direction, end margin specify the right margin. In RTL direction, end margin specify the left margin.
  • marginHorizontal(_ value: CGFloat), marginHorizontal(_ percent: FPercent)
    Set the left, right, start and end margins to the specified value.
  • marginVertical(_ value: CGFloat), marginVertical(_ percent: FPercent)
    Set the top and bottom margins to the specified value.
  • margin(_ insets: UIEdgeInsets) Set all margins using an UIEdgeInsets. This method is particularly useful to set all margins using iOS 11 UIView.safeAreaInsets.
  • margin(_ insets: NSDirectionalEdgeInsets) Set all margins using an NSDirectionalEdgeInsets. This method is useful to set all margins using iOS 11 UIView. directionalLayoutMargins when layouting a view supporting RTL/LTR languages.
  • margin(_ value: CGFloat)
    Set all margins to the specified value.
  • margin(_ vertical: CGFloat, _ horizontal: CGFloat)
  • margin(_ top: CGFloat, _ horizontal: CGFloat, _ bottom: CGFloat)
  • margin(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat)
Usage examples:
  view.flex.margin(20)
  view.flex.marginTop(20%).marginLeft(20%)
  view.flex.marginHorizontal(20)
  view.flex.margin(safeAreaInsets)
  view.flex.margin(10, 12, 0, 12)

7. Paddings

Padding specify the offset children should have from a certain edge on the container.

Methods:

  • paddingTop(_ value: CGFloat), paddingTop(_ percent: FPercent)
  • paddingLeft(_ value: CGFloat), paddingLeft(_ percent: FPercent)
  • paddingBottom(_ value: CGFloat), paddingBottom(_ percent: FPercent)
  • paddingRight(_ value: CGFloat), paddingRight(_ percent: FPercent)
  • paddingStart(_ value: CGFloat), paddingStart(_ percent: FPercent)
  • paddingEnd(_ value: CGFloat), paddingEnd(_ percent: FPercent)
  • paddingHorizontal(_ value: CGFloat), paddingHorizontal(_ percent: FPercent)
  • paddingVertical(_ value: CGFloat), paddingVertical(_ percent: FPercent)
  • padding(_ insets: UIEdgeInsets) Set all paddings using an UIEdgeInsets. This method is particularly useful to set all paddings using iOS 11 UIView.safeAreaInsets.
  • padding(_ insets: NSDirectionalEdgeInsets)
    Set all paddings using an NSDirectionalEdgeInsets. This method is particularly useful to set all padding using iOS 11 UIView. directionalLayoutMargins when layouting a view supporting RTL/LTR languages.
  • padding(_ value: CGFloat), padding(_ percent: FPercent)
  • padding(_ vertical: CGFloat, _ horizontal: CGFloat), padding(_ vertical: FPercent, horizontal: FPercent
  • padding(_ top: CGFloat, _ horizontal: CGFloat, _ bottom: CGFloat), padding(_ top: FPercent, _ horizontal: FPercent, _ bottom: FPercent)
  • padding(_ top: CGFloat, _ left: FPercent, _ bottom: FPercent, _ right: FPercent), padding(_ top: FPercent, _ left: FPercent, _ bottom: FPercent, _ right: FPercent)
Usage examples:
  view.flex.padding(20)
  view.flex.paddingTop(20%).paddingLeft(20%)
  view.flex.paddingBottom(20)
  view.flex.paddingHorizontal(20)
  view.flex.padding(10, 12, 0, 12)

9. Extra UIView methods

FlexLayout also adds methods to set common UIView properties.

Methods:

  • backgroundColor(_ color: UIColor)
    Set the flex item's UIView background color.
  • cornerRadius(_ value: CGFloat)
    Set the flex item's UIView rounded corner radius.
  • border(_ width: CGFloat, _ color: UIColor)
    Set the flex item's UIView border.
Usage examples:
  // Create a gray column container and add a black horizontal line separator 
  flex.addItem().backgroundColor(.gray).define { (flex) in
      flex.addItem().height(1).backgroundColor(.black)
  }
  // Set rounded corner
  flex.addItem().cornerRadius(12)
  // Set border
  flex.addItem().border(1, .black)

FlexLayout API Documentation

The complete FlexLayout API is available here.


Example App

The FlexLayout's Example App exposes some usage example of FlexLayout.
See the Example App section to get more information.


FAQ

  • Q: The flex item overflows or is bigger than its container?
    A: By default the flex item's shrink value is 0, which keeps the item's current size in the main-axis direction. So that may cause the item to overflow its flex container. To fix that you just have to specify a shrink value bigger than 0:
   view.flex.shrink(1)
  • Q: How to keep the view size (width/height)?
    A: By default view's flex shrink value is set to 1, which reduce the size of the view if the view is bigger than its flex container in the main-axis direction. If the direction is column, the height is adjusted, if the direction is row, the width is adjusted. Setting this value to 0 will keep the view size in the main-axis direction.

  • Q: How to apply percentage from a CGFloat, a Float or an Int value?
    R: Few FlexLayout's method has a parameter of type FPercent. You can easily specify this type of parameter simply by adding the % operator to your value (eg: view.flex.width(25%). It is similar if you have a value of type CGFloat, Float or Int, simply adds the % operator:

     let percentageValue: CGFloat = 50
     view.flex.height(percentageValue%)

Flexbox interesting external links


Contributing, comments, ideas, suggestions, issues, ....

For any comments, ideas, suggestions, simply open an issue.

For issues, please have a look at Yoga's issues. Your issue may have been already reported. If not, it may be a FlexLayout issue. In this case open an issue and we'll let you know if the issue is related to Yoga's implementation.

If you find FlexLayout interesting, thanks to Star it. You'll be able to retrieve it easily later.

If you'd like to contribute, you're welcome!


Installation

CocoaPods

To integrate FlexLayout into your Xcode project using CocoaPods, specify it in your Podfile:

  pod 'FlexLayout'

Then, run pod install.

Carthage

To integrate FlexLayout into your Xcode project using Carthage:

  1. Specify in your Cartfile:
github "layoutBox/FlexLayout"
  1. Run carthage update to build frameworks.
  2. Add built FlexLayout.framework in your Xcode project in the Embedded Binaries section.

Swift Package Manager

Another Swift Package

To integrate FlexLayout into another Swift Package, add it as a dependency:

.package(url: "https://github.com/layoutBox/FlexLayout.git", from: "1.3.18")

In an Xcode target

To integrate FlexLayout into an Xcode target, use the File -> Swift Packages -> Add Package Dependency menu item.


Changelog

FlexLayout recent history is available in the are documented in the CHANGELOG.


License

MIT License

flexlayout's People

Contributors

baekteun avatar dependabot[bot] avatar ekkog avatar gcox avatar greenover avatar gyuchan0128 avatar hoonv avatar iohin avatar kenny-pu avatar kuluum avatar levi avatar lucdion avatar lukewakeford avatar minhaaan avatar namolnad avatar nuomi1 avatar ohkanghoon avatar pual avatar rachikabidi avatar rag0n avatar rantingmong avatar skyline-23 avatar stephengroat avatar stleamist avatar taekh avatar vincentsit avatar wcoder avatar wnstkdyu avatar zedd0202 avatar zintus 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

flexlayout's Issues

UILabel Inconsistencies

e4313409-bb6e-44d4-8774-b7c3d196542c

I am trying to build a very simple β€œpost” view as shown above. I have three labels: the name, the timestamp, and the content. I want the content to be able to expand as necessary, but I am getting strange padding on the label when I scroll. Some posts have this padding, some don’t, and when a container cell scrolls out and then back into view, it seems to change.

Has anyone experienced this? Is there a solid example with a resizing label?

Two Questions

  1. Do you support or plan on supporting macOS?
  2. What would you tell a dev that is on the fence between FlexLayout and LayoutKit for a bigger project?

Finally I love your work and the performance benchmarks. Thanks for putting creating this, I've already used it on a smaller project and it's fantastic!

Cheers!
Manny

scrollview help

I have a contentView, contentView have a scrollview, code is below, but scrollview frame is larger than contentView, not equal contentView height, how can I do?

addSubview(contentView)
contentView.flex.direction(.column).define { (flex) in
         flex.addItem(scrollView).define({ (flex) in
                    for item in list {
                        let view = VoteTextSelectRow(state: item)
                        flex.addItem(view).marginTop(26)
                    }
                    flex.addItem().height(80)
                })
                
        }

UILabel size is not enough to render the text

I have a tableView and three cells. Each cell has two labels: timeLabel and titleLabel. The first two titleLabels, whose background colors are red, have the same text "ζœͺ命名". The first one show full text, but the second one not.
My code in the cell:

self.contentView.flex.direction(.row).define { (flex) in
    flex.addItem(timeLabel)
    flex.addItem(titleLabel).marginLeft(10).shrink(1).backgroundColor(UIColor.red)
}

image

Issue with Carthage

Hi,

I get the following error when trying to add FlexLayout to my project using Carthage:

=== BUILD TARGET FlexLayout OF PROJECT FlexLayout WITH CONFIGURATION Release ===

Check dependencies
The file β€œPods-FlexLayout.release.xcconfig” couldn’t be opened because there is no such file. (/Path/To/Project/Carthage/Checkouts/FlexLayout/Pods/Target Support Files/Pods-FlexLayout/Pods-FlexLayout.release.xcconfig)
Warning: The Copy Bundle Resources build phase contains this target's Info.plist file 'Sources/SupportingFiles/Info.plist'.

PhaseScriptExecution [CP]\ Check\ Pods\ Manifest.lock /Users/Username/Library/Caches/org.carthage.CarthageKit/DerivedData/9.0_9A235/FlexLayout/1.1.1/Build/Intermediates.noindex/FlexLayout.build/Release-iphoneos/FlexLayout.build/Script-6850E88D30235C33E59B38DA.sh
    cd /Path/To/Project/Carthage/Checkouts/FlexLayout
    /bin/sh -c /Users/Username/Library/Caches/org.carthage.CarthageKit/DerivedData/9.0_9A235/FlexLayout/1.1.1/Build/Intermediates.noindex/FlexLayout.build/Release-iphoneos/FlexLayout.build/Script-6850E88D30235C33E59B38DA.sh
diff: /Podfile.lock: No such file or directory
diff: /Manifest.lock: No such file or directory
error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.

** BUILD FAILED **

scrollview help

I have a contentView, contentView have a scrollview, code is below, but scrollview frame is larger than contentView, not equal contentView height, how can I do?

 addSubview(contentView)
        contentView.flex
            .direction(.column)
            .padding(23, 16, 23, 16)
            .define { (flex) in
                flex.addItem(scrollView).define({ (flex) in
                    for item in list {
                        let view = VoteTextSelectRow(state: item)
                        flex.addItem(view).marginTop(26)
                    }
                    flex.addItem().height(80)
                })
                
        }

Recalculate FlexConteiner

How to recalculate the entire container if one object is hidden and the container is compressed ?

Help with some issues

Maybe we can use this as an example app to help others?
Not sure if i'm the only one stuck.

Here is my example app -> https://github.com/patchthecode/FlexLayoutPlayground
Just clone and do pod update and it should work.

I needed help on the following. I am not sure if i am not updating the layouts properly.

  1. When i launch the app all seems well except for the bottom right blue KiloMeters label. I just dont know how to get it properly right aligned. Also it's width should take higher priority than the Label to the left of it. Blue view should fit the width of the label. And greenview to the left should take up the remaining space, but shrink if blueView needs more space. Left greenView number or lines of label is 2. If it cant fit, it should wrap to 2nd line.

screen shot 2017-10-19 at 7 41 44 am

  1. As i start scrolling i sometimes (but not always) see the right padding disappear. When i checked it out, i realized that the green container view didnt adjust its width to fit the label.

screen shot 2017-10-19 at 7 40 46 am

  1. The bottom right blue view starts sticking to the top. Also, theCompany name does not break to another line.

screen shot 2017-10-19 at 7 41 23 am

screen shot 2017-10-19 at 7 41 02 am

  1. Also, with the number of lines on a label set to 0, I get this when i scroll.

screen shot 2017-10-19 at 8 16 12 am

Maybe it should get the width of the label first, and then wrap it if it cant fit? (or maybe i am just doing something wrong again πŸ˜….

  1. Lastly how do I make the cells height automatic?
    i tried using UICollectionViewFlowLayoutAutomaticSize with an estimated height, but the views become wrong sizes. And nothing displays.

I'm pretty sure it must be something wrong im doing, so maybe If you help with this project, it can be used as an example for this repo? (if you want to of coruse)

Thanks!

child items out of the bounds of the container

//
//  TestViewController.swift
//  FlexLayoutSample
//
//  Created by ciel on 2018/5/2.
//  Copyright Β© 2018εΉ΄ Mirego. All rights reserved.
//

import UIKit
import FlexLayout
import PinLayout

class TestViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.backgroundColor = .red
        
        // Do any additional setup after loading the view.
        self.view.flex.define { (flex) in
            flex.addItem().define({ (flex) in
                flex.view?.backgroundColor = .white
                flex.height(100)
                flex.direction(.row)
                flex.wrap(.noWrap)
                let v = UIView()
                v.backgroundColor = .green
                
                flex.marginTop(100)
                flex.addItem(v).define({ (flex) in
                    flex.size(CGSize(width: 30, height: 30))
                })
                flex.addItem().direction(.column).define({ (flex) in
                    flex.marginLeft(10)
                    flex.view?.backgroundColor = .gray
                    for _ in 0...3 {
                        let btn = UIButton(type: .custom)
                        btn.backgroundColor = .blue
                        flex.addItem(btn).define({ (flex) in
                            flex.width(100)
                            flex.marginTop(10)
                        })
                    }
                })
            })
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.view.flex.layout()
    }

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

With the latest version, and code above, blue items out of the bounds of the container

image

Horizontal Scroll View

Hi, Everyone. I tried to make a horizontal scroll view by using overflow.
I have a scrollview with a contentView inside. The contentView is set to have direction as .row, justifyContent as .spaceAround and wrap as .noWrap. Then I insert views into the contentView with width equal to the screen width and shrink equal to 0, hoping that the total width of the views I inserted can set the width of the contentView which then set the contentSize of the scrollview. However, it fails and instead I have to explicitly set the scrollView contentSize in order to make to scroll view scrolls. So my question is : Is there a way to make a horizontal scroll view without setting scrollView.contentSize explicitly using flexbox layout.
Thank you πŸ˜ƒ

flex layout for navigation bar

Need suggestion for flex layout to be used in navigation bar and its items, considering if I'm customising my navigation bar without using NavigationController

Remove Item using Flex

how to remove an item in flex like removeFromSuperView() - is not an issue, need suggestion

Updating a label value results in truncated text even after updating layout

Hello, I noticed something while building a layout : when a label's text value is updated its bounds don't seem to update even after layoutSubviews is executed in the parent view.

Here's a simple example : I have a controller with a flex container containing a button and a label. Pressing the button assign a new text to the label (a bit longer than the original value) and setNeedLayout is called on the controller's view. However doing so cause the UILabel to truncate the text.

class DummyView: UIView {
    
    let flexContainer = UIView()
    let button = UIButton()
    let label = UILabel()
    
    required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
    override init(frame: CGRect) { super.init(frame: frame) }
    
    convenience init() {
        self.init(frame: .zero)
        self.button.setTitle("button", for: .normal)
        self.button.setTitleColor(UIColor.red, for: .normal)
        self.label.text = "hello"
        
        flexContainer.flex.padding(20).alignItems(.center).define { (flex) in
            flex.addItem(button).width(100%)
            flex.addItem(label).marginTop(10)
        }
        addSubview(flexContainer)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        self.flexContainer.pin.top().left().right()
        self.flexContainer.flex.layout(mode: .adjustHeight)
    }
    
}
class DummyController: UIViewController {

    fileprivate var mainView: DummyView { return self.view as! DummyView }
    init() {  super.init(nibName: nil, bundle: nil) }
    required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
    override func loadView() { view = DummyView() }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        mainView.button.addTarget(self, action: #selector(onButtonPressed(sender:)), for: .touchUpInside)
    }
    
    @objc func onButtonPressed(sender: UIButton) {
        mainView.label.text = "goodbye"
        mainView.setNeedsLayout()
    }
    
}

before

after

about marginTop(n%) not refer to superView's height

My code is:

import UIKit
import FlexLayout

class YogaExampleAView: BaseView {
    fileprivate let rootFlexContainer = UIView()

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override init() {
        super.init()
        rootFlexContainer.flex.define { (flex) in
            flex.addItem().width(80).height(40).marginLeft(20).marginTop(10%).backgroundColor(.blue)
            flex.addItem().height(100).width(250).marginLeft(40).marginTop(20).backgroundColor(.green).define { flex in
                flex.addItem().height(20).width(30).marginTop(16%).backgroundColor(.magenta)
            }
        }
        addSubview(rootFlexContainer)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        rootFlexContainer.frame = bounds
        rootFlexContainer.flex.layout()
    }
}

the UI looks like :

image

As you see, I set the blue view's marginTop to 10% (I assume that means 10% height of it's superView), but the blue view's Y is actually 37.5, by a strange coincidence, It's 10% of the superView's width(375).

And then, I verify with magenta view's width and Y:

image

The magenta view's Y is 40, 16% of the superView's(green) width(250).

Just confuse about that...😳

Getting issue while exporting to IPA (carthage and bitcode)

I am getting below Error while i export to IPA.

Failed to verify bitcode in FlexLayout.framework/FlexLayout:
error: Cannot extract bundle from /var/folders/ww/nzb88by17dxg0bxns_9zncfc0000gn/T/XcodeDistPipeline.IU0/Root/Payload/SampleApp.app/Frameworks/FlexLayout.framework/FlexLayout (i386)

Conflict with rn yoga

RN needs to pod import yoga file with conflict with the file in FlexLayout, do you have some solutions?

Problem when using with UILabel

When I tried to layout a cell, there is a problem with UILabel.
Here is the code of layout:

contentView.flex.direction(Flex.Direction.column).alignContent(Flex.AlignContent.stretch).justifyContent(Flex.JustifyContent.center).marginLeft(15).marginRight(15).define { (flex) in
      flex.addItem().direction(Flex.Direction.row).alignItems(Flex.AlignItems.center).justifyContent(Flex.JustifyContent.start).define({ (flex) in
        flex.addItem(iconImageBackView).width(30).height(30).addItem(iconImageView).width(30).height(30)
        flex.addItem().grow(1).alignContent(Flex.AlignContent.stretch).marginLeft(10).define({ (flex) in
          flex.addItem(titleLabel).marginTop(9.5).height(20)
          flex.addItem().grow(1).alignContent(Flex.AlignContent.center).direction(Flex.Direction.row).justifyContent(Flex.JustifyContent.end).marginBottom(9).height(17.5).define({ (flex) in
            flex.addItem(subTitle).shrink(1).grow(1).backgroundColor(UIColor.green)
            flex.addItem(ruleLabel).marginLeft(2.5)
            flex.addItem(playerLabel).marginLeft(2.5)
            flex.addItem(scoreLabel).marginLeft(2.5)
          })
        })
      })
      flex.addItem().height(1).backgroundColor(UIColor.white22622622610)
    }

In this code, roleLabel, playerLabel and scoreLabel all have layout like this, they are the label with red border with rounded corner.

flex.width(45).shrink(0).height(18).alignItems(Flex.AlignItems.center).justifyContent(Flex.JustifyContent.center).addItem(label).width(45)

The Layout result is like this:
qq20180122-004957 2x
the UILabel object subTitle pointed by the blue arrow is bigger than expected, can you help me with this problem?

The best way to do this

Hello! I need to make custom view that contains self sized UITextView. I need to change height for textView and "green view" when content for textView bigger than UITextView.contentView can contain. And I need to have a maximum height for textView or "green view". What is the best way to do this?

Code from init method for "green view":

`
attachmentButton = UIButton()
self.attachmentButton.setImage(UIImage.init(named: "ic_attachment"), for: UIControlState.normal)
self.attachmentButton.pin.size(32)

    self.sendButton = UIButton()
    self.sendButton.setImage(UIImage.init(named: "ic_send"), for: UIControlState.normal)
    self.sendButton.pin.size(32)
    
    inputTextView = UITextView()
    inputTextView.delegate = self
    inputTextView.isScrollEnabled = false
    inputTextView.font = UIFont.systemFont(ofSize: 17)
    inputTextView.backgroundColor = UIColor.red
    
    self.flex.direction(.column).paddingTop(10).paddingBottom(10).define { (flex) in
        flex.addItem().direction(.row).define { (flex) in
            flex.addItem(self.attachmentButton).paddingLeft(10).paddingRight(10)
            flex.addItem(self.inputTextView).grow(1)
            flex.addItem(self.sendButton).paddingLeft(10).paddingRight(10)
        }
    }`

screen shot 2018-06-07 at 16 16 17

The margin of the subview using FlexLayout is incorrect.

I am trying to make a dynamic height TableViewCell using FlexLayout. I follow the TableViewExample in FlexLayoutSample and found a problem, if the height of the Cell changes, the margin of the subview using the FlexLayout layout will not meet expectations.

I use FlexLayoutSample as an example. After a simple modification, I can reproduce this problem. The marginTop will be based on the parent container instead of the sibling item.

I want to ask how to solve this problem. I don't know if this is a bug of Yoga, it's more like a FlexLayout usage issue.

Snapshot

ezgif-4-05f7589ab9

Code

MethodCell.swift

diff --git a/Example/FlexLayoutSample/UI/Examples/TableViewExample/Subviews/MethodCell.swift b/Example/FlexLayoutSample/UI/Examples/TableViewExample/Subviews/MethodCell.swift
index 3fc6df2..7209c16 100644
--- a/Example/FlexLayoutSample/UI/Examples/TableViewExample/Subviews/MethodCell.swift
+++ b/Example/FlexLayoutSample/UI/Examples/TableViewExample/Subviews/MethodCell.swift
@@ -21,7 +21,7 @@ class MethodCell: UITableViewCell {
     fileprivate let padding: CGFloat = 10

     fileprivate let nameLabel = UILabel()
-    fileprivate let descriptionLabel = UILabel()
+    fileprivate let descriptionLabel = CustomView()

     override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
         super.init(style: style, reuseIdentifier: reuseIdentifier)
@@ -34,8 +34,8 @@ class MethodCell: UITableViewCell {
         nameLabel.font = UIFont.boldSystemFont(ofSize: 14)
         nameLabel.lineBreakMode = .byTruncatingTail

-        descriptionLabel.font = UIFont.systemFont(ofSize: 12)
-        descriptionLabel.numberOfLines = 0
+//        descriptionLabel.font = UIFont.systemFont(ofSize: 12)
+//        descriptionLabel.numberOfLines = 0

         // Use contentView as the root flex container
         contentView.flex.padding(12).define { (flex) in

TableViewExampleView.swift

diff --git a/Example/FlexLayoutSample/UI/Examples/TableViewExample/TableViewExampleView.swift b/Example/FlexLayoutSample/UI/Examples/TableViewExample/TableViewExampleView.swift
index 57ce16c..fac7d55 100644
--- a/Example/FlexLayoutSample/UI/Examples/TableViewExample/TableViewExampleView.swift
+++ b/Example/FlexLayoutSample/UI/Examples/TableViewExample/TableViewExampleView.swift
@@ -76,4 +76,16 @@ extension TableViewExampleView: UITableViewDataSource, UITableViewDelegate {
         // WANRING: You must also set the UITableView.estimatedRowHeight for this to work.
         return UITableViewAutomaticDimension
     }
+
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        tableView.deselectRow(at: indexPath, animated: true)
+
+        let cell = tableView.cellForRow(at: indexPath) as! MethodCell
+        let randomIndex = Int(arc4random_uniform(UInt32(methods.count) - 1))
+        let method = methods[randomIndex]
+        cell.configure(method: method)
+
+        tableView.beginUpdates()
+        tableView.endUpdates()
+    }
 }

CustomView.swift

import UIKit

final class CustomView: UIView {
  
  var text: String? {
    didSet {
      label.text = text
    }
  }
  
  private let label: UILabel = {
    let label = UILabel()
    label.font = .systemFont(ofSize: 12)
    label.numberOfLines = 0
    return label
  }()
  
  override init(frame: CGRect) {
    super.init(frame: frame)
    
    flex.addItem(label)
  }
  
  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  
  override func layoutSubviews() {
    super.layoutSubviews()
    
    flex.layout(mode: .adjustHeight)
  }
}


You can also check out the custom_view_layout branch of my fork.

How to use baseline alignment?

Hi Luc,
I don't know how to use the baseline alignment, they seems like not working as expect:

image

my code is here:

import UIKit
import FlexLayout

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupSubviews()
    }

    fileprivate func setupSubviews() {
        let label1 = UILabel()
        label1.text = "Hello."
        label1.font = UIFont.systemFont(ofSize: 18)
        
        let label2 = UILabel()
        label2.text = ".world."
        label2.font = UIFont.systemFont(ofSize: 12)
        
        let label3 = UILabel()
        label3.text = ".Intro."
        label3.font = UIFont.systemFont(ofSize: 22)
        
        let label4 = UILabel()
        label4.numberOfLines = 0
        label4.text = ".controller"
        label4.font = UIFont.systemFont(ofSize: 30)
        
        view.flex.paddingTop(100).define{ flex in
            flex.addItem().direction(.row).alignItems(.baseline).backgroundColor(.green).define{ flex in
                flex.addItem(label1).backgroundColor(.red)
                flex.addItem(label2).backgroundColor(.yellow)
                flex.addItem(label3).backgroundColor(.magenta)
                flex.addItem(label4).backgroundColor(.cyan)
            }
        }
        
    }    
   
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        view.flex.layout()
    }
}

Error sending to Apple

Can not fill application.

ERROR ITMS-90087: "Unsupported Architectures. The executable for Programme.app/Frameworks/FlexLayout.framework/Frameworks/YogaKit.framework contains unsupported architectures '[x86_64, i386]'."

ERROR ITMS-90685: "CFBundleIdentifier Collision. There is more than one bundle with the CFBundleIdentifier value 'com.facebook.YogaKit' under the iOS application 'Programme.app'."

ERROR ITMS-90205: "Invalid Bundle. The bundle at 'Programme.app/Frameworks/FlexLayout.framework' contains disallowed nested bundles."

ERROR ITMS-90206: "Invalid Bundle. The bundle at 'Programme.app/Frameworks/FlexLayout.framework' contains disallowed file 'Frameworks'."

Xcode 10 Beta

Hi @lucdion. I guess I'm rushing things but if you fix this mistake it would be good in Xcode 10 Beta

Error - Module compiled with Swift 4.1.2 cannot be imported in Swift 4.1.50:

Objective-C Runtime Overhead

Hi @lucdion β€” first off, I appreciate how well documented and thought-out the library is. Thank you!

I was reading through both codebases (FlexLayout and Yoga’s) and found an interesting pointer regarding the Objective-C runtime β€œhidden” behind the Swift layer.

UIView+Yoga.h#L29

/**
 In ObjC land, every time you access `view.yoga.*` you are adding another `objc_msgSend`
 to your code. If you plan on making multiple changes to YGLayout, it's more performant
 to use this method, which uses a single objc_msgSend call.
 */
- (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block
    NS_SWIFT_NAME(configureLayout(block:));

Given the current implementation of the wonderful chaining-based design, it seems like there is an opportunity to reduce the overhead to a single objc_msgSend call and also inform users of the same cost for view.flex.

use grow() to fill space without overflowing

Hi,

I'm trying to make a simple view composed of one row of two columns : the first column contains two labels (title and subtitle below) and the second col contains a button with a static size and centered vertically.

My goal is to make the labels fill the remaining horizontal space to always have the button on the right side of the view. It works well when the text inside the labels is short and it's pushing the button outside the container once the text is long enough to cause the label to expand vertically.

What am I doing wrong ?

here's what i'm trying to achieve (green outline is the frame) :

schema

here's the result on simulator :

schema

here's the code :

class MyView: BaseView {
    
    var titleLabel = UILabel()
    var subtitleLabel = UILabel()
    var infoButton = MyButton()
    var mainContainer = UIView()
    
    override init() {
        super.init()
        setup()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
    
    fileprivate func setup() {
        subtitleLabel.numberOfLines = 0

        mainContainer.flex.direction(.row).define { (flex) in
            flex.addItem().grow(1).define({ (flex) in
                flex.addItem(titleLabel)
                flex.addItem(subtitleLabel).marginTop(Dimen.spacing.tiny)
            })
            flex.addItem().shrink(0).define({ (flex) in
                flex.addItem(infoButton).width(30).height(30).alignSelf(.center)
            })
        }
        
        addSubview(mainContainer)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        mainContainer.flex.layout()
    }
}

you can assume BaseView is a regular UIView and Dimen.spacing.tiny is just a CGFloat constant

Button size seems to be larger than intrinsic size

I have a view with a containerView. There are two UILabels and a UIButton added to containerView, named titleLabel0 with text "000000...", titleLabel1 with text "1111111...", button0 with text "222222...". Layout is shown in image below. I wonder why the button0's size is not the same as its titleLabel's ?
image

In addition, my layout code is:

self.addSubview(containerView)
self.containerView.flex.direction(.column).alignItems(.center).define { (flex) in
        flex.addItem(tipLabel0)
        flex.addItem(tipLabel1).marginTop(10)
        flex.addItem(button0).marginTop(40)
}
override func layoutSubviews() {
        super.layoutSubviews()
        self.containerView.pin.width(100%)
        self.containerView.flex.layout(mode: .adjustHeight)
}

Update license to MIT

Following the recent update of Yoga license to MIT shouldn't FlexLayout update the license of FlexLayout and PinLayout to MIT also.
It will be very much appreciated.

Need some help about layout wrap

I'm new to use FlexLayout, and I want to layout 2~9 imageViews (aspectRatio 1:1) like this:
image

But I try my best, not really exact:
image

My code is here, hope you can give me some solutionπŸ˜† :

import UIKit
import FlexLayout
import PinLayout

class TestView: UIView {
    fileprivate let rootFlexContainer = UIView()
    
    init() {
        super.init(frame: .zero)
        backgroundColor = .white
        rootFlexContainer.backgroundColor = .yellow
        addSubview(rootFlexContainer)
        
        var picViews = [UIImageView]()
        for _ in 0..<9 {
            let imageView = UIImageView(image: UIImage(named: "method"))
            imageView.contentMode = .scaleAspectFill
            imageView.clipsToBounds = true
            picViews.append(imageView)
            rootFlexContainer.addSubview(imageView)
        }
        
        rootFlexContainer.flex.direction(.row).wrap(.wrap)
            .marginLeft(50).marginTop(100).define { flex in
            for (i, imgV) in picViews.enumerated() {
                flex.addItem(imgV).width(30%).aspectRatio(1)
                if i % 3 > 0 { // 右2εˆ—
                    imgV.flex.marginLeft(10)
                }
                if i / 3 > 0 { // δΈ‹2葌
                    imgV.flex.marginTop(10)
                }
            }
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        rootFlexContainer.pin.top().horizontally().width(87%)
        rootFlexContainer.flex.layout(mode: .adjustHeight)
    }
}

tvOS support and Podspec

I did see some references to tvOS in the code, but the Podspec doesn't declare its support for tvOS. Is this omission on purpose? Not being ready for tvOS for example?

Preprocessor macros

Hi!

I have an issue with preprocessor macros, such as FLEXLAYOUT_USE_CARTHAGE. There is situations when I cannot set them, eg: in swift playgrounds.

I just removed them and everything works fine. But I have a question why you are using them at all? I mean what are the cases when we need to import Yoga instead of YogaKit?

I think those preprocessor macros should be removed. Or maybe you should revert them: without macros we should import YogaKit, with macro should import Yoga. Because it seems like YogaKit import is used in almost every case.

Thank you!

P.S. I can send a pull request if you wish.

macOS support?

Hi,

First off, wonderful library.

Was wondering if you plan to add support for macOS similar to PinLayout having support for macOS?

Nice work! May I ask some questions?

I read about YogaKit and your FlexLayout recently and I found that there is rarely a detail example or a guide to use it in normal development. I'm interesting in Yoga and FlexLayout and I consider two questions if I choose to import it in my project:

  1. How does YogaKit or FlexLayout calculate cell heights in tableview or collectionview?
  2. How to use YogaKit or FlexLayout to do animations?

Some concerns about this project

FlexLayout is awesome, I like flexbox, and thanks to Yoga, also thank you for this opensource project, to bring this nice wrapper of Yoga, but I have some concerns about this project

  1. Swift is changing, with a lot of break changes every year, do you have any plan or roadmap to switch to the latest Swift version?
  2. For a framework's user, it's good if the framework has no bug, but it's impossible, so I want to know will you fully support the user's issues, feature request etc, this is important to me to choose a framework to use in the production environment.

Thank you very much.

Shrink and Expand the UIView with its child UIView components shrinking as well through PanGesture.

Hey hie thanks for the Awesome Library =D .

So there's a small problem which I'm facing
I was able to add a pan gesture in the View which is inherited from BaseView in ViewController inherited from BAseViewController . (Followed the same approach which is in the Example code of the library swift).

The below gif shows my requirements.
This thing is done from storyboard I'm trying it using FlexLayout.

So here(in the gif) I added the priorities to UIVIew with Autolayout then made an IBoutlet of NSLayoutConstraint
so when I swipe up using PAN gesture the view Expands and while sliding down the view shrinks (so as the constraints.constant value). So all the sliding up and down is done on that Iboutlet of NSLayoutConstraint.constant value (I mean I modify the value so the view changes its height with :usingSpringWithDamping effect)

imageedit_3_3530390270

But in FlexLayout I Couldn't get the constraints.constant value . I know FlexLayout lays out the view.. but How to achieve the above scenario with FlexLayout.

Looking for immediate help.
Thanks =)

[P.S. Sorry for hiding the details, there are some copyright thingy issues.]

Error add Carthage

Hello. Could not check before. Found an error

/Carthage/Build/iOS/YogaKit.framework/Headers/YGLayout.h:21:13: error: 'yoga/YGEnums.h' file not found #import <yoga/YGEnums.h>

#import <yoga/YGEnums.h> 'yoga/YGEnums.h' file not found

Question marginBottom()

Hi @lucdion. When we hide the object with selec.flex.isIncludedInLayout (false), it disappears, but its marginBottom (8) remains, and afterwards there is a large blank if there are many such objects. How to hide an object completely with all its indents ?

How to set an absolute item to parent view's center?

Hmmmm....I'm studying this framework, and I don't know how to set the yellow view to the view's center (horizontal & vertical) when it's being position(.absolute) mode, could you please give me some solution? πŸ˜‰

image

import UIKit
import FlexLayout

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupSubviews()
    }

    fileprivate func setupSubviews() {
        let imageView = UIImageView()
        imageView.backgroundColor = .cyan
        
        let seg = UISegmentedControl(items: ["Intro", "FlexLayout", "PinLayout"])
        
        let label1 = UILabel()
        label1.numberOfLines = 0
        label1.text = "FlexBox Layouting is simple, powerful and fast."
        
        let label2 = UILabel()
        label2.numberOfLines = 0
        label2.text = "FlexLayout syntax is concise and chainable."
        
        let label3 = UILabel()
        label3.numberOfLines = 0
        label3.text = "FlexLayout/yoga is incredibly fast, its even faster than manual layout."
        
        
        view.flex.padding(10).addItem().direction(.row).define { flex in
            flex.addItem(imageView).width(100).height(80)
            flex.addItem().marginLeft(10).shrink(1).define({ flex in
                flex.addItem(seg)
                flex.addItem(label1).marginTop(15)
                flex.addItem(label2).marginTop(15)
            })
        }
        // separator
        view.flex.addItem().marginTop(15).height(1).backgroundColor(.lightGray)
        view.flex.addItem(label3).marginTop(15)
        
        // absolute
        view.flex.addItem().size(100).position(.absolute).alignSelf(.center).top(200).backgroundColor(.yellow)
    }    
   
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        view.flex.layout()
    }
}

How does UIImageView size work?

I have a question about UIImageView's size, look through the project there does not have UIImageView related special things, but when set an image to UIImageView, the UIImageView auto have a size, as Apple's document says, set image will not set the UIImageView's size but call sie sizeToFit method to set the size, so my question is how the UIImageView's size work in Yoga?

Addtionly, I have a situation that I want to add a button in a UIImageView object, but after added the button, the image resize to the button's size, not keep the image object's size, how to solve it? here is my code

flex.addItem().direction(.row).padding(10).define({ (flex) in
    let imageView = UIImageView()
    imageView.image = UIImage(named: "ui-icons_2e83ff_256x240")
    flex.addItem(imageView).define({ (flex) in
        flex.alignItems(.center)
        flex.justifyContent(.center)
        
        let button = UIButton()
        flex.addItem(button).backgroundColor(.red).define({ (flex) in
            flex.width(50)
            flex.height(50)
        })
    })
})

Thank you very much.

Can a constraint be removed?

Hello. I want to ask a question. I have an UIImageView as this:

imageView.flex.size(someSize)

If I don't want the size constraint in some conditions and use imageView's intrinsic size, how can I remove the size constraints to the imageView?

Adding Dynamic Content to UITableViewCell

Hi again.

I'm trying to update my UITableViewCell with a dynamic number of views after it has been fetched from the database. The layout works fine (I love it) when I run it with fixed content that is available when the cell is initiated.

Basically I retrieve some tasks, and reload the table, calling configure(_ ...) with the data in the cellForRow
Other code omitted for simplicity

fileprivate var tasks: [SomeRandomObject] = []
private func setupFlexContainer() {
        contentView.flex.define { flex in
            // Green Container
            flex.addItem(titleContainer)
                .padding(padding)
                .alignItems(.stretch)
                .backgroundColor(.green)
                .define { flexTitleContainer in
                    flexTitleContainer.addItem(exerciseLabel)
                    flexTitleContainer.addItem(exerciseName).marginTop(8).grow(1).shrink(1)
                }
            // Exercise row
                for task in tasks {
                    flex.addItem()
                        .direction(.row)
                        .padding(padding)
                        .define { nameRow in
                            nameRow.addItem(generateIcon(for: task)).size(30).aspectRatio(1)
                            nameRow.addItem(generateLabel(for: task)).grow(1).marginLeft(16)
                        }
                }

            flex.addItem(acceptButton)
                .backgroundColor(.red)
                .height(50)
                .marginHorizontal(padding)
            
            flex.addItem(descriptionLabel)
                .alignSelf(.center)
                .marginBottom(padding)
                .marginTop(8)
        }
    }

func configure(_ exerciseTasks: [SomeRandomObject]) {
        tasks = exerciseTasks
        contentView.flex.markDirty()
        setNeedsLayout()
 }
    
override func layoutSubviews() {
        super.layoutSubviews()
        layout()
 }
    
fileprivate func layout() {
        contentView.flex.layout(mode: .adjustHeight)
}
    
override func sizeThatFits(_ size: CGSize) -> CGSize {
        contentView.pin.width(size.width)
        layout()
        return contentView.frame.size
}

However, I can't get view to relayout when the tasks has been filled with objects

Any help is appreciated.

Best,

Carthage

Please add the installation framework with Carthage

Combining FlexLayout & PinLayout - Check

Hi, I decided to try FlexLayout / PinLayout and have some questions about combining them and the workflow of "layers" and nested views.

Below is a super ugly sketch of the desired outcome:
export

It's a UITableViewCell containing:

  • One container (red): Which holds the row containing:

    • One circular UIView: (white) with green border
      • The circular UIView holds an UIImageView
    • One multi line label that scales
  • Two lines (Green): From the top of the cell (no margin) to the top of the circular container and from the bottom of the cell to the bottom of the circular container

This was my approach after some mixing, checking your UITableView sample:
FlexLayout:

  • Add a container with margin or padding, holding the row of items
  • First item in row, add a rounded UIView with padding and call addItem on it to add the imageview within
  • Add the multi line label to the container

Pin:
Add two UIViews and pin one to top, topCenter of the imageContainer while pinning the other one to bottom and bottomCenter of the imageContainer

(The red container is in reality transparent)

fileprivate let iconImageView = UIImageView()
fileprivate let nameLabel = UILabel()
fileprivate let imageContainer = UIView()
fileprivate let topLine = UIView()
fileprivate let bottomLine = UIView()
fileprivate let containerView = UIView()
let padding: CGFloat = 16

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    selectionStyle = .none
    separatorInset = .zero
    iconImageView.contentMode = .scaleAspectFit
    contentView.backgroundColor = .white
    containerView.backgroundColor = .clear
    nameLabel.font = .getFont()
    nameLabel.numberOfLines = 0
    designLines()
    addLines()
    containerView.flex.define { (flex) in
        flex.addItem().direction(.row).padding(padding).define({ (flex) in
        flex.addItem(imageContainer).size(40).alignSelf(.center).padding(5)
            .addItem(iconImageView).size(30).aspectRatio(1)
            flex.addItem(nameLabel).marginLeft(padding).grow(1).shrink(1)
        })
    }
    addSubview(containerView)
}
private func addLines() {
    contentView.addSubview(topLine)
    contentView.addSubview(bottomLine)
}
private func designLines() {
    topLine.backgroundColor = .green
    bottomLine.backgroundColor = .green
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

func configure(_ text: String) {
    nameLabel.text = text
    nameLabel.flex.markDirty()
}

override func layoutSubviews() {
    super.layoutSubviews()
    imageContainer.setupCircleView(backgroundColor: .white, borderThickness: 2.0, borderColor: .green)
    contentView.flex.layout(mode: .adjustHeight)
}

// MARK: - Pin the lines to top / bottom of the cell and centered by imageContainer
private func pinLines() {
    topLine.pin.top().bottomCenter(to: imageContainer.anchor.topCenter).width(2)
    bottomLine.pin.bottom().topCenter(to: imageContainer.anchor.bottomCenter).width(2)
}

fileprivate func layout(_ size: CGSize) {
    containerView.pin.width(size.width)
    containerView.flex.layout(mode: .adjustHeight)
    pinLines()
}

override func sizeThatFits(_ size: CGSize) -> CGSize {
    layout(size)
    return containerView.frame.size
}

}

Ideally I'd go with margin on the containerView but it ended up wonky, and right now the bottom green line isn't showing.

Is this a sane approach to layout this type of view or do you have a better suggestion?

Best,

Cannot access flex.view in 1.3.4

Per documentation:

It is possible to access the flex items's UIView using flex.view. This is particularly useful when using flex.define() method.

1.3.4 eliminates that by making flex.view a private method alongside fixing the retain cycle issue. This is a breaking change to the API that I don't think should be happening on a ..z version bump.

It's really convenient to attach an extension to Flex class to do stuff like drop shadow, borders in a chainable way--it makes view descriptions very declarative. Would prefer that we don't make this var private -- developers can easily read the weak tag and understand the limitations there.

Question: Different Configurations With FlexLayout

Hi, I was having trouble setting up something like this:

screen shot 2017-10-17 at 9 56 22 am

I always seem to have the left text pushing the right text outside of the box (overflow?)
My code was basically this:

flex.addItem().direction(.row).define { flex in
   flex.addItem(text1)
   flex.addItem(text2)
}

I also tried different combinations of positioning, but without much luck. Any advice?

Edit - is there a way to maybe divide the flex box into percentage proportions?
link maybe this
screen shot 2017-10-17 at 10 04 28 am

That way, i have multiple sections with different kinds of setup. I am not sure if you already have things that can accomplish this.

What am I do wrong?

1

textView.flex.direction(.column).padding(UI.Cards.inset).justifyContent(.center).define { flex in
    
  flex.addItem(section)   
  flex.addItem().direction(.rowReverse).position(.absolute).left(UI.Cards.inset).bottom(UI.Cards.inset).right(UI.Cards.inset).justifyContent(.spaceBetween).define { flex in
    
    flex.addItem(button).height(28).maxWidth(50%).grow(1).position(.absolute).right(0).bottom(0)
    flex.addItem().direction(.column).define {

       flex.addItem(title).shrink(1)
       flex.addItem(subtitle).shrink(1)
    }
  }
}

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.