public class

Flow

extends VirtualLayout

 java.lang.Object

↳View

androidx.constraintlayout.widget.ConstraintHelper

androidx.constraintlayout.widget.VirtualLayout

↳androidx.constraintlayout.helper.widget.Flow

Gradle dependencies

compile group: 'androidx.constraintlayout', name: 'constraintlayout', version: '2.2.0-alpha01'

  • groupId: androidx.constraintlayout
  • artifactId: constraintlayout
  • version: 2.2.0-alpha01

Artifact androidx.constraintlayout:constraintlayout:2.2.0-alpha01 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.constraintlayout:constraintlayout com.android.support.constraint:constraint-layout

Overview

Flow VirtualLayout. Added in 2.0 Allows positioning of referenced widgets horizontally or vertically, similar to a Chain. The elements referenced are indicated via constraint_referenced_ids, as with other ConstraintHelper implementations. Those referenced widgets are then laid out by the Flow virtual layout in three possible ways:

  • wrap none : simply create a chain out of the referenced elements
  • wrap chain : create multiple chains (one after the other) if the referenced elements do not fit
  • wrap aligned : similar to wrap chain, but will align the elements by creating rows and columns
As VirtualLayouts are ConstraintHelpers, they are normal views; you can thus treat them as such, and setting up constraints on them (position, dimension) or some view attributes (background, padding) will work. The main difference between VirtualLayouts and ViewGroups is that:
  • VirtualLayout keep the hierarchy flat
  • Other views can thus reference / constrain to not only the VirtualLayout, but also the views laid out by the VirtualLayout
  • VirtualLayout allow on the fly behavior modifications (e.g. for Flow, changing the orientation)

flow_wrapMode = "none"

This will simply create an horizontal or vertical chain out of the referenced widgets. This is the default behavior of Flow. XML attributes that are allowed in this mode:
  • flow_horizontalStyle = "spread|spread_inside|packed"
  • flow_verticalStyle = "spread|spread_inside|packed"
  • flow_horizontalBias = "float"
  • flow_verticalBias = "float"
  • flow_horizontalGap = "dimension"
  • flow_verticalGap = "dimension"
  • flow_horizontalAlign = "start|end"
  • flow_verticalAlign = "top|bottom|center|baseline
While the elements are laid out as a chain in the orientation defined, the way they are laid out in the other dimension is controlled by flow_horizontalAlign and flow_verticalAlign attributes.

flow_wrapMode = "chain"

Similar to wrap none in terms of creating chains, but if the referenced widgets do not fit the horizontal or vertical dimension (depending on the orientation picked), they will wrap around to the next line / column. XML attributes are the same same as in wrap_none, with the addition of attributes specifying chain style and chain bias applied to the first chain. This way, it is possible to specify different chain behavior between the first chain and the rest of the chains eventually created.
  • flow_firstHorizontalStyle = "spread|spread_inside|packed"
  • flow_firstVerticalStyle = "spread|spread_inside|packed"
  • flow_firstHorizontalBias = "float"
  • flow_firstVerticalBias = "float"
One last important attribute is flow_maxElementsWrap, which specify the number of elements before wrapping, regardless if they fit or not in the available space.

flow_wrapMode = "aligned"

Same XML attributes as for WRAP_CHAIN, with the difference that the elements are going to be laid out in a set of rows and columns instead of chains. The attribute specifying chains style and bias are thus not going to be applied.

Summary

Fields
public static final intCHAIN_PACKED

public static final intCHAIN_SPREAD

public static final intCHAIN_SPREAD_INSIDE

public static final intHORIZONTAL

public static final intHORIZONTAL_ALIGN_CENTER

public static final intHORIZONTAL_ALIGN_END

public static final intHORIZONTAL_ALIGN_START

public static final intVERTICAL

public static final intVERTICAL_ALIGN_BASELINE

public static final intVERTICAL_ALIGN_BOTTOM

public static final intVERTICAL_ALIGN_CENTER

public static final intVERTICAL_ALIGN_TOP

public static final intWRAP_ALIGNED

public static final intWRAP_CHAIN

public static final intWRAP_NONE

from ConstraintHelpermCount, mHelperWidget, mIds[], mMap, mReferenceIds, mReferenceTags, mUseViewMeasure, myContext
Constructors
publicFlow(Context context)

publicFlow(Context context, AttributeSet attrs)

publicFlow(Context context, AttributeSet attrs, int defStyleAttr)

Methods
protected voidinit(AttributeSet attrs)

public voidloadParameters(ConstraintSet.Constraint constraint, HelperWidget child, ConstraintLayout.LayoutParams layoutParams, <any> mapIdToWidget)

protected voidonMeasure(int widthMeasureSpec, int heightMeasureSpec)

public voidonMeasure(VirtualLayout layout, int widthMeasureSpec, int heightMeasureSpec)

public voidresolveRtl(ConstraintWidget widget, boolean isRtl)

public voidsetFirstHorizontalBias(float bias)

Similar to setHorizontalBias(), but only applied to the first chain.

public voidsetFirstHorizontalStyle(int style)

Similar to setHorizontalStyle(), but only applies to the first chain.

public voidsetFirstVerticalBias(float bias)

Similar to setVerticalBias(), but only applied to the first chain.

public voidsetFirstVerticalStyle(int style)

Similar to setVerticalStyle(), but only applies to the first chain.

public voidsetHorizontalAlign(int align)

Set up the horizontal alignment of the elements in the layout, if the layout orientation is set to Flow.VERTICAL Can be either: Flow.HORIZONTAL_ALIGN_START Flow.HORIZONTAL_ALIGN_END Flow.HORIZONTAL_ALIGN_CENTER

public voidsetHorizontalBias(float bias)

Set the horizontal bias applied to the chain

public voidsetHorizontalGap(int gap)

Set up the horizontal gap between elements

public voidsetHorizontalStyle(int style)

Set horizontal chain style.

public voidsetLastHorizontalBias(float bias)

Set the bias of the last Horizontal column.

public voidsetLastHorizontalStyle(int style)

Set the style of the last Horizontal column.

public voidsetLastVerticalBias(float bias)

Set the bias of the last vertical row.

public voidsetLastVerticalStyle(int style)

Set the style of the last vertical row.

public voidsetMaxElementsWrap(int max)

Set up the maximum number of elements before wrapping.

public voidsetOrientation(int orientation)

Set the orientation of the layout

public voidsetPadding(int padding)

Set padding around the content

public voidsetPaddingBottom(int paddingBottom)

Set padding bottom around the content

public voidsetPaddingLeft(int paddingLeft)

Set padding left around the content

public voidsetPaddingRight(int paddingRight)

Set padding right around the content

public voidsetPaddingTop(int paddingTop)

Set padding top around the content

public voidsetVerticalAlign(int align)

Set up the vertical alignment of the elements in the layout, if the layout orientation is set to Flow.HORIZONTAL Can be either: Flow.VERTICAL_ALIGN_TOP Flow.VERTICAL_ALIGN_BOTTOM Flow.VERTICAL_ALIGN_CENTER Flow.VERTICAL_ALIGN_BASELINE

public voidsetVerticalBias(float bias)

Set the vertical bias applied to the chain

public voidsetVerticalGap(int gap)

Set up the vertical gap between elements

public voidsetVerticalStyle(int style)

Set vertical chain style.

public voidsetWrapMode(int mode)

Set wrap mode for the layout.

from VirtualLayoutapplyLayoutFeaturesInConstraintSet, onAttachedToWindow, setElevation, setVisibility
from ConstraintHelperaddView, applyLayoutFeatures, applyLayoutFeatures, containsId, getReferencedIds, getViews, indexFromId, onDraw, removeView, setIds, setReferencedIds, setReferenceTags, setTag, updatePostConstraints, updatePostLayout, updatePostMeasure, updatePreDraw, updatePreLayout, updatePreLayout, validateParams
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public static final int HORIZONTAL

public static final int VERTICAL

public static final int WRAP_NONE

public static final int WRAP_CHAIN

public static final int WRAP_ALIGNED

public static final int CHAIN_SPREAD

public static final int CHAIN_SPREAD_INSIDE

public static final int CHAIN_PACKED

public static final int HORIZONTAL_ALIGN_START

public static final int HORIZONTAL_ALIGN_END

public static final int HORIZONTAL_ALIGN_CENTER

public static final int VERTICAL_ALIGN_TOP

public static final int VERTICAL_ALIGN_BOTTOM

public static final int VERTICAL_ALIGN_CENTER

public static final int VERTICAL_ALIGN_BASELINE

Constructors

public Flow(Context context)

public Flow(Context context, AttributeSet attrs)

public Flow(Context context, AttributeSet attrs, int defStyleAttr)

Methods

public void resolveRtl(ConstraintWidget widget, boolean isRtl)

Parameters:

widget:
isRtl:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

public void onMeasure(VirtualLayout layout, int widthMeasureSpec, int heightMeasureSpec)

Parameters:

layout:
widthMeasureSpec:
heightMeasureSpec:

public void loadParameters(ConstraintSet.Constraint constraint, HelperWidget child, ConstraintLayout.LayoutParams layoutParams, <any> mapIdToWidget)

Parameters:

constraint:
child:
layoutParams:
mapIdToWidget:

protected void init(AttributeSet attrs)

Parameters:

attrs:

public void setOrientation(int orientation)

Set the orientation of the layout

Parameters:

orientation: either Flow.HORIZONTAL or FLow.VERTICAL

public void setPadding(int padding)

Set padding around the content

Parameters:

padding:

public void setPaddingLeft(int paddingLeft)

Set padding left around the content

Parameters:

paddingLeft:

public void setPaddingTop(int paddingTop)

Set padding top around the content

Parameters:

paddingTop:

public void setPaddingRight(int paddingRight)

Set padding right around the content

Parameters:

paddingRight:

public void setPaddingBottom(int paddingBottom)

Set padding bottom around the content

Parameters:

paddingBottom:

public void setLastHorizontalStyle(int style)

Set the style of the last Horizontal column.

Parameters:

style: Flow.CHAIN_SPREAD, Flow.CHAIN_SPREAD_INSIDE, or Flow.CHAIN_PACKED

public void setLastVerticalStyle(int style)

Set the style of the last vertical row.

Parameters:

style: Flow.CHAIN_SPREAD, Flow.CHAIN_SPREAD_INSIDE, or Flow.CHAIN_PACKED

public void setLastHorizontalBias(float bias)

Set the bias of the last Horizontal column.

Parameters:

bias:

public void setLastVerticalBias(float bias)

Set the bias of the last vertical row.

Parameters:

bias:

public void setWrapMode(int mode)

Set wrap mode for the layout. Can be: Flow.WRAP_NONE (default) -- no wrap behavior, create a single chain Flow.WRAP_CHAIN -- if not enough space to fit the referenced elements, will create additional chains after the first one Flow.WRAP_ALIGNED -- if not enough space to fit the referenced elements, will wrap the elements, keeping them aligned (like a table)

Parameters:

mode:

public void setHorizontalStyle(int style)

Set horizontal chain style. Can be: Flow.CHAIN_SPREAD Flow.CHAIN_SPREAD_INSIDE Flow.CHAIN_PACKED

Parameters:

style:

public void setVerticalStyle(int style)

Set vertical chain style. Can be: Flow.CHAIN_SPREAD Flow.CHAIN_SPREAD_INSIDE Flow.CHAIN_PACKED

Parameters:

style:

public void setHorizontalBias(float bias)

Set the horizontal bias applied to the chain

Parameters:

bias: from 0 to 1

public void setVerticalBias(float bias)

Set the vertical bias applied to the chain

Parameters:

bias: from 0 to 1

public void setFirstHorizontalStyle(int style)

Similar to setHorizontalStyle(), but only applies to the first chain.

Parameters:

style:

public void setFirstVerticalStyle(int style)

Similar to setVerticalStyle(), but only applies to the first chain.

Parameters:

style:

public void setFirstHorizontalBias(float bias)

Similar to setHorizontalBias(), but only applied to the first chain.

Parameters:

bias:

public void setFirstVerticalBias(float bias)

Similar to setVerticalBias(), but only applied to the first chain.

Parameters:

bias:

public void setHorizontalAlign(int align)

Set up the horizontal alignment of the elements in the layout, if the layout orientation is set to Flow.VERTICAL Can be either: Flow.HORIZONTAL_ALIGN_START Flow.HORIZONTAL_ALIGN_END Flow.HORIZONTAL_ALIGN_CENTER

Parameters:

align:

public void setVerticalAlign(int align)

Set up the vertical alignment of the elements in the layout, if the layout orientation is set to Flow.HORIZONTAL Can be either: Flow.VERTICAL_ALIGN_TOP Flow.VERTICAL_ALIGN_BOTTOM Flow.VERTICAL_ALIGN_CENTER Flow.VERTICAL_ALIGN_BASELINE

Parameters:

align:

public void setHorizontalGap(int gap)

Set up the horizontal gap between elements

Parameters:

gap:

public void setVerticalGap(int gap)

Set up the vertical gap between elements

Parameters:

gap:

public void setMaxElementsWrap(int max)

Set up the maximum number of elements before wrapping.

Parameters:

max:

Source

/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package androidx.constraintlayout.helper.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.util.AttributeSet;
import android.util.SparseArray;

import androidx.constraintlayout.core.widgets.ConstraintWidget;
import androidx.constraintlayout.core.widgets.HelperWidget;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.constraintlayout.widget.R;
import androidx.constraintlayout.widget.VirtualLayout;

/**
 *
 * Flow VirtualLayout. <b>Added in 2.0</b>
 *
 * Allows positioning of referenced widgets horizontally or vertically, similar to a Chain.
 *
 * The elements referenced are indicated via constraint_referenced_ids, as with other
 * ConstraintHelper implementations.
 *
 * Those referenced widgets are then laid out by the Flow virtual layout in three possible ways:
 * <ul>
 *     <li><a href="#wrap_none">wrap none</a> : simply create a chain out of the
 *     referenced elements</li>
 *     <li><a href="#wrap_chain">wrap chain</a> : create multiple chains (one after the other)
 *     if the referenced elements do not fit</li>
 *     <li><a href="#wrap_aligned">wrap aligned</a> : similar to wrap chain, but will align the
 *     elements by creating rows and columns</li>
 * </ul>
 *
 * As VirtualLayouts are ConstraintHelpers, they are normal views; you can thus treat them as such,
 * and setting up constraints on them (position, dimension) or some view attributes
 * (background, padding) will work. The main difference between VirtualLayouts and ViewGroups is
 * that:
 * <ul>
 *     <li>VirtualLayout keep the hierarchy flat</li>
 *     <li>Other views can thus reference / constrain to not only the VirtualLayout, but also
 *     the views laid out by the VirtualLayout</li>
 *     <li>VirtualLayout allow on the fly behavior modifications
 *     (e.g. for Flow, changing the orientation)</li>
 * </ul>
 *
 * <h4 id="wrap_none">flow_wrapMode = "none"</h4>
 *
 * This will simply create an horizontal or vertical chain out of the referenced widgets.
 * This is the default behavior of Flow.
 *
 * XML attributes that are allowed in this mode:
 *
 * <ul>
 *     <li>flow_horizontalStyle = "spread|spread_inside|packed"</li>
 *     <li>flow_verticalStyle = "spread|spread_inside|packed"</li>
 *     <li>flow_horizontalBias = "<i>float</i>"</li>
 *     <li>flow_verticalBias = "<i>float</i>"</li>
 *     <li>flow_horizontalGap = "<i>dimension</i>"</li>
 *     <li>flow_verticalGap = "<i>dimension</i>"</li>
 *     <li>flow_horizontalAlign = "start|end"</li>
 *     <li>flow_verticalAlign = "top|bottom|center|baseline</li>
 * </ul>
 *
 * While the elements are laid out as a chain in the orientation defined, the way they are laid
 * out in the other dimension is controlled
 * by <i>flow_horizontalAlign</i> and <i>flow_verticalAlign</i> attributes.
 *
 * <h4 id="wrap_chain">flow_wrapMode = "chain"</h4>
 *
 * Similar to wrap none in terms of creating chains, but if the referenced widgets do not fit the
 * horizontal or vertical dimension (depending
 * on the orientation picked), they will wrap around to the next line / column.
 *
 * XML attributes are the same same as in wrap_none, with the addition of attributes specifying
 * chain style and chain bias applied to the first chain. This way, it is possible to specify
 * different chain behavior between the first chain and the rest of the chains eventually created.
 *
 * <ul>
 *     <li>flow_firstHorizontalStyle = "spread|spread_inside|packed"</li>
 *     <li>flow_firstVerticalStyle = "spread|spread_inside|packed"</li>
 *     <li>flow_firstHorizontalBias = "<i>float</i>"</li>
 *     <li>flow_firstVerticalBias = "<i>float</i>"</li>
 * </ul>
 *
 * One last important attribute is <i>flow_maxElementsWrap</i>, which specify the number
 * of elements before wrapping, regardless if they
 * fit or not in the available space.
 *
 * <h4 id="wrap_aligned">flow_wrapMode = "aligned"</h4>
 *
 * Same XML attributes as for WRAP_CHAIN, with the difference that the elements are going to be
 * laid out in a set of rows and columns instead of chains.
 * The attribute specifying chains style and bias are thus not going to be applied.
 */
public class Flow extends VirtualLayout {
    private static final String TAG = "Flow";

    private androidx.constraintlayout.core.widgets.Flow mFlow;

    public static final int HORIZONTAL = androidx.constraintlayout.core.widgets.Flow.HORIZONTAL;
    public static final int VERTICAL = androidx.constraintlayout.core.widgets.Flow.VERTICAL;
    public static final int WRAP_NONE = androidx.constraintlayout.core.widgets.Flow.WRAP_NONE;
    public static final int WRAP_CHAIN = androidx.constraintlayout.core.widgets.Flow.WRAP_CHAIN;
    public static final int WRAP_ALIGNED = androidx.constraintlayout.core.widgets.Flow.WRAP_ALIGNED;

    public static final int CHAIN_SPREAD = ConstraintWidget.CHAIN_SPREAD;
    public static final int CHAIN_SPREAD_INSIDE = ConstraintWidget.CHAIN_SPREAD_INSIDE;
    public static final int CHAIN_PACKED = ConstraintWidget.CHAIN_PACKED;

    public static final int HORIZONTAL_ALIGN_START =
            androidx.constraintlayout.core.widgets.Flow.HORIZONTAL_ALIGN_START;
    public static final int HORIZONTAL_ALIGN_END =
            androidx.constraintlayout.core.widgets.Flow.HORIZONTAL_ALIGN_END;
    public static final int HORIZONTAL_ALIGN_CENTER =
            androidx.constraintlayout.core.widgets.Flow.HORIZONTAL_ALIGN_CENTER;

    public static final int VERTICAL_ALIGN_TOP =
            androidx.constraintlayout.core.widgets.Flow.VERTICAL_ALIGN_TOP;
    public static final int VERTICAL_ALIGN_BOTTOM =
            androidx.constraintlayout.core.widgets.Flow.VERTICAL_ALIGN_BOTTOM;
    public static final int VERTICAL_ALIGN_CENTER =
            androidx.constraintlayout.core.widgets.Flow.VERTICAL_ALIGN_CENTER;
    public static final int VERTICAL_ALIGN_BASELINE =
            androidx.constraintlayout.core.widgets.Flow.VERTICAL_ALIGN_BASELINE;

    public Flow(Context context) {
        super(context);
    }

    public Flow(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public Flow(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * @DoNotShow
     *
     * @param widget
     * @param isRtl
     */
    @Override
    public void resolveRtl(ConstraintWidget widget, boolean isRtl) {
        mFlow.applyRtl(isRtl);
    }

    @SuppressLint("WrongCall")
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        onMeasure(mFlow, widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * @DoNotShow
     *
     * @param layout
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    public void onMeasure(androidx.constraintlayout.core.widgets.VirtualLayout layout,
                          int widthMeasureSpec,
                          int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        if (layout != null) {
            layout.measure(widthMode, widthSize, heightMode, heightSize);
            setMeasuredDimension(layout.getMeasuredWidth(), layout.getMeasuredHeight());
        } else {
            setMeasuredDimension(0, 0);
        }
    }

    /**
     * @DoNotShow
     *
     * @param constraint
     * @param child
     * @param layoutParams
     * @param mapIdToWidget
     */
    @Override
    public void loadParameters(ConstraintSet.Constraint constraint, HelperWidget child,
                               ConstraintLayout.LayoutParams layoutParams,
                               SparseArray<ConstraintWidget> mapIdToWidget) {
        super.loadParameters(constraint, child, layoutParams, mapIdToWidget);
        if (child instanceof androidx.constraintlayout.core.widgets.Flow) {
            androidx.constraintlayout.core.widgets.Flow flow =
                    (androidx.constraintlayout.core.widgets.Flow) child;
            if (layoutParams.orientation != -1) {
                flow.setOrientation(layoutParams.orientation);
            }
        }
    }

    /**
     * @DoNotShow
     *
     * @param attrs
     */
    @Override
    protected void init(AttributeSet attrs) {
        super.init(attrs);
        mFlow = new androidx.constraintlayout.core.widgets.Flow();
        if (attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs,
                    R.styleable.ConstraintLayout_Layout);
            final int n = a.getIndexCount();
            for (int i = 0; i < n; i++) {
                int attr = a.getIndex(i);
                if (attr == R.styleable.ConstraintLayout_Layout_android_orientation) {
                    mFlow.setOrientation(a.getInt(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_android_padding) {
                    mFlow.setPadding(a.getDimensionPixelSize(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_android_paddingStart) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        mFlow.setPaddingStart(a.getDimensionPixelSize(attr, 0));
                    }
                } else if (attr == R.styleable.ConstraintLayout_Layout_android_paddingEnd) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        mFlow.setPaddingEnd(a.getDimensionPixelSize(attr, 0));
                    }
                } else if (attr == R.styleable.ConstraintLayout_Layout_android_paddingLeft) {
                    mFlow.setPaddingLeft(a.getDimensionPixelSize(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_android_paddingTop) {
                    mFlow.setPaddingTop(a.getDimensionPixelSize(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_android_paddingRight) {
                    mFlow.setPaddingRight(a.getDimensionPixelSize(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_android_paddingBottom) {
                    mFlow.setPaddingBottom(a.getDimensionPixelSize(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_wrapMode) {
                    mFlow.setWrapMode(a.getInt(attr,
                            androidx.constraintlayout.core.widgets.Flow.WRAP_NONE));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_horizontalStyle) {
                    mFlow.setHorizontalStyle(a.getInt(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_verticalStyle) {
                    mFlow.setVerticalStyle(a.getInt(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_firstHorizontalStyle) {
                    mFlow.setFirstHorizontalStyle(a.getInt(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_lastHorizontalStyle) {
                    mFlow.setLastHorizontalStyle(a.getInt(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_firstVerticalStyle) {
                    mFlow.setFirstVerticalStyle(a.getInt(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_lastVerticalStyle) {
                    mFlow.setLastVerticalStyle(a.getInt(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_horizontalBias) {
                    mFlow.setHorizontalBias(a.getFloat(attr, 0.5f));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_firstHorizontalBias) {
                    mFlow.setFirstHorizontalBias(a.getFloat(attr, 0.5f));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_lastHorizontalBias) {
                    mFlow.setLastHorizontalBias(a.getFloat(attr, 0.5f));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_firstVerticalBias) {
                    mFlow.setFirstVerticalBias(a.getFloat(attr, 0.5f));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_lastVerticalBias) {
                    mFlow.setLastVerticalBias(a.getFloat(attr, 0.5f));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_verticalBias) {
                    mFlow.setVerticalBias(a.getFloat(attr, 0.5f));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_horizontalAlign) {
                    mFlow.setHorizontalAlign(a.getInt(attr,
                            androidx.constraintlayout.core.widgets.Flow.HORIZONTAL_ALIGN_CENTER));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_verticalAlign) {
                    mFlow.setVerticalAlign(a.getInt(attr,
                            androidx.constraintlayout.core.widgets.Flow.VERTICAL_ALIGN_CENTER));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_horizontalGap) {
                    mFlow.setHorizontalGap(a.getDimensionPixelSize(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_verticalGap) {
                    mFlow.setVerticalGap(a.getDimensionPixelSize(attr, 0));
                } else if (attr == R.styleable.ConstraintLayout_Layout_flow_maxElementsWrap) {
                    mFlow.setMaxElementsWrap(a.getInt(attr, -1));
                }
            }
            a.recycle();
        }

        mHelperWidget = mFlow;
        validateParams();
    }

    /**
     * Set the orientation of the layout
     *
     * @param orientation either Flow.HORIZONTAL or FLow.VERTICAL
     */
    public void setOrientation(int orientation) {
        mFlow.setOrientation(orientation);
        requestLayout();
    }

    /**
     * Set padding around the content
     *
     * @param padding
     */
    public void setPadding(int padding) {
        mFlow.setPadding(padding);
        requestLayout();
    }

    /**
     * Set padding left around the content
     *
     * @param paddingLeft
     */
    public void setPaddingLeft(int paddingLeft) {
        mFlow.setPaddingLeft(paddingLeft);
        requestLayout();
    }

    /**
     * Set padding top around the content
     *
     * @param paddingTop
     */
    public void setPaddingTop(int paddingTop) {
        mFlow.setPaddingTop(paddingTop);
        requestLayout();
    }

    /**
     * Set padding right around the content
     *
     * @param paddingRight
     */
    public void setPaddingRight(int paddingRight) {
        mFlow.setPaddingRight(paddingRight);
        requestLayout();
    }

    /**
     * Set padding bottom around the content
     *
     * @param paddingBottom
     */
    public void setPaddingBottom(int paddingBottom) {
        mFlow.setPaddingBottom(paddingBottom);
        requestLayout();
    }

    /**
     * Set the style of the last Horizontal column.
     * @param style Flow.CHAIN_SPREAD, Flow.CHAIN_SPREAD_INSIDE, or Flow.CHAIN_PACKED
     */
    public void setLastHorizontalStyle(int style) {
        mFlow.setLastHorizontalStyle(style);
        requestLayout();
    }

    /**
     * Set the style of the last vertical row.
     * @param style  Flow.CHAIN_SPREAD, Flow.CHAIN_SPREAD_INSIDE, or Flow.CHAIN_PACKED
     */
    public void setLastVerticalStyle(int style) {
        mFlow.setLastVerticalStyle(style);
        requestLayout();
    }

    /**
     * Set the bias of the last Horizontal column.
     * @param bias
     */
    public void setLastHorizontalBias(float bias) {
        mFlow.setLastHorizontalBias(bias);
        requestLayout();
    }

    /**
     * Set the bias of the last vertical row.
     * @param bias
     */
    public void setLastVerticalBias(float bias) {
        mFlow.setLastVerticalBias(bias);
        requestLayout();
    }

    /**
     * Set wrap mode for the layout. Can be:
     *
     * Flow.WRAP_NONE (default) -- no wrap behavior, create a single chain
     * Flow.WRAP_CHAIN -- if not enough space to fit the referenced elements,
     * will create additional chains after the first one
     * Flow.WRAP_ALIGNED -- if not enough space to fit the referenced elements,
     * will wrap the elements, keeping them aligned (like a table)
     *
     * @param mode
     */
    public void setWrapMode(int mode) {
        mFlow.setWrapMode(mode);
        requestLayout();
    }

    /**
     * Set horizontal chain style. Can be:
     *
     * Flow.CHAIN_SPREAD
     * Flow.CHAIN_SPREAD_INSIDE
     * Flow.CHAIN_PACKED
     *
     * @param style
     */
    public void setHorizontalStyle(int style) {
        mFlow.setHorizontalStyle(style);
        requestLayout();
    }

    /**
     * Set vertical chain style. Can be:
     *
     * Flow.CHAIN_SPREAD
     * Flow.CHAIN_SPREAD_INSIDE
     * Flow.CHAIN_PACKED
     *
     * @param style
     */
    public void setVerticalStyle(int style) {
        mFlow.setVerticalStyle(style);
        requestLayout();
    }

    /**
     * Set the horizontal bias applied to the chain
     *
     * @param bias from 0 to 1
     */
    public void setHorizontalBias(float bias) {
        mFlow.setHorizontalBias(bias);
        requestLayout();
    }

    /**
     * Set the vertical bias applied to the chain
     *
     * @param bias from 0 to 1
     */
    public void setVerticalBias(float bias) {
        mFlow.setVerticalBias(bias);
        requestLayout();
    }

    /**
     * Similar to setHorizontalStyle(), but only applies to the first chain.
     *
     * @param style
     */
    public void setFirstHorizontalStyle(int style) {
        mFlow.setFirstHorizontalStyle(style);
        requestLayout();
    }

    /**
     * Similar to setVerticalStyle(), but only applies to the first chain.
     *
     * @param style
     */
    public void setFirstVerticalStyle(int style) {
        mFlow.setFirstVerticalStyle(style);
        requestLayout();
    }

    /**
     * Similar to setHorizontalBias(), but only applied to the first chain.
     *
     * @param bias
     */
    public void setFirstHorizontalBias(float bias) {
        mFlow.setFirstHorizontalBias(bias);
        requestLayout();
    }

    /**
     * Similar to setVerticalBias(), but only applied to the first chain.
     *
     * @param bias
     */
    public void setFirstVerticalBias(float bias) {
        mFlow.setFirstVerticalBias(bias);
        requestLayout();
    }

    /**
     * Set up the horizontal alignment of the elements in the layout,
     * if the layout orientation is set to Flow.VERTICAL
     *
     * Can be either:
     * Flow.HORIZONTAL_ALIGN_START
     * Flow.HORIZONTAL_ALIGN_END
     * Flow.HORIZONTAL_ALIGN_CENTER
     *
     * @param align
     */
    public void setHorizontalAlign(int align) {
        mFlow.setHorizontalAlign(align);
        requestLayout();
    }

    /**
     * Set up the vertical alignment of the elements in the layout,
     * if the layout orientation is set to Flow.HORIZONTAL
     *
     * Can be either:
     * Flow.VERTICAL_ALIGN_TOP
     * Flow.VERTICAL_ALIGN_BOTTOM
     * Flow.VERTICAL_ALIGN_CENTER
     * Flow.VERTICAL_ALIGN_BASELINE
     *
     * @param align
     */
    public void setVerticalAlign(int align) {
        mFlow.setVerticalAlign(align);
        requestLayout();
    }

    /**
     * Set up the horizontal gap between elements
     *
     * @param gap
     */
    public void setHorizontalGap(int gap) {
        mFlow.setHorizontalGap(gap);
        requestLayout();
    }

    /**
     * Set up the vertical gap between elements
     *
     * @param gap
     */
    public void setVerticalGap(int gap) {
        mFlow.setVerticalGap(gap);
        requestLayout();
    }

    /**
     * Set up the maximum number of elements before wrapping.
     *
     * @param max
     */
    public void setMaxElementsWrap(int max) {
        mFlow.setMaxElementsWrap(max);
        requestLayout();
    }
}