compile group: 'androidx.constraintlayout', name: 'constraintlayout', version: '2.2.0-beta01'
Artifact androidx.constraintlayout:constraintlayout:2.2.0-beta01 it located at Google repository (https://maven.google.com/)
androidx.constraintlayout:constraintlayout com.android.support.constraint:constraint-layout
androidx.constraintlayout.widget.ConstraintSet android.support.constraint.ConstraintSet
ConstraintSet enables you create and save constraints and apply
them to an existing ConstraintLayout. For details about constraint
behaviour, see ConstraintLayout.
Calculate the size of a view in 0 dp by reducing the constrains gaps as much as possible
The horizontal orientation.
The vertical orientation.
Used to create a horizontal create guidelines.
The left side of a view.
The right side of a view.
The top of a view.
The bottom side of a view.
The baseline of the text in a view.
The left side of a view in left to right languages.
In right to left languages it corresponds to the right side of the view
The right side of a view in left to right languages.
In right to left languages it corresponds to the left side of the view
Circle reference from a view.
This will copy Constraints from the ConstraintLayout if it does not have parameters
Get the types associated with this ConstraintSet
The types mechanism allows you to tag the constraint set
with a series of string to define properties of a ConstraintSet
Set the types associated with this ConstraintSet
The types mechanism allows you to tag the constraint set
with a series of string to define properties of a ConstraintSet
Set the types associated with this ConstraintSet
The types mechanism allows you to tag the constraint set
with a series of string to define properties of a ConstraintSet
Copy the constraints from a layout.
Copy the constraints from a layout.
Copy the layout parameters of a ConstraintLayout.
Copy the layout parameters of a ConstraintLayout.
Apply the constraints to a ConstraintLayout.
Apply the constraints to a ConstraintLayout.
Fill in a ConstraintLayout LayoutParam based on the id.
Spaces a set of widgets vertically between the view topId and bottomId.
Widgets can be spaced with weights.
This operation sets all the related margins to 0.
Spaces a set of widgets horizontally between the view startID and endId.
Widgets can be spaced with weights.
This operation sets all the related margins to 0.
Centers the view horizontally relative to toView's position.
Centers the view horizontally relative to toView's position.
Centers the view vertically relative to toView's position.
Remove all constraints from this view.
Remove a constraint from this view.
Sets the margin.
Sets the gone margin.
Adjust the horizontal bias of the view (used with views constrained on left and right).
Adjust the vertical bias of the view (used with views constrained on left and right).
Constrains the views aspect ratio.
For Example a HD screen is 16 by 9 = 16/(float)9 = 1.777f.
Adjust the visibility of a view.
Adjust the alpha of a view.
return with the constraint set will apply elevation for the specified view.
set if elevation will be applied to the view.
Elevation logic is based on style and animation. By default it is not used because it would
lead to unexpected results.
Adjust the elevation of a view.
Adjust the post-layout rotation about the Z axis of a view.
Adjust the post-layout rotation about the X axis of a view.
Adjust the post-layout rotation about the Y axis of a view.
Adjust the post-layout scale in X of a view.
Adjust the post-layout scale in Y of a view.
Set X location of the pivot point around which the view will rotate and scale.
use Float.NaN to clear the pivot value.
Note: once an actual View has had its pivot set it cannot be cleared.
Set Y location of the pivot point around which the view will rotate and scale.
use Float.NaN to clear the pivot value.
Note: once an actual View has had its pivot set it cannot be cleared.
Set X,Y location of the pivot point around which the view will rotate and scale.
use Float.NaN to clear the pivot value.
Note: once an actual View has had its pivot set it cannot be cleared.
Adjust the post-layout X translation of a view.
Adjust the post-layout Y translation of a view.
Adjust the post-layout translation of a view.
Adjust the translation in Z of a view.
Sets the maximum height of the view. It is a dimension, It is only applicable if height is
#MATCH_CONSTRAINT}.
Sets the maximum width of the view. It is a dimension, It is only applicable if width is
#MATCH_CONSTRAINT}.
Sets the height of the view. It is a dimension, It is only applicable if height is
#MATCH_CONSTRAINT}.
Sets the width of the view. It is a dimension, It is only applicable if width is
#MATCH_CONSTRAINT}.
Sets the width of the view as a percentage of the parent.
Sets the height of the view as a percentage of the parent.
Sets how the height is calculated ether MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD.
Default is spread.
Sets how the width is calculated ether MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD.
Default is spread.
Sets how the height is calculated ether MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD.
Default is spread.
Sets how the width is calculated ether MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD.
Default is spread.
The child's weight that we can use to distribute the available horizontal space
in a chain, if the dimension behaviour is set to MATCH_CONSTRAINT
The child's weight that we can use to distribute the available vertical space
in a chain, if the dimension behaviour is set to MATCH_CONSTRAINT
How the elements of the horizontal chain will be positioned. if the dimension
behaviour is set to MATCH_CONSTRAINT. The possible values are:
How the elements of the vertical chain will be positioned. in a chain, if the dimension
behaviour is set to MATCH_CONSTRAINT
Adds a view to a horizontal chain.
Adds a view to a horizontal chain.
Adds a view to a vertical chain.
Removes a view from a vertical chain.
This assumes the view is connected to a vertical chain.
Its behaviour is undefined if not part of a vertical chain.
Removes a view from a horizontal chain.
This assumes the view is connected to a horizontal chain.
Its behaviour is undefined if not part of a horizontal chain.
Creates a ConstraintLayout virtual object. Currently only horizontal or vertical GuideLines.
Creates a ConstraintLayout Barrier object.
Set the guideline's distance form the top or left edge.
Set a guideline's distance to end.
Set a Guideline's percent.
get the reference id's of a helper.
sets the reference id's of a barrier.
Load a constraint set from a constraintSet.xml file.
Note. Do NOT use this to load a layout file.
It will fail silently as there is no efficient way to differentiate.
Enforce id are required for all ConstraintLayout children to use ConstraintSet.
default = true;
Enforce id are required for all ConstraintLayout children to use ConstraintSet.
default = true;
If true perform validation checks when parsing ConstraintSets
This will slow down parsing and should only be used for debugging
If true perform validation checks when parsing ConstraintSets
This will slow down parsing and should only be used for debugging
/*
* Copyright (C) 2016 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.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Color;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.util.Xml;
import android.view.LayoutInflater;
import android.view.View;
import androidx.constraintlayout.core.motion.utils.Easing;
import androidx.constraintlayout.core.widgets.ConstraintWidget;
import androidx.constraintlayout.core.widgets.HelperWidget;
import androidx.constraintlayout.motion.widget.Debug;
import androidx.constraintlayout.motion.widget.MotionLayout;
import androidx.constraintlayout.motion.widget.MotionScene;
import androidx.constraintlayout.widget.ConstraintAttribute.AttributeType;
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
/**
* Defines a set of constraints to be used with {@link ConstraintLayout}.
*
* <p>{@code ConstraintSet} enables you create and save constraints and apply
* them to an existing {@code ConstraintLayout}. For details about constraint
* behaviour, see {@link ConstraintLayout}.</p>
*
* <p>{@code ConstraintsSet} can be created in various ways:</p>
* <ul>
* <li>Manually —
* {@code c = new ConstraintSet(); c.connect(...);}</li>
* <li>From an {@code R.layout.*} object —
* {@code c.clone(context, R.layout.layout1);}</li>
* <li>From a {@code ConstraintLayout} —
* {@code c.clone(constraintLayout);}</li>
* </ul>
*
* <p>Example code:</p>
* <pre>import android.content.Context;
* import android.os.Bundle;
* import android.support.constraint.ConstraintLayout;
* import android.support.constraint.ConstraintSet;
* import android.support.transition.TransitionManager;
* import android.support.v7.app.AppCompatActivity;
* import android.view.View;
*
* public class MainActivity extends AppCompatActivity {
* ConstraintSet mConstraintSet1 = new ConstraintSet(); // Create a ConstraintSet.
* ConstraintSet mConstraintSet2 = new ConstraintSet(); // Create a ConstraintSet.
* ConstraintLayout mConstraintLayout; // Cache the ConstraintLayout.
* boolean mOld = true;
*
*
* protected void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
* Context context = this;
* mConstraintSet2.clone(context, R.layout.state2); // Get constraints from layout.
* setContentView(R.layout.state1);
* mConstraintLayout = (ConstraintLayout) findViewById(R.id.activity_main);
* mConstraintSet1.clone(mConstraintLayout); // Get constraints from ConstraintSet.
* }
*
* public void foo(View view) {
* TransitionManager.beginDelayedTransition(mConstraintLayout);
* if (mOld = !mOld) {
* mConstraintSet1.applyTo(mConstraintLayout); // Set new constraints.
* } else {
* mConstraintSet2.applyTo(mConstraintLayout); // Set new constraints.
* }
* }
* }</pre>
*/
public class ConstraintSet {
private static final String TAG = "ConstraintSet";
private static final String ERROR_MESSAGE = "XML parser error must be within a Constraint ";
private static final int INTERNAL_MATCH_PARENT = -1;
private static final int INTERNAL_WRAP_CONTENT = -2;
private static final int INTERNAL_MATCH_CONSTRAINT = -3;
private static final int INTERNAL_WRAP_CONTENT_CONSTRAINED = -4;
private boolean mValidate;
public String mIdString;
public String derivedState = "";
private String [] mMatchLabels = new String[0];
public static final int ROTATE_NONE = 0;
public static final int ROTATE_PORTRATE_OF_RIGHT = 1;
public static final int ROTATE_PORTRATE_OF_LEFT = 2;
public static final int ROTATE_RIGHT_OF_PORTRATE = 3;
public static final int ROTATE_LEFT_OF_PORTRATE = 4;
public int mRotate = 0;
private HashMap<String, ConstraintAttribute> mSavedAttributes = new HashMap<>();
/**
* require that all views have IDs to function
*/
private boolean mForceId = true;
/**
* Used to indicate a parameter is cleared or not set
*/
public static final int UNSET = LayoutParams.UNSET;
/**
* Dimension will be controlled by constraints
*/
public static final int MATCH_CONSTRAINT = ConstraintLayout.LayoutParams.MATCH_CONSTRAINT;
/**
* Dimension will set by the view's content
*/
public static final int WRAP_CONTENT = ConstraintLayout.LayoutParams.WRAP_CONTENT;
/**
* How to calculate the size of a view in 0 dp by using its wrap_content size
*/
public static final int MATCH_CONSTRAINT_WRAP =
ConstraintLayout.LayoutParams.MATCH_CONSTRAINT_WRAP;
/**
* Calculate the size of a view in 0 dp by reducing the constrains gaps as much as possible
*/
public static final int MATCH_CONSTRAINT_SPREAD =
ConstraintLayout.LayoutParams.MATCH_CONSTRAINT_SPREAD;
public static final int MATCH_CONSTRAINT_PERCENT =
ConstraintLayout.LayoutParams.MATCH_CONSTRAINT_PERCENT;
/**
* References the id of the parent.
* Used in:
* <ul>
* <li>{@link #connect(int, int, int, int, int)}</li>
* <li>{@link #center(int, int, int, int, int, int, int, float)}</li>
* </ul>
*/
public static final int PARENT_ID = ConstraintLayout.LayoutParams.PARENT_ID;
/**
* The horizontal orientation.
*/
public static final int HORIZONTAL = ConstraintLayout.LayoutParams.HORIZONTAL;
/**
* The vertical orientation.
*/
public static final int VERTICAL = ConstraintLayout.LayoutParams.VERTICAL;
/**
* Used to create a horizontal create guidelines.
*/
public static final int HORIZONTAL_GUIDELINE = 0;
/**
* Used to create a vertical create guidelines.
* see {@link #create(int, int)}
*/
public static final int VERTICAL_GUIDELINE = 1;
/**
* This view is visible.
* Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
* android:visibility}.
*/
public static final int VISIBLE = View.VISIBLE;
/**
* This view is invisible, but it still takes up space for layout purposes.
* Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
* android:visibility}.
*/
public static final int INVISIBLE = View.INVISIBLE;
/**
* This view is gone, and will not take any space for layout
* purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
* android:visibility}.
*/
public static final int GONE = View.GONE;
/**
* The left side of a view.
*/
public static final int LEFT = ConstraintLayout.LayoutParams.LEFT;
/**
* The right side of a view.
*/
public static final int RIGHT = ConstraintLayout.LayoutParams.RIGHT;
/**
* The top of a view.
*/
public static final int TOP = ConstraintLayout.LayoutParams.TOP;
/**
* The bottom side of a view.
*/
public static final int BOTTOM = ConstraintLayout.LayoutParams.BOTTOM;
/**
* The baseline of the text in a view.
*/
public static final int BASELINE = ConstraintLayout.LayoutParams.BASELINE;
/**
* The left side of a view in left to right languages.
* In right to left languages it corresponds to the right side of the view
*/
public static final int START = ConstraintLayout.LayoutParams.START;
/**
* The right side of a view in left to right languages.
* In right to left languages it corresponds to the left side of the view
*/
public static final int END = ConstraintLayout.LayoutParams.END;
/**
* Circle reference from a view.
*/
public static final int CIRCLE_REFERENCE = ConstraintLayout.LayoutParams.CIRCLE;
/**
* Chain spread style
*/
public static final int CHAIN_SPREAD = ConstraintLayout.LayoutParams.CHAIN_SPREAD;
/**
* Chain spread inside style
*/
public static final int CHAIN_SPREAD_INSIDE = ConstraintLayout.LayoutParams.CHAIN_SPREAD_INSIDE;
public static final int VISIBILITY_MODE_NORMAL = 0;
public static final int VISIBILITY_MODE_IGNORE = 1;
/**
* Chain packed style
*/
public static final int CHAIN_PACKED = ConstraintLayout.LayoutParams.CHAIN_PACKED;
private static final boolean DEBUG = false;
private static final int[] VISIBILITY_FLAGS = new int[]{VISIBLE, INVISIBLE, GONE};
private static final int BARRIER_TYPE = 1;
private HashMap<Integer, Constraint> mConstraints = new HashMap<Integer, Constraint>();
private static SparseIntArray sMapToConstant = new SparseIntArray();
private static SparseIntArray sOverrideMapToConstant = new SparseIntArray();
private static final int BASELINE_TO_BASELINE = 1;
private static final int BOTTOM_MARGIN = 2;
private static final int BOTTOM_TO_BOTTOM = 3;
private static final int BOTTOM_TO_TOP = 4;
private static final int DIMENSION_RATIO = 5;
private static final int EDITOR_ABSOLUTE_X = 6;
private static final int EDITOR_ABSOLUTE_Y = 7;
private static final int END_MARGIN = 8;
private static final int END_TO_END = 9;
private static final int END_TO_START = 10;
private static final int GONE_BOTTOM_MARGIN = 11;
private static final int GONE_END_MARGIN = 12;
private static final int GONE_LEFT_MARGIN = 13;
private static final int GONE_RIGHT_MARGIN = 14;
private static final int GONE_START_MARGIN = 15;
private static final int GONE_TOP_MARGIN = 16;
private static final int GUIDE_BEGIN = 17;
private static final int GUIDE_END = 18;
private static final int GUIDE_PERCENT = 19;
private static final int HORIZONTAL_BIAS = 20;
private static final int LAYOUT_HEIGHT = 21;
private static final int LAYOUT_VISIBILITY = 22;
private static final int LAYOUT_WIDTH = 23;
private static final int LEFT_MARGIN = 24;
private static final int LEFT_TO_LEFT = 25;
private static final int LEFT_TO_RIGHT = 26;
private static final int ORIENTATION = 27;
private static final int RIGHT_MARGIN = 28;
private static final int RIGHT_TO_LEFT = 29;
private static final int RIGHT_TO_RIGHT = 30;
private static final int START_MARGIN = 31;
private static final int START_TO_END = 32;
private static final int START_TO_START = 33;
private static final int TOP_MARGIN = 34;
private static final int TOP_TO_BOTTOM = 35;
private static final int TOP_TO_TOP = 36;
private static final int VERTICAL_BIAS = 37;
private static final int VIEW_ID = 38;
private static final int HORIZONTAL_WEIGHT = 39;
private static final int VERTICAL_WEIGHT = 40;
private static final int HORIZONTAL_STYLE = 41;
private static final int VERTICAL_STYLE = 42;
private static final int ALPHA = 43;
private static final int ELEVATION = 44;
private static final int ROTATION_X = 45;
private static final int ROTATION_Y = 46;
private static final int SCALE_X = 47;
private static final int SCALE_Y = 48;
private static final int TRANSFORM_PIVOT_X = 49;
private static final int TRANSFORM_PIVOT_Y = 50;
private static final int TRANSLATION_X = 51;
private static final int TRANSLATION_Y = 52;
private static final int TRANSLATION_Z = 53;
private static final int WIDTH_DEFAULT = 54;
private static final int HEIGHT_DEFAULT = 55;
private static final int WIDTH_MAX = 56;
private static final int HEIGHT_MAX = 57;
private static final int WIDTH_MIN = 58;
private static final int HEIGHT_MIN = 59;
private static final int ROTATION = 60;
private static final int CIRCLE = 61;
private static final int CIRCLE_RADIUS = 62;
private static final int CIRCLE_ANGLE = 63;
private static final int ANIMATE_RELATIVE_TO = 64;
private static final int TRANSITION_EASING = 65;
private static final int DRAW_PATH = 66;
private static final int TRANSITION_PATH_ROTATE = 67;
private static final int PROGRESS = 68;
private static final int WIDTH_PERCENT = 69;
private static final int HEIGHT_PERCENT = 70;
private static final int CHAIN_USE_RTL = 71;
private static final int BARRIER_DIRECTION = 72;
private static final int BARRIER_MARGIN = 73;
private static final int CONSTRAINT_REFERENCED_IDS = 74;
private static final int BARRIER_ALLOWS_GONE_WIDGETS = 75;
private static final int PATH_MOTION_ARC = 76;
private static final int CONSTRAINT_TAG = 77;
private static final int VISIBILITY_MODE = 78;
private static final int MOTION_STAGGER = 79;
private static final int CONSTRAINED_WIDTH = 80;
private static final int CONSTRAINED_HEIGHT = 81;
private static final int ANIMATE_CIRCLE_ANGLE_TO = 82;
private static final int TRANSFORM_PIVOT_TARGET = 83;
private static final int QUANTIZE_MOTION_STEPS = 84;
private static final int QUANTIZE_MOTION_PHASE = 85;
private static final int QUANTIZE_MOTION_INTERPOLATOR = 86;
private static final int UNUSED = 87;
private static final int QUANTIZE_MOTION_INTERPOLATOR_TYPE = 88;
private static final int QUANTIZE_MOTION_INTERPOLATOR_ID = 89;
private static final int QUANTIZE_MOTION_INTERPOLATOR_STR = 90;
private static final int BASELINE_TO_TOP = 91;
private static final int BASELINE_TO_BOTTOM = 92;
private static final int BASELINE_MARGIN = 93;
private static final int GONE_BASELINE_MARGIN = 94;
private static final int LAYOUT_CONSTRAINT_WIDTH = 95;
private static final int LAYOUT_CONSTRAINT_HEIGHT = 96;
private static final int LAYOUT_WRAP_BEHAVIOR = 97;
private static final int MOTION_TARGET = 98;
private static final int GUIDELINE_USE_RTL = 99;
private static final String KEY_WEIGHT = "weight";
private static final String KEY_RATIO = "ratio";
private static final String KEY_PERCENT_PARENT = "parent";
static {
sMapToConstant.append(R.styleable.Constraint_layout_constraintLeft_toLeftOf, LEFT_TO_LEFT);
sMapToConstant.append(R.styleable.Constraint_layout_constraintLeft_toRightOf,
LEFT_TO_RIGHT);
sMapToConstant.append(R.styleable.Constraint_layout_constraintRight_toLeftOf,
RIGHT_TO_LEFT);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintRight_toRightOf, RIGHT_TO_RIGHT);
sMapToConstant.append(R.styleable.Constraint_layout_constraintTop_toTopOf, TOP_TO_TOP);
sMapToConstant.append(R.styleable.Constraint_layout_constraintTop_toBottomOf,
TOP_TO_BOTTOM);
sMapToConstant.append(R.styleable.Constraint_layout_constraintBottom_toTopOf,
BOTTOM_TO_TOP);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintBottom_toBottomOf, BOTTOM_TO_BOTTOM);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintBaseline_toBaselineOf,
BASELINE_TO_BASELINE);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintBaseline_toTopOf, BASELINE_TO_TOP);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintBaseline_toBottomOf, BASELINE_TO_BOTTOM);
sMapToConstant.append(R.styleable.Constraint_layout_editor_absoluteX, EDITOR_ABSOLUTE_X);
sMapToConstant.append(R.styleable.Constraint_layout_editor_absoluteY, EDITOR_ABSOLUTE_Y);
sMapToConstant.append(R.styleable.Constraint_layout_constraintGuide_begin, GUIDE_BEGIN);
sMapToConstant.append(R.styleable.Constraint_layout_constraintGuide_end, GUIDE_END);
sMapToConstant.append(R.styleable.Constraint_layout_constraintGuide_percent, GUIDE_PERCENT);
sMapToConstant.append(R.styleable.Constraint_guidelineUseRtl, GUIDELINE_USE_RTL);
sMapToConstant.append(R.styleable.Constraint_android_orientation, ORIENTATION);
sMapToConstant.append(R.styleable.Constraint_layout_constraintStart_toEndOf, START_TO_END);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintStart_toStartOf, START_TO_START);
sMapToConstant.append(R.styleable.Constraint_layout_constraintEnd_toStartOf, END_TO_START);
sMapToConstant.append(R.styleable.Constraint_layout_constraintEnd_toEndOf, END_TO_END);
sMapToConstant.append(R.styleable.Constraint_layout_goneMarginLeft, GONE_LEFT_MARGIN);
sMapToConstant.append(R.styleable.Constraint_layout_goneMarginTop, GONE_TOP_MARGIN);
sMapToConstant.append(R.styleable.Constraint_layout_goneMarginRight, GONE_RIGHT_MARGIN);
sMapToConstant.append(R.styleable.Constraint_layout_goneMarginBottom, GONE_BOTTOM_MARGIN);
sMapToConstant.append(R.styleable.Constraint_layout_goneMarginStart, GONE_START_MARGIN);
sMapToConstant.append(R.styleable.Constraint_layout_goneMarginEnd, GONE_END_MARGIN);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintVertical_weight, VERTICAL_WEIGHT);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintHorizontal_weight, HORIZONTAL_WEIGHT);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintHorizontal_chainStyle, HORIZONTAL_STYLE);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintVertical_chainStyle, VERTICAL_STYLE);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintHorizontal_bias, HORIZONTAL_BIAS);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintVertical_bias, VERTICAL_BIAS);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintDimensionRatio, DIMENSION_RATIO);
sMapToConstant.append(R.styleable.Constraint_layout_constraintLeft_creator, UNUSED);
sMapToConstant.append(R.styleable.Constraint_layout_constraintTop_creator, UNUSED);
sMapToConstant.append(R.styleable.Constraint_layout_constraintRight_creator, UNUSED);
sMapToConstant.append(R.styleable.Constraint_layout_constraintBottom_creator, UNUSED);
sMapToConstant.append(R.styleable.Constraint_layout_constraintBaseline_creator, UNUSED);
sMapToConstant.append(R.styleable.Constraint_android_layout_marginLeft, LEFT_MARGIN);
sMapToConstant.append(R.styleable.Constraint_android_layout_marginRight, RIGHT_MARGIN);
sMapToConstant.append(R.styleable.Constraint_android_layout_marginStart, START_MARGIN);
sMapToConstant.append(R.styleable.Constraint_android_layout_marginEnd, END_MARGIN);
sMapToConstant.append(R.styleable.Constraint_android_layout_marginTop, TOP_MARGIN);
sMapToConstant.append(R.styleable.Constraint_android_layout_marginBottom, BOTTOM_MARGIN);
sMapToConstant.append(R.styleable.Constraint_android_layout_width, LAYOUT_WIDTH);
sMapToConstant.append(
R.styleable.Constraint_android_layout_height, LAYOUT_HEIGHT);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintWidth, LAYOUT_CONSTRAINT_WIDTH);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintHeight, LAYOUT_CONSTRAINT_HEIGHT);
sMapToConstant.append(R.styleable.Constraint_android_visibility, LAYOUT_VISIBILITY);
sMapToConstant.append(R.styleable.Constraint_android_alpha, ALPHA);
sMapToConstant.append(R.styleable.Constraint_android_elevation, ELEVATION);
sMapToConstant.append(R.styleable.Constraint_android_rotationX, ROTATION_X);
sMapToConstant.append(R.styleable.Constraint_android_rotationY, ROTATION_Y);
sMapToConstant.append(R.styleable.Constraint_android_rotation, ROTATION);
sMapToConstant.append(R.styleable.Constraint_android_scaleX, SCALE_X);
sMapToConstant.append(R.styleable.Constraint_android_scaleY, SCALE_Y);
sMapToConstant.append(R.styleable.Constraint_android_transformPivotX, TRANSFORM_PIVOT_X);
sMapToConstant.append(R.styleable.Constraint_android_transformPivotY, TRANSFORM_PIVOT_Y);
sMapToConstant.append(R.styleable.Constraint_android_translationX, TRANSLATION_X);
sMapToConstant.append(R.styleable.Constraint_android_translationY, TRANSLATION_Y);
sMapToConstant.append(R.styleable.Constraint_android_translationZ, TRANSLATION_Z);
sMapToConstant.append(R.styleable.Constraint_layout_constraintWidth_default, WIDTH_DEFAULT);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintHeight_default, HEIGHT_DEFAULT);
sMapToConstant.append(R.styleable.Constraint_layout_constraintWidth_max, WIDTH_MAX);
sMapToConstant.append(R.styleable.Constraint_layout_constraintHeight_max, HEIGHT_MAX);
sMapToConstant.append(R.styleable.Constraint_layout_constraintWidth_min, WIDTH_MIN);
sMapToConstant.append(R.styleable.Constraint_layout_constraintHeight_min, HEIGHT_MIN);
sMapToConstant.append(R.styleable.Constraint_layout_constraintCircle, CIRCLE);
sMapToConstant.append(R.styleable.Constraint_layout_constraintCircleRadius, CIRCLE_RADIUS);
sMapToConstant.append(R.styleable.Constraint_layout_constraintCircleAngle, CIRCLE_ANGLE);
sMapToConstant.append(R.styleable.Constraint_animateRelativeTo, ANIMATE_RELATIVE_TO);
sMapToConstant.append(R.styleable.Constraint_transitionEasing, TRANSITION_EASING);
sMapToConstant.append(R.styleable.Constraint_drawPath, DRAW_PATH);
sMapToConstant.append(R.styleable.Constraint_transitionPathRotate, TRANSITION_PATH_ROTATE);
sMapToConstant.append(R.styleable.Constraint_motionStagger, MOTION_STAGGER);
sMapToConstant.append(R.styleable.Constraint_android_id, VIEW_ID);
sMapToConstant.append(R.styleable.Constraint_motionProgress, PROGRESS);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintWidth_percent, WIDTH_PERCENT);
sMapToConstant.append(
R.styleable.Constraint_layout_constraintHeight_percent, HEIGHT_PERCENT);
sMapToConstant.append(
R.styleable.Constraint_layout_wrapBehaviorInParent, LAYOUT_WRAP_BEHAVIOR);
sMapToConstant.append(R.styleable.Constraint_chainUseRtl, CHAIN_USE_RTL);
sMapToConstant.append(R.styleable.Constraint_barrierDirection, BARRIER_DIRECTION);
sMapToConstant.append(R.styleable.Constraint_barrierMargin, BARRIER_MARGIN);
sMapToConstant.append(
R.styleable.Constraint_constraint_referenced_ids, CONSTRAINT_REFERENCED_IDS);
sMapToConstant.append(
R.styleable.Constraint_barrierAllowsGoneWidgets, BARRIER_ALLOWS_GONE_WIDGETS);
sMapToConstant.append(R.styleable.Constraint_pathMotionArc, PATH_MOTION_ARC);
sMapToConstant.append(R.styleable.Constraint_layout_constraintTag, CONSTRAINT_TAG);
sMapToConstant.append(R.styleable.Constraint_visibilityMode, VISIBILITY_MODE);
sMapToConstant.append(
R.styleable.Constraint_layout_constrainedWidth, CONSTRAINED_WIDTH);
sMapToConstant.append(
R.styleable.Constraint_layout_constrainedHeight, CONSTRAINED_HEIGHT);
sMapToConstant.append(
R.styleable.Constraint_polarRelativeTo, ANIMATE_CIRCLE_ANGLE_TO);
sMapToConstant.append(
R.styleable.Constraint_transformPivotTarget, TRANSFORM_PIVOT_TARGET);
sMapToConstant.append(
R.styleable.Constraint_quantizeMotionSteps, QUANTIZE_MOTION_STEPS);
sMapToConstant.append(
R.styleable.Constraint_quantizeMotionPhase, QUANTIZE_MOTION_PHASE);
sMapToConstant.append(
R.styleable.Constraint_quantizeMotionInterpolator, QUANTIZE_MOTION_INTERPOLATOR);
/*
The tags not available in constraintOverride
Left here to help with documentation and understanding
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintLeft_toLeftOf, LEFT_TO_LEFT);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintLeft_toRightOf, LEFT_TO_RIGHT);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintRight_toLeftOf, RIGHT_TO_LEFT);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintRight_toRightOf, RIGHT_TO_RIGHT);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintTop_toTopOf, TOP_TO_TOP);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintTop_toBottomOf, TOP_TO_BOTTOM);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintBottom_toTopOf, BOTTOM_TO_TOP);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintBottom_toBottomOf, BOTTOM_TO_BOTTOM);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintBaseline_toBaselineOf,
BASELINE_TO_BASELINE);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintGuide_begin, GUIDE_BEGIN);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintGuide_end, GUIDE_END);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintGuide_percent, GUIDE_PERCENT);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintStart_toEndOf, START_TO_END);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintStart_toStartOf, START_TO_START);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintEnd_toStartOf, END_TO_START);
overrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintEnd_toEndOf, END_TO_END);
*/
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_editor_absoluteY, EDITOR_ABSOLUTE_X);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_editor_absoluteY, EDITOR_ABSOLUTE_Y);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_android_orientation, ORIENTATION);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_goneMarginLeft, GONE_LEFT_MARGIN);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_goneMarginTop, GONE_TOP_MARGIN);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_goneMarginRight, GONE_RIGHT_MARGIN);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_goneMarginBottom, GONE_BOTTOM_MARGIN);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_goneMarginStart, GONE_START_MARGIN);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_goneMarginEnd, GONE_END_MARGIN);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintVertical_weight,
VERTICAL_WEIGHT);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintHorizontal_weight,
HORIZONTAL_WEIGHT);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintHorizontal_chainStyle,
HORIZONTAL_STYLE);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintVertical_chainStyle,
VERTICAL_STYLE);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintHorizontal_bias,
HORIZONTAL_BIAS);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintVertical_bias,
VERTICAL_BIAS);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintDimensionRatio, DIMENSION_RATIO);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintLeft_creator,
UNUSED);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintTop_creator,
UNUSED);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintRight_creator,
UNUSED);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintBottom_creator, UNUSED);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintBaseline_creator,
UNUSED);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginLeft,
LEFT_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginRight,
RIGHT_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginStart,
START_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginEnd,
END_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginTop,
TOP_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginBottom,
BOTTOM_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_width,
LAYOUT_WIDTH);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_height,
LAYOUT_HEIGHT);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth,
LAYOUT_CONSTRAINT_WIDTH);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight,
LAYOUT_CONSTRAINT_HEIGHT);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_visibility,
LAYOUT_VISIBILITY);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_alpha, ALPHA);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_elevation, ELEVATION);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_rotationX, ROTATION_X);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_rotationY, ROTATION_Y);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_rotation, ROTATION);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_scaleX, SCALE_X);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_scaleY, SCALE_Y);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_transformPivotX,
TRANSFORM_PIVOT_X);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_transformPivotY,
TRANSFORM_PIVOT_Y);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_translationX,
TRANSLATION_X);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_translationY,
TRANSLATION_Y);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_translationZ,
TRANSLATION_Z);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_default,
WIDTH_DEFAULT);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintHeight_default, HEIGHT_DEFAULT);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_max,
WIDTH_MAX);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight_max,
HEIGHT_MAX);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_min,
WIDTH_MIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight_min,
HEIGHT_MIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintCircleRadius,
CIRCLE_RADIUS);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintCircleAngle,
CIRCLE_ANGLE);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_animateRelativeTo,
ANIMATE_RELATIVE_TO);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_transitionEasing,
TRANSITION_EASING);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_drawPath, DRAW_PATH);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_transitionPathRotate,
TRANSITION_PATH_ROTATE);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_motionStagger, MOTION_STAGGER);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_id, VIEW_ID);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_motionTarget, MOTION_TARGET);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_motionProgress, PROGRESS);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_percent,
WIDTH_PERCENT);
sOverrideMapToConstant.append(
R.styleable.ConstraintOverride_layout_constraintHeight_percent, HEIGHT_PERCENT);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_chainUseRtl, CHAIN_USE_RTL);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_barrierDirection,
BARRIER_DIRECTION);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_barrierMargin,
BARRIER_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_constraint_referenced_ids,
CONSTRAINT_REFERENCED_IDS);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_barrierAllowsGoneWidgets,
BARRIER_ALLOWS_GONE_WIDGETS);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_pathMotionArc,
PATH_MOTION_ARC);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintTag,
CONSTRAINT_TAG);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_visibilityMode,
VISIBILITY_MODE);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constrainedWidth,
CONSTRAINED_WIDTH);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constrainedHeight,
CONSTRAINED_HEIGHT);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_polarRelativeTo,
ANIMATE_CIRCLE_ANGLE_TO);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_transformPivotTarget,
TRANSFORM_PIVOT_TARGET);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_quantizeMotionSteps,
QUANTIZE_MOTION_STEPS);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_quantizeMotionPhase,
QUANTIZE_MOTION_PHASE);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_quantizeMotionInterpolator,
QUANTIZE_MOTION_INTERPOLATOR);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_wrapBehaviorInParent,
LAYOUT_WRAP_BEHAVIOR);
}
public HashMap<String, ConstraintAttribute> getCustomAttributeSet() {
return mSavedAttributes;
}
// @TODO: add description
/**
*
* @param mId
* @return
*/
public Constraint getParameters(int mId) {
return get(mId);
}
/**
* This will copy Constraints from the ConstraintSet
*
* @param set
*/
public void readFallback(ConstraintSet set) {
for (Integer key : set.mConstraints.keySet()) {
int id = key;
Constraint parent = set.mConstraints.get(key);
if (!mConstraints.containsKey(id)) {
mConstraints.put(id, new Constraint());
}
Constraint constraint = mConstraints.get(id);
if (constraint == null) {
continue;
}
if (!constraint.layout.mApply) {
constraint.layout.copyFrom(parent.layout);
}
if (!constraint.propertySet.mApply) {
constraint.propertySet.copyFrom(parent.propertySet);
}
if (!constraint.transform.mApply) {
constraint.transform.copyFrom(parent.transform);
}
if (!constraint.motion.mApply) {
constraint.motion.copyFrom(parent.motion);
}
for (String s : parent.mCustomConstraints.keySet()) {
if (!constraint.mCustomConstraints.containsKey(s)) {
constraint.mCustomConstraints.put(s, parent.mCustomConstraints.get(s));
}
}
}
}
/**
* This will copy Constraints from the ConstraintLayout if it does not have parameters
*
* @param constraintLayout
*/
public void readFallback(ConstraintLayout constraintLayout) {
int count = constraintLayout.getChildCount();
for (int i = 0; i < count; i++) {
View view = constraintLayout.getChildAt(i);
ConstraintLayout.LayoutParams param =
(ConstraintLayout.LayoutParams) view.getLayoutParams();
int id = view.getId();
if (mForceId && id == -1) {
throw new RuntimeException("All children of ConstraintLayout "
+ "must have ids to use ConstraintSet");
}
if (!mConstraints.containsKey(id)) {
mConstraints.put(id, new Constraint());
}
Constraint constraint = mConstraints.get(id);
if (constraint == null) {
continue;
}
if (!constraint.layout.mApply) {
constraint.fillFrom(id, param);
if (view instanceof ConstraintHelper) {
constraint.layout.mReferenceIds = ((ConstraintHelper) view).getReferencedIds();
if (view instanceof Barrier) {
Barrier barrier = (Barrier) view;
constraint.layout.mBarrierAllowsGoneWidgets = barrier.getAllowsGoneWidget();
constraint.layout.mBarrierDirection = barrier.getType();
constraint.layout.mBarrierMargin = barrier.getMargin();
}
}
constraint.layout.mApply = true;
}
if (!constraint.propertySet.mApply) {
constraint.propertySet.visibility = view.getVisibility();
constraint.propertySet.alpha = view.getAlpha();
constraint.propertySet.mApply = true;
}
if (!constraint.transform.mApply) {
constraint.transform.mApply = true;
constraint.transform.rotation = view.getRotation();
constraint.transform.rotationX = view.getRotationX();
constraint.transform.rotationY = view.getRotationY();
constraint.transform.scaleX = view.getScaleX();
constraint.transform.scaleY = view.getScaleY();
float pivotX = view.getPivotX(); // we assume it is not set if set to 0.0
float pivotY = view.getPivotY(); // we assume it is not set if set to 0.0
if (pivotX != 0.0 || pivotY != 0.0) {
constraint.transform.transformPivotX = pivotX;
constraint.transform.transformPivotY = pivotY;
}
constraint.transform.translationX = view.getTranslationX();
constraint.transform.translationY = view.getTranslationY();
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
constraint.transform.translationZ = view.getTranslationZ();
if (constraint.transform.applyElevation) {
constraint.transform.elevation = view.getElevation();
}
}
}
}
}
/**
* Get the delta form the ConstraintSet and aplly to this
* @param cs
*/
public void applyDeltaFrom(ConstraintSet cs) {
for (Constraint from : cs.mConstraints.values()) {
if (from.mDelta == null) {
continue;
}
if (from.mTargetString == null) {
Constraint constraint = getConstraint(from.mViewId);
from.mDelta.applyDelta(constraint);
continue;
}
for (int key : mConstraints.keySet()) {
Constraint potential = getConstraint(key);
if (potential.layout.mConstraintTag == null) {
continue;
}
if (from.mTargetString.matches(potential.layout.mConstraintTag)) {
from.mDelta.applyDelta(potential);
@SuppressWarnings("unchecked")
HashMap<String, ConstraintAttribute> fromClone =
(HashMap<String, ConstraintAttribute>) from.mCustomConstraints.clone();
potential.mCustomConstraints.putAll(fromClone);
}
}
}
}
/**
* Parse the constraint dimension attribute
*
* @param a
* @param attr
* @param orientation
*/
static void parseDimensionConstraints(Object data, TypedArray a, int attr, int orientation) {
if (data == null) {
return;
}
// data can be of:
//
// ConstraintLayout.LayoutParams
// ConstraintSet.Layout
// Constraint.Delta
TypedValue v = a.peekValue(attr);
int type = v.type;
int finalValue = 0;
boolean finalConstrained = false;
switch (type) {
case TypedValue.TYPE_DIMENSION: {
finalValue = a.getDimensionPixelSize(attr, 0);
}
break;
case TypedValue.TYPE_STRING: {
String value = a.getString(attr);
parseDimensionConstraintsString(data, value, orientation);
return;
}
default: {
int value = a.getInt(attr, 0);
switch (value) {
case INTERNAL_WRAP_CONTENT:
case INTERNAL_MATCH_PARENT: {
finalValue = value;
}
break;
case INTERNAL_MATCH_CONSTRAINT: {
finalValue = MATCH_CONSTRAINT;
}
break;
case INTERNAL_WRAP_CONTENT_CONSTRAINED: {
finalValue = WRAP_CONTENT;
finalConstrained = true;
}
break;
}
}
}
if (data instanceof ConstraintLayout.LayoutParams) {
ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) data;
if (orientation == HORIZONTAL) {
params.width = finalValue;
params.constrainedWidth = finalConstrained;
} else {
params.height = finalValue;
params.constrainedHeight = finalConstrained;
}
} else if (data instanceof Layout) {
Layout params = (Layout) data;
if (orientation == HORIZONTAL) {
params.mWidth = finalValue;
params.constrainedWidth = finalConstrained;
} else {
params.mHeight = finalValue;
params.constrainedHeight = finalConstrained;
}
} else if (data instanceof Constraint.Delta) {
Constraint.Delta params = (Constraint.Delta) data;
if (orientation == HORIZONTAL) {
params.add(LAYOUT_WIDTH, finalValue);
params.add(CONSTRAINED_WIDTH, finalConstrained);
} else {
params.add(LAYOUT_HEIGHT, finalValue);
params.add(CONSTRAINED_HEIGHT, finalConstrained);
}
}
}
/**
* Parse the dimension ratio string
*
* @param value
*/
static void parseDimensionRatioString(ConstraintLayout.LayoutParams params, String value) {
String dimensionRatio = value;
float dimensionRatioValue = Float.NaN;
int dimensionRatioSide = UNSET;
if (dimensionRatio != null) {
int len = dimensionRatio.length();
int commaIndex = dimensionRatio.indexOf(',');
if (commaIndex > 0 && commaIndex < len - 1) {
String dimension = dimensionRatio.substring(0, commaIndex);
if (dimension.equalsIgnoreCase("W")) {
dimensionRatioSide = HORIZONTAL;
} else if (dimension.equalsIgnoreCase("H")) {
dimensionRatioSide = VERTICAL;
}
commaIndex++;
} else {
commaIndex = 0;
}
int colonIndex = dimensionRatio.indexOf(':');
if (colonIndex >= 0 && colonIndex < len - 1) {
String nominator = dimensionRatio.substring(commaIndex, colonIndex);
String denominator = dimensionRatio.substring(colonIndex + 1);
if (nominator.length() > 0 && denominator.length() > 0) {
try {
float nominatorValue = Float.parseFloat(nominator);
float denominatorValue = Float.parseFloat(denominator);
if (nominatorValue > 0 && denominatorValue > 0) {
if (dimensionRatioSide == VERTICAL) {
dimensionRatioValue = Math.abs(denominatorValue / nominatorValue);
} else {
dimensionRatioValue = Math.abs(nominatorValue / denominatorValue);
}
}
} catch (NumberFormatException e) {
// Ignore
}
}
} else {
String r = dimensionRatio.substring(commaIndex);
if (r.length() > 0) {
try {
dimensionRatioValue = Float.parseFloat(r);
} catch (NumberFormatException e) {
// Ignore
}
}
}
}
params.dimensionRatio = dimensionRatio;
params.mDimensionRatioValue = dimensionRatioValue;
params.mDimensionRatioSide = dimensionRatioSide;
}
/**
* Parse the constraints string dimension
*
* @param value
* @param orientation
*/
static void parseDimensionConstraintsString(Object data, String value, int orientation) {
// data can be of:
//
// ConstraintLayout.LayoutParams
// ConstraintSet.Layout
// Constraint.Delta
// String should be of the form
//
// "<Key>=<Value>"
// supported Keys are:
// "weight=<value>"
// "ratio=<value>"
// "parent=<value>"
if (value == null) {
return;
}
int equalIndex = value.indexOf('=');
int len = value.length();
if (equalIndex > 0 && equalIndex < len - 1) {
String key = value.substring(0, equalIndex);
String val = value.substring(equalIndex + 1);
if (val.length() > 0) {
key = key.trim();
val = val.trim();
if (KEY_RATIO.equalsIgnoreCase(key)) {
if (data instanceof ConstraintLayout.LayoutParams) {
ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) data;
if (orientation == HORIZONTAL) {
params.width = MATCH_CONSTRAINT;
} else {
params.height = MATCH_CONSTRAINT;
}
parseDimensionRatioString(params, val);
} else if (data instanceof Layout) {
Layout params = (Layout) data;
params.dimensionRatio = val;
} else if (data instanceof Constraint.Delta) {
Constraint.Delta params = (Constraint.Delta) data;
params.add(DIMENSION_RATIO, val);
}
} else if (KEY_WEIGHT.equalsIgnoreCase(key)) {
try {
float weight = Float.parseFloat(val);
if (data instanceof ConstraintLayout.LayoutParams) {
ConstraintLayout.LayoutParams params =
(ConstraintLayout.LayoutParams) data;
if (orientation == HORIZONTAL) {
params.width = MATCH_CONSTRAINT;
params.horizontalWeight = weight;
} else {
params.height = MATCH_CONSTRAINT;
params.verticalWeight = weight;
}
} else if (data instanceof Layout) {
Layout params = (Layout) data;
if (orientation == HORIZONTAL) {
params.mWidth = MATCH_CONSTRAINT;
params.horizontalWeight = weight;
} else {
params.mHeight = MATCH_CONSTRAINT;
params.verticalWeight = weight;
}
} else if (data instanceof Constraint.Delta) {
Constraint.Delta params = (Constraint.Delta) data;
if (orientation == HORIZONTAL) {
params.add(LAYOUT_WIDTH, MATCH_CONSTRAINT);
params.add(HORIZONTAL_WEIGHT, weight);
} else {
params.add(LAYOUT_HEIGHT, MATCH_CONSTRAINT);
params.add(VERTICAL_WEIGHT, weight);
}
}
} catch (NumberFormatException e) {
// nothing
}
} else if (KEY_PERCENT_PARENT.equalsIgnoreCase(key)) {
try {
float percent = Math.min(1, Float.parseFloat(val));
percent = Math.max(0, percent);
if (data instanceof ConstraintLayout.LayoutParams) {
ConstraintLayout.LayoutParams params =
(ConstraintLayout.LayoutParams) data;
if (orientation == HORIZONTAL) {
params.width = MATCH_CONSTRAINT;
params.matchConstraintPercentWidth = percent;
params.matchConstraintDefaultWidth = MATCH_CONSTRAINT_PERCENT;
} else {
params.height = MATCH_CONSTRAINT;
params.matchConstraintPercentHeight = percent;
params.matchConstraintDefaultHeight = MATCH_CONSTRAINT_PERCENT;
}
} else if (data instanceof Layout) {
Layout params = (Layout) data;
if (orientation == HORIZONTAL) {
params.mWidth = MATCH_CONSTRAINT;
params.widthPercent = percent;
params.widthDefault = MATCH_CONSTRAINT_PERCENT;
} else {
params.mHeight = MATCH_CONSTRAINT;
params.heightPercent = percent;
params.heightDefault = MATCH_CONSTRAINT_PERCENT;
}
} else if (data instanceof Constraint.Delta) {
Constraint.Delta params = (Constraint.Delta) data;
if (orientation == HORIZONTAL) {
params.add(LAYOUT_WIDTH, MATCH_CONSTRAINT);
params.add(WIDTH_DEFAULT, MATCH_CONSTRAINT_PERCENT);
} else {
params.add(LAYOUT_HEIGHT, MATCH_CONSTRAINT);
params.add(HEIGHT_DEFAULT, MATCH_CONSTRAINT_PERCENT);
}
}
} catch (NumberFormatException e) {
// nothing
}
}
}
}
}
/**
* Get the types associated with this ConstraintSet
* The types mechanism allows you to tag the constraint set
* with a series of string to define properties of a ConstraintSet
*
* @return an array of type strings
*/
public String[] getStateLabels() {
return Arrays.copyOf(mMatchLabels, mMatchLabels.length);
}
/**
* Set the types associated with this ConstraintSet
* The types mechanism allows you to tag the constraint set
* with a series of string to define properties of a ConstraintSet
* @param types a comer separated array of strings.
*/
public void setStateLabels(String types) {
mMatchLabels = types.split(",");
for (int i = 0; i < mMatchLabels.length; i++) {
mMatchLabels[i] = mMatchLabels[i].trim();
}
}
/**
* Set the types associated with this ConstraintSet
* The types mechanism allows you to tag the constraint set
* with a series of string to define properties of a ConstraintSet
* @param types a comer separated array of strings.
*/
public void setStateLabelsList(String... types) {
mMatchLabels = types;
for (int i = 0; i < mMatchLabels.length; i++) {
mMatchLabels[i] = mMatchLabels[i].trim();
}
}
/**
* Test if the list of strings matches labels defined on this constraintSet
* @param types list of types
* @return true if all types are in the labels
*/
public boolean matchesLabels(String...types) {
for (String type : types) {
boolean match = false;
for (String matchType : mMatchLabels) {
if (matchType.equals(type)) {
match = true;
break;
}
}
if (!match) {
return false;
}
}
return true;
}
/**
*
*/
public static class Layout {
public boolean mIsGuideline = false;
public boolean mApply = false;
public boolean mOverride = false;
public int mWidth;
public int mHeight;
public static final int UNSET = ConstraintSet.UNSET;
public static final int UNSET_GONE_MARGIN = Integer.MIN_VALUE;
public int guideBegin = UNSET;
public int guideEnd = UNSET;
public float guidePercent = UNSET;
public boolean guidelineUseRtl = true;
public int leftToLeft = UNSET;
public int leftToRight = UNSET;
public int rightToLeft = UNSET;
public int rightToRight = UNSET;
public int topToTop = UNSET;
public int topToBottom = UNSET;
public int bottomToTop = UNSET;
public int bottomToBottom = UNSET;
public int baselineToBaseline = UNSET;
public int baselineToTop = UNSET;
public int baselineToBottom = UNSET;
public int startToEnd = UNSET;
public int startToStart = UNSET;
public int endToStart = UNSET;
public int endToEnd = UNSET;
public float horizontalBias = 0.5f;
public float verticalBias = 0.5f;
public String dimensionRatio = null;
public int circleConstraint = UNSET;
public int circleRadius = 0;
public float circleAngle = 0;
public int editorAbsoluteX = UNSET;
public int editorAbsoluteY = UNSET;
public int orientation = UNSET;
public int leftMargin = 0;
public int rightMargin = 0;
public int topMargin = 0;
public int bottomMargin = 0;
public int endMargin = 0;
public int startMargin = 0;
public int baselineMargin = 0;
public int goneLeftMargin = UNSET_GONE_MARGIN;
public int goneTopMargin = UNSET_GONE_MARGIN;
public int goneRightMargin = UNSET_GONE_MARGIN;
public int goneBottomMargin = UNSET_GONE_MARGIN;
public int goneEndMargin = UNSET_GONE_MARGIN;
public int goneStartMargin = UNSET_GONE_MARGIN;
public int goneBaselineMargin = UNSET_GONE_MARGIN;
public float verticalWeight = UNSET;
public float horizontalWeight = UNSET;
public int horizontalChainStyle = CHAIN_SPREAD;
public int verticalChainStyle = CHAIN_SPREAD;
public int widthDefault = ConstraintWidget.MATCH_CONSTRAINT_SPREAD;
public int heightDefault = ConstraintWidget.MATCH_CONSTRAINT_SPREAD;
public int widthMax = 0;
public int heightMax = 0;
public int widthMin = 0;
public int heightMin = 0;
public float widthPercent = 1;
public float heightPercent = 1;
public int mBarrierDirection = UNSET;
public int mBarrierMargin = 0;
public int mHelperType = UNSET;
public int[] mReferenceIds;
public String mReferenceIdString;
public String mConstraintTag;
public boolean constrainedWidth = false;
public boolean constrainedHeight = false;
// TODO public boolean mChainUseRtl = false;
public boolean mBarrierAllowsGoneWidgets = true;
public int mWrapBehavior = ConstraintWidget.WRAP_BEHAVIOR_INCLUDED;
/**
* Copy from Layout
* @param src
*/
public void copyFrom(Layout src) {
mIsGuideline = src.mIsGuideline;
mWidth = src.mWidth;
mApply = src.mApply;
mHeight = src.mHeight;
guideBegin = src.guideBegin;
guideEnd = src.guideEnd;
guidePercent = src.guidePercent;
guidelineUseRtl = src.guidelineUseRtl;
leftToLeft = src.leftToLeft;
leftToRight = src.leftToRight;
rightToLeft = src.rightToLeft;
rightToRight = src.rightToRight;
topToTop = src.topToTop;
topToBottom = src.topToBottom;
bottomToTop = src.bottomToTop;
bottomToBottom = src.bottomToBottom;
baselineToBaseline = src.baselineToBaseline;
baselineToTop = src.baselineToTop;
baselineToBottom = src.baselineToBottom;
startToEnd = src.startToEnd;
startToStart = src.startToStart;
endToStart = src.endToStart;
endToEnd = src.endToEnd;
horizontalBias = src.horizontalBias;
verticalBias = src.verticalBias;
dimensionRatio = src.dimensionRatio;
circleConstraint = src.circleConstraint;
circleRadius = src.circleRadius;
circleAngle = src.circleAngle;
editorAbsoluteX = src.editorAbsoluteX;
editorAbsoluteY = src.editorAbsoluteY;
orientation = src.orientation;
leftMargin = src.leftMargin;
rightMargin = src.rightMargin;
topMargin = src.topMargin;
bottomMargin = src.bottomMargin;
endMargin = src.endMargin;
startMargin = src.startMargin;
baselineMargin = src.baselineMargin;
goneLeftMargin = src.goneLeftMargin;
goneTopMargin = src.goneTopMargin;
goneRightMargin = src.goneRightMargin;
goneBottomMargin = src.goneBottomMargin;
goneEndMargin = src.goneEndMargin;
goneStartMargin = src.goneStartMargin;
goneBaselineMargin = src.goneBaselineMargin;
verticalWeight = src.verticalWeight;
horizontalWeight = src.horizontalWeight;
horizontalChainStyle = src.horizontalChainStyle;
verticalChainStyle = src.verticalChainStyle;
widthDefault = src.widthDefault;
heightDefault = src.heightDefault;
widthMax = src.widthMax;
heightMax = src.heightMax;
widthMin = src.widthMin;
heightMin = src.heightMin;
widthPercent = src.widthPercent;
heightPercent = src.heightPercent;
mBarrierDirection = src.mBarrierDirection;
mBarrierMargin = src.mBarrierMargin;
mHelperType = src.mHelperType;
mConstraintTag = src.mConstraintTag;
if (src.mReferenceIds != null && src.mReferenceIdString == null) {
mReferenceIds = Arrays.copyOf(src.mReferenceIds, src.mReferenceIds.length);
} else {
mReferenceIds = null;
}
mReferenceIdString = src.mReferenceIdString;
constrainedWidth = src.constrainedWidth;
constrainedHeight = src.constrainedHeight;
// TODO mChainUseRtl = t.mChainUseRtl;
mBarrierAllowsGoneWidgets = src.mBarrierAllowsGoneWidgets;
mWrapBehavior = src.mWrapBehavior;
}
private static SparseIntArray sMapToConstant = new SparseIntArray();
private static final int BASELINE_TO_BASELINE = 1;
private static final int BOTTOM_MARGIN = 2;
private static final int BOTTOM_TO_BOTTOM = 3;
private static final int BOTTOM_TO_TOP = 4;
private static final int DIMENSION_RATIO = 5;
private static final int EDITOR_ABSOLUTE_X = 6;
private static final int EDITOR_ABSOLUTE_Y = 7;
private static final int END_MARGIN = 8;
private static final int END_TO_END = 9;
private static final int END_TO_START = 10;
private static final int GONE_BOTTOM_MARGIN = 11;
private static final int GONE_END_MARGIN = 12;
private static final int GONE_LEFT_MARGIN = 13;
private static final int GONE_RIGHT_MARGIN = 14;
private static final int GONE_START_MARGIN = 15;
private static final int GONE_TOP_MARGIN = 16;
private static final int GUIDE_BEGIN = 17;
private static final int GUIDE_END = 18;
private static final int GUIDE_PERCENT = 19;
private static final int HORIZONTAL_BIAS = 20;
private static final int LAYOUT_HEIGHT = 21;
private static final int LAYOUT_WIDTH = 22;
private static final int LEFT_MARGIN = 23;
private static final int LEFT_TO_LEFT = 24;
private static final int LEFT_TO_RIGHT = 25;
private static final int ORIENTATION = 26;
private static final int RIGHT_MARGIN = 27;
private static final int RIGHT_TO_LEFT = 28;
private static final int RIGHT_TO_RIGHT = 29;
private static final int START_MARGIN = 30;
private static final int START_TO_END = 31;
private static final int START_TO_START = 32;
private static final int TOP_MARGIN = 33;
private static final int TOP_TO_BOTTOM = 34;
private static final int TOP_TO_TOP = 35;
private static final int VERTICAL_BIAS = 36;
private static final int HORIZONTAL_WEIGHT = 37;
private static final int VERTICAL_WEIGHT = 38;
private static final int HORIZONTAL_STYLE = 39;
private static final int VERTICAL_STYLE = 40;
private static final int LAYOUT_CONSTRAINT_WIDTH = 41;
private static final int LAYOUT_CONSTRAINT_HEIGHT = 42;
private static final int CIRCLE = 61;
private static final int CIRCLE_RADIUS = 62;
private static final int CIRCLE_ANGLE = 63;
private static final int WIDTH_PERCENT = 69;
private static final int HEIGHT_PERCENT = 70;
private static final int CHAIN_USE_RTL = 71;
private static final int BARRIER_DIRECTION = 72;
private static final int BARRIER_MARGIN = 73;
private static final int CONSTRAINT_REFERENCED_IDS = 74;
private static final int BARRIER_ALLOWS_GONE_WIDGETS = 75;
private static final int LAYOUT_WRAP_BEHAVIOR = 76;
private static final int BASELINE_TO_TOP = 77;
private static final int BASELINE_TO_BOTTOM = 78;
private static final int GONE_BASELINE_MARGIN = 79;
private static final int BASELINE_MARGIN = 80;
private static final int WIDTH_DEFAULT = 81;
private static final int HEIGHT_DEFAULT = 82;
private static final int HEIGHT_MAX = 83;
private static final int WIDTH_MAX = 84;
private static final int HEIGHT_MIN = 85;
private static final int WIDTH_MIN = 86;
private static final int CONSTRAINED_WIDTH = 87;
private static final int CONSTRAINED_HEIGHT = 88;
private static final int CONSTRAINT_TAG = 89;
private static final int GUIDE_USE_RTL = 90;
private static final int UNUSED = 91;
static {
sMapToConstant.append(R.styleable.Layout_layout_constraintLeft_toLeftOf, LEFT_TO_LEFT);
sMapToConstant.append(R.styleable.Layout_layout_constraintLeft_toRightOf,
LEFT_TO_RIGHT);
sMapToConstant.append(R.styleable.Layout_layout_constraintRight_toLeftOf,
RIGHT_TO_LEFT);
sMapToConstant.append(R.styleable.Layout_layout_constraintRight_toRightOf,
RIGHT_TO_RIGHT);
sMapToConstant.append(R.styleable.Layout_layout_constraintTop_toTopOf, TOP_TO_TOP);
sMapToConstant.append(R.styleable.Layout_layout_constraintTop_toBottomOf,
TOP_TO_BOTTOM);
sMapToConstant.append(R.styleable.Layout_layout_constraintBottom_toTopOf,
BOTTOM_TO_TOP);
sMapToConstant.append(R.styleable.Layout_layout_constraintBottom_toBottomOf,
BOTTOM_TO_BOTTOM);
sMapToConstant.append(R.styleable.Layout_layout_constraintBaseline_toBaselineOf,
BASELINE_TO_BASELINE);
sMapToConstant.append(R.styleable.Layout_layout_editor_absoluteX, EDITOR_ABSOLUTE_X);
sMapToConstant.append(R.styleable.Layout_layout_editor_absoluteY, EDITOR_ABSOLUTE_Y);
sMapToConstant.append(R.styleable.Layout_layout_constraintGuide_begin, GUIDE_BEGIN);
sMapToConstant.append(R.styleable.Layout_layout_constraintGuide_end, GUIDE_END);
sMapToConstant.append(R.styleable.Layout_layout_constraintGuide_percent, GUIDE_PERCENT);
sMapToConstant.append(R.styleable.Layout_guidelineUseRtl, GUIDE_USE_RTL);
sMapToConstant.append(R.styleable.Layout_android_orientation, ORIENTATION);
sMapToConstant.append(R.styleable.Layout_layout_constraintStart_toEndOf, START_TO_END);
sMapToConstant.append(R.styleable.Layout_layout_constraintStart_toStartOf,
START_TO_START);
sMapToConstant.append(R.styleable.Layout_layout_constraintEnd_toStartOf, END_TO_START);
sMapToConstant.append(R.styleable.Layout_layout_constraintEnd_toEndOf, END_TO_END);
sMapToConstant.append(R.styleable.Layout_layout_goneMarginLeft, GONE_LEFT_MARGIN);
sMapToConstant.append(R.styleable.Layout_layout_goneMarginTop, GONE_TOP_MARGIN);
sMapToConstant.append(R.styleable.Layout_layout_goneMarginRight, GONE_RIGHT_MARGIN);
sMapToConstant.append(R.styleable.Layout_layout_goneMarginBottom, GONE_BOTTOM_MARGIN);
sMapToConstant.append(R.styleable.Layout_layout_goneMarginStart, GONE_START_MARGIN);
sMapToConstant.append(R.styleable.Layout_layout_goneMarginEnd, GONE_END_MARGIN);
sMapToConstant.append(R.styleable.Layout_layout_constraintVertical_weight,
VERTICAL_WEIGHT);
sMapToConstant.append(R.styleable.Layout_layout_constraintHorizontal_weight,
HORIZONTAL_WEIGHT);
sMapToConstant.append(R.styleable.Layout_layout_constraintHorizontal_chainStyle,
HORIZONTAL_STYLE);
sMapToConstant.append(R.styleable.Layout_layout_constraintVertical_chainStyle,
VERTICAL_STYLE);
sMapToConstant.append(R.styleable.Layout_layout_constraintHorizontal_bias,
HORIZONTAL_BIAS);
sMapToConstant.append(R.styleable.Layout_layout_constraintVertical_bias,
VERTICAL_BIAS);
sMapToConstant.append(R.styleable.Layout_layout_constraintDimensionRatio,
DIMENSION_RATIO);
sMapToConstant.append(R.styleable.Layout_layout_constraintLeft_creator, UNUSED);
sMapToConstant.append(R.styleable.Layout_layout_constraintTop_creator, UNUSED);
sMapToConstant.append(R.styleable.Layout_layout_constraintRight_creator, UNUSED);
sMapToConstant.append(R.styleable.Layout_layout_constraintBottom_creator, UNUSED);
sMapToConstant.append(R.styleable.Layout_layout_constraintBaseline_creator, UNUSED);
sMapToConstant.append(R.styleable.Layout_android_layout_marginLeft, LEFT_MARGIN);
sMapToConstant.append(R.styleable.Layout_android_layout_marginRight, RIGHT_MARGIN);
sMapToConstant.append(R.styleable.Layout_android_layout_marginStart, START_MARGIN);
sMapToConstant.append(R.styleable.Layout_android_layout_marginEnd, END_MARGIN);
sMapToConstant.append(R.styleable.Layout_android_layout_marginTop, TOP_MARGIN);
sMapToConstant.append(R.styleable.Layout_android_layout_marginBottom, BOTTOM_MARGIN);
sMapToConstant.append(R.styleable.Layout_android_layout_width, LAYOUT_WIDTH);
sMapToConstant.append(R.styleable.Layout_android_layout_height, LAYOUT_HEIGHT);
sMapToConstant.append(R.styleable.Layout_layout_constraintWidth,
LAYOUT_CONSTRAINT_WIDTH);
sMapToConstant.append(R.styleable.Layout_layout_constraintHeight,
LAYOUT_CONSTRAINT_HEIGHT);
sMapToConstant.append(R.styleable.Layout_layout_constrainedWidth,
CONSTRAINED_WIDTH);
sMapToConstant.append(R.styleable.Layout_layout_constrainedHeight,
CONSTRAINED_HEIGHT);
sMapToConstant.append(R.styleable.Layout_layout_wrapBehaviorInParent,
LAYOUT_WRAP_BEHAVIOR);
sMapToConstant.append(R.styleable.Layout_layout_constraintCircle, CIRCLE);
sMapToConstant.append(R.styleable.Layout_layout_constraintCircleRadius, CIRCLE_RADIUS);
sMapToConstant.append(R.styleable.Layout_layout_constraintCircleAngle, CIRCLE_ANGLE);
sMapToConstant.append(R.styleable.Layout_layout_constraintWidth_percent, WIDTH_PERCENT);
sMapToConstant.append(R.styleable.Layout_layout_constraintHeight_percent,
HEIGHT_PERCENT);
sMapToConstant.append(R.styleable.Layout_chainUseRtl, CHAIN_USE_RTL);
sMapToConstant.append(R.styleable.Layout_barrierDirection, BARRIER_DIRECTION);
sMapToConstant.append(R.styleable.Layout_barrierMargin, BARRIER_MARGIN);
sMapToConstant.append(R.styleable.Layout_constraint_referenced_ids,
CONSTRAINT_REFERENCED_IDS);
sMapToConstant.append(R.styleable.Layout_barrierAllowsGoneWidgets,
BARRIER_ALLOWS_GONE_WIDGETS);
sMapToConstant.append(R.styleable.Layout_layout_constraintWidth_max,
WIDTH_MAX);
sMapToConstant.append(R.styleable.Layout_layout_constraintWidth_min,
WIDTH_MIN);
sMapToConstant.append(R.styleable.Layout_layout_constraintWidth_max,
HEIGHT_MAX);
sMapToConstant.append(R.styleable.Layout_layout_constraintHeight_min,
HEIGHT_MIN);
sMapToConstant.append(R.styleable.Layout_layout_constraintWidth, CONSTRAINED_WIDTH);
sMapToConstant.append(R.styleable.Layout_layout_constraintHeight, CONSTRAINED_HEIGHT);
sMapToConstant.append(R.styleable.ConstraintLayout_Layout_layout_constraintTag,
CONSTRAINT_TAG);
sMapToConstant.append(R.styleable.Layout_guidelineUseRtl, GUIDE_USE_RTL);
}
void fillFromAttributeList(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Layout);
mApply = true;
final int count = a.getIndexCount();
for (int i = 0; i < count; i++) {
int attr = a.getIndex(i);
switch (sMapToConstant.get(attr)) {
case LEFT_TO_LEFT:
leftToLeft = lookupID(a, attr, leftToLeft);
break;
case LEFT_TO_RIGHT:
leftToRight = lookupID(a, attr, leftToRight);
break;
case RIGHT_TO_LEFT:
rightToLeft = lookupID(a, attr, rightToLeft);
break;
case RIGHT_TO_RIGHT:
rightToRight = lookupID(a, attr, rightToRight);
break;
case TOP_TO_TOP:
topToTop = lookupID(a, attr, topToTop);
break;
case TOP_TO_BOTTOM:
topToBottom = lookupID(a, attr, topToBottom);
break;
case BOTTOM_TO_TOP:
bottomToTop = lookupID(a, attr, bottomToTop);
break;
case BOTTOM_TO_BOTTOM:
bottomToBottom = lookupID(a, attr, bottomToBottom);
break;
case BASELINE_TO_BASELINE:
baselineToBaseline = lookupID(a, attr, baselineToBaseline);
break;
case BASELINE_TO_TOP:
baselineToTop = lookupID(a, attr, baselineToTop);
break;
case BASELINE_TO_BOTTOM:
baselineToBottom = lookupID(a, attr, baselineToBottom);
break;
case EDITOR_ABSOLUTE_X:
editorAbsoluteX = a.getDimensionPixelOffset(attr, editorAbsoluteX);
break;
case EDITOR_ABSOLUTE_Y:
editorAbsoluteY = a.getDimensionPixelOffset(attr, editorAbsoluteY);
break;
case GUIDE_BEGIN:
guideBegin = a.getDimensionPixelOffset(attr, guideBegin);
break;
case GUIDE_END:
guideEnd = a.getDimensionPixelOffset(attr, guideEnd);
break;
case GUIDE_PERCENT:
guidePercent = a.getFloat(attr, guidePercent);
break;
case GUIDE_USE_RTL:
guidelineUseRtl = a.getBoolean(attr, guidelineUseRtl);
break;
case ORIENTATION:
orientation = a.getInt(attr, orientation);
break;
case START_TO_END:
startToEnd = lookupID(a, attr, startToEnd);
break;
case START_TO_START:
startToStart = lookupID(a, attr, startToStart);
break;
case END_TO_START:
endToStart = lookupID(a, attr, endToStart);
break;
case END_TO_END:
endToEnd = lookupID(a, attr, endToEnd);
break;
case CIRCLE:
circleConstraint = lookupID(a, attr, circleConstraint);
break;
case CIRCLE_RADIUS:
circleRadius = a.getDimensionPixelSize(attr, circleRadius);
break;
case CIRCLE_ANGLE:
circleAngle = a.getFloat(attr, circleAngle);
break;
case GONE_LEFT_MARGIN:
goneLeftMargin = a.getDimensionPixelSize(attr, goneLeftMargin);
break;
case GONE_TOP_MARGIN:
goneTopMargin = a.getDimensionPixelSize(attr, goneTopMargin);
break;
case GONE_RIGHT_MARGIN:
goneRightMargin = a.getDimensionPixelSize(attr, goneRightMargin);
break;
case GONE_BOTTOM_MARGIN:
goneBottomMargin = a.getDimensionPixelSize(attr, goneBottomMargin);
break;
case GONE_START_MARGIN:
goneStartMargin = a.getDimensionPixelSize(attr, goneStartMargin);
break;
case GONE_END_MARGIN:
goneEndMargin = a.getDimensionPixelSize(attr, goneEndMargin);
break;
case GONE_BASELINE_MARGIN:
goneBaselineMargin = a.getDimensionPixelSize(attr, goneBaselineMargin);
break;
case HORIZONTAL_BIAS:
horizontalBias = a.getFloat(attr, horizontalBias);
break;
case VERTICAL_BIAS:
verticalBias = a.getFloat(attr, verticalBias);
break;
case LEFT_MARGIN:
leftMargin = a.getDimensionPixelSize(attr, leftMargin);
break;
case RIGHT_MARGIN:
rightMargin = a.getDimensionPixelSize(attr, rightMargin);
break;
case START_MARGIN:
startMargin = a.getDimensionPixelSize(attr, startMargin);
break;
case END_MARGIN:
endMargin = a.getDimensionPixelSize(attr, endMargin);
break;
case TOP_MARGIN:
topMargin = a.getDimensionPixelSize(attr, topMargin);
break;
case BOTTOM_MARGIN:
bottomMargin = a.getDimensionPixelSize(attr, bottomMargin);
break;
case BASELINE_MARGIN:
baselineMargin = a.getDimensionPixelSize(attr, baselineMargin);
break;
case LAYOUT_WIDTH:
mWidth = a.getLayoutDimension(attr, mWidth);
break;
case LAYOUT_HEIGHT:
mHeight = a.getLayoutDimension(attr, mHeight);
break;
case LAYOUT_CONSTRAINT_WIDTH:
ConstraintSet.parseDimensionConstraints(this, a, attr, HORIZONTAL);
break;
case LAYOUT_CONSTRAINT_HEIGHT:
ConstraintSet.parseDimensionConstraints(this, a, attr, VERTICAL);
break;
case WIDTH_DEFAULT:
widthDefault = a.getInt(attr, widthDefault);
break;
case HEIGHT_DEFAULT:
heightDefault = a.getInt(attr, heightDefault);
break;
case VERTICAL_WEIGHT:
verticalWeight = a.getFloat(attr, verticalWeight);
break;
case HORIZONTAL_WEIGHT:
horizontalWeight = a.getFloat(attr, horizontalWeight);
break;
case VERTICAL_STYLE:
verticalChainStyle = a.getInt(attr, verticalChainStyle);
break;
case HORIZONTAL_STYLE:
horizontalChainStyle = a.getInt(attr, horizontalChainStyle);
break;
case DIMENSION_RATIO:
dimensionRatio = a.getString(attr);
break;
case HEIGHT_MAX:
heightMax = a.getDimensionPixelSize(attr, heightMax);
break;
case WIDTH_MAX:
widthMax = a.getDimensionPixelSize(attr, widthMax);
break;
case HEIGHT_MIN:
heightMin = a.getDimensionPixelSize(attr, heightMin);
break;
case WIDTH_MIN:
widthMin = a.getDimensionPixelSize(attr, widthMin);
break;
case WIDTH_PERCENT:
widthPercent = a.getFloat(attr, 1);
break;
case HEIGHT_PERCENT:
heightPercent = a.getFloat(attr, 1);
break;
case CONSTRAINED_WIDTH:
constrainedWidth = a.getBoolean(attr, constrainedWidth);
break;
case CONSTRAINED_HEIGHT:
constrainedHeight = a.getBoolean(attr, constrainedHeight);
break;
case CHAIN_USE_RTL:
Log.e(TAG, "CURRENTLY UNSUPPORTED"); // TODO add support or remove
// TODO add support or remove c.mChainUseRtl
// = a.getBoolean(attr,c.mChainUseRtl);
break;
case BARRIER_DIRECTION:
mBarrierDirection = a.getInt(attr, mBarrierDirection);
break;
case LAYOUT_WRAP_BEHAVIOR:
mWrapBehavior = a.getInt(attr, mWrapBehavior);
break;
case BARRIER_MARGIN:
mBarrierMargin = a.getDimensionPixelSize(attr, mBarrierMargin);
break;
case CONSTRAINT_REFERENCED_IDS:
mReferenceIdString = a.getString(attr);
break;
case BARRIER_ALLOWS_GONE_WIDGETS:
mBarrierAllowsGoneWidgets = a.getBoolean(attr, mBarrierAllowsGoneWidgets);
break;
case CONSTRAINT_TAG:
mConstraintTag = a.getString(attr);
break;
case UNUSED:
Log.w(TAG,
"unused attribute 0x" + Integer.toHexString(attr)
+ " " + sMapToConstant.get(attr));
break;
default:
Log.w(TAG,
"Unknown attribute 0x" + Integer.toHexString(attr)
+ " " + sMapToConstant.get(attr));
}
}
a.recycle();
}
/**
* Print the content to a string
* @param scene
* @param stringBuilder
*/
public void dump(MotionScene scene, StringBuilder stringBuilder) {
Field[] fields = this.getClass().getDeclaredFields();
stringBuilder.append("\n");
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
String name = field.getName();
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
try {
Object value = field.get(this);
Class<?> type = field.getType();
if (type == Integer.TYPE) {
Integer iValue = (Integer) value;
if (iValue != UNSET) {
String stringId = scene.lookUpConstraintName(iValue);
stringBuilder.append(" ");
stringBuilder.append(name);
stringBuilder.append(" = \"");
stringBuilder.append((stringId == null) ? iValue : stringId);
stringBuilder.append("\"\n");
}
} else if (type == Float.TYPE) {
Float fValue = (Float) value;
if (fValue != UNSET) {
stringBuilder.append(" ");
stringBuilder.append(name);
stringBuilder.append(" = \"");
stringBuilder.append(fValue);
stringBuilder.append("\"\n");
}
}
} catch (IllegalAccessException e) {
Log.e(TAG, "Error accessing ConstraintSet field", e);
}
}
}
}
/**
*
*/
public static class Transform {
public boolean mApply = false;
public float rotation = 0;
public float rotationX = 0;
public float rotationY = 0;
public float scaleX = 1;
public float scaleY = 1;
public float transformPivotX = Float.NaN;
public float transformPivotY = Float.NaN;
public int transformPivotTarget = UNSET;
public float translationX = 0;
public float translationY = 0;
public float translationZ = 0;
public boolean applyElevation = false;
public float elevation = 0;
/**
* Copy Transform from src
* @param src
*/
public void copyFrom(Transform src) {
mApply = src.mApply;
rotation = src.rotation;
rotationX = src.rotationX;
rotationY = src.rotationY;
scaleX = src.scaleX;
scaleY = src.scaleY;
transformPivotX = src.transformPivotX;
transformPivotY = src.transformPivotY;
transformPivotTarget = src.transformPivotTarget;
translationX = src.translationX;
translationY = src.translationY;
translationZ = src.translationZ;
applyElevation = src.applyElevation;
elevation = src.elevation;
}
private static SparseIntArray sMapToConstant = new SparseIntArray();
private static final int ROTATION = 1;
private static final int ROTATION_X = 2;
private static final int ROTATION_Y = 3;
private static final int SCALE_X = 4;
private static final int SCALE_Y = 5;
private static final int TRANSFORM_PIVOT_X = 6;
private static final int TRANSFORM_PIVOT_Y = 7;
private static final int TRANSLATION_X = 8;
private static final int TRANSLATION_Y = 9;
private static final int TRANSLATION_Z = 10;
private static final int ELEVATION = 11;
private static final int TRANSFORM_PIVOT_TARGET = 12;
static {
sMapToConstant.append(R.styleable.Transform_android_rotation, ROTATION);
sMapToConstant.append(R.styleable.Transform_android_rotationX, ROTATION_X);
sMapToConstant.append(R.styleable.Transform_android_rotationY, ROTATION_Y);
sMapToConstant.append(R.styleable.Transform_android_scaleX, SCALE_X);
sMapToConstant.append(R.styleable.Transform_android_scaleY, SCALE_Y);
sMapToConstant.append(R.styleable.Transform_android_transformPivotX, TRANSFORM_PIVOT_X);
sMapToConstant.append(R.styleable.Transform_android_transformPivotY, TRANSFORM_PIVOT_Y);
sMapToConstant.append(R.styleable.Transform_android_translationX, TRANSLATION_X);
sMapToConstant.append(R.styleable.Transform_android_translationY, TRANSLATION_Y);
sMapToConstant.append(R.styleable.Transform_android_translationZ, TRANSLATION_Z);
sMapToConstant.append(R.styleable.Transform_android_elevation, ELEVATION);
sMapToConstant.append(R.styleable.Transform_transformPivotTarget,
TRANSFORM_PIVOT_TARGET);
}
void fillFromAttributeList(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Transform);
mApply = true;
final int count = a.getIndexCount();
for (int i = 0; i < count; i++) {
int attr = a.getIndex(i);
switch (sMapToConstant.get(attr)) {
case ROTATION:
rotation = a.getFloat(attr, rotation);
break;
case ROTATION_X:
rotationX = a.getFloat(attr, rotationX);
break;
case ROTATION_Y:
rotationY = a.getFloat(attr, rotationY);
break;
case SCALE_X:
scaleX = a.getFloat(attr, scaleX);
break;
case SCALE_Y:
scaleY = a.getFloat(attr, scaleY);
break;
case TRANSFORM_PIVOT_X:
transformPivotX = a.getDimension(attr, transformPivotX);
break;
case TRANSFORM_PIVOT_Y:
transformPivotY = a.getDimension(attr, transformPivotY);
break;
case TRANSFORM_PIVOT_TARGET:
transformPivotTarget = lookupID(a, attr, transformPivotTarget);
break;
case TRANSLATION_X:
translationX = a.getDimension(attr, translationX);
break;
case TRANSLATION_Y:
translationY = a.getDimension(attr, translationY);
break;
case TRANSLATION_Z:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
translationZ = a.getDimension(attr, translationZ);
}
break;
case ELEVATION:
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
applyElevation = true;
elevation = a.getDimension(attr, elevation);
}
break;
}
}
a.recycle();
}
}
/**
*
*/
public static class PropertySet {
public boolean mApply = false;
public int visibility = View.VISIBLE;
public int mVisibilityMode = VISIBILITY_MODE_NORMAL;
public float alpha = 1;
public float mProgress = Float.NaN;
// @TODO: add description
/**
*
* @param src
*/
public void copyFrom(PropertySet src) {
mApply = src.mApply;
visibility = src.visibility;
alpha = src.alpha;
mProgress = src.mProgress;
mVisibilityMode = src.mVisibilityMode;
}
void fillFromAttributeList(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PropertySet);
mApply = true;
final int count = a.getIndexCount();
for (int i = 0; i < count; i++) {
int attr = a.getIndex(i);
if (attr == R.styleable.PropertySet_android_alpha) {
alpha = a.getFloat(attr, alpha);
} else if (attr == R.styleable.PropertySet_android_visibility) {
visibility = a.getInt(attr, visibility);
visibility = VISIBILITY_FLAGS[visibility];
} else if (attr == R.styleable.PropertySet_visibilityMode) {
mVisibilityMode = a.getInt(attr, mVisibilityMode);
} else if (attr == R.styleable.PropertySet_motionProgress) {
mProgress = a.getFloat(attr, mProgress);
}
}
a.recycle();
}
}
/**
*
*/
public static class Motion {
public boolean mApply = false;
public int mAnimateRelativeTo = Layout.UNSET;
public int mAnimateCircleAngleTo = 0;
public String mTransitionEasing = null;
public int mPathMotionArc = Layout.UNSET;
public int mDrawPath = 0;
public float mMotionStagger = Float.NaN;
public int mPolarRelativeTo = Layout.UNSET;
public float mPathRotate = Float.NaN;
public float mQuantizeMotionPhase = Float.NaN;
public int mQuantizeMotionSteps = Layout.UNSET;
public String mQuantizeInterpolatorString = null;
public int mQuantizeInterpolatorType = INTERPOLATOR_UNDEFINED; // undefined
public int mQuantizeInterpolatorID = -1;
private static final int INTERPOLATOR_REFERENCE_ID = -2;
private static final int SPLINE_STRING = -1;
private static final int INTERPOLATOR_UNDEFINED = -3;
// @TODO: add description
/**
*
* @param src
*/
public void copyFrom(Motion src) {
mApply = src.mApply;
mAnimateRelativeTo = src.mAnimateRelativeTo;
mTransitionEasing = src.mTransitionEasing;
mPathMotionArc = src.mPathMotionArc;
mDrawPath = src.mDrawPath;
mPathRotate = src.mPathRotate;
mMotionStagger = src.mMotionStagger;
mPolarRelativeTo = src.mPolarRelativeTo;
}
private static SparseIntArray sMapToConstant = new SparseIntArray();
private static final int TRANSITION_PATH_ROTATE = 1;
private static final int PATH_MOTION_ARC = 2;
private static final int TRANSITION_EASING = 3;
private static final int MOTION_DRAW_PATH = 4;
private static final int ANIMATE_RELATIVE_TO = 5;
private static final int ANIMATE_CIRCLE_ANGLE_TO = 6;
private static final int MOTION_STAGGER = 7;
private static final int QUANTIZE_MOTION_STEPS = 8;
private static final int QUANTIZE_MOTION_PHASE = 9;
private static final int QUANTIZE_MOTION_INTERPOLATOR = 10;
static {
sMapToConstant.append(R.styleable.Motion_motionPathRotate, TRANSITION_PATH_ROTATE);
sMapToConstant.append(R.styleable.Motion_pathMotionArc, PATH_MOTION_ARC);
sMapToConstant.append(R.styleable.Motion_transitionEasing, TRANSITION_EASING);
sMapToConstant.append(R.styleable.Motion_drawPath, MOTION_DRAW_PATH);
sMapToConstant.append(R.styleable.Motion_animateRelativeTo, ANIMATE_RELATIVE_TO);
sMapToConstant.append(R.styleable.Motion_animateCircleAngleTo, ANIMATE_CIRCLE_ANGLE_TO);
sMapToConstant.append(R.styleable.Motion_motionStagger, MOTION_STAGGER);
sMapToConstant.append(R.styleable.Motion_quantizeMotionSteps, QUANTIZE_MOTION_STEPS);
sMapToConstant.append(R.styleable.Motion_quantizeMotionPhase, QUANTIZE_MOTION_PHASE);
sMapToConstant.append(R.styleable.Motion_quantizeMotionInterpolator,
QUANTIZE_MOTION_INTERPOLATOR);
}
void fillFromAttributeList(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Motion);
mApply = true;
final int count = a.getIndexCount();
for (int i = 0; i < count; i++) {
int attr = a.getIndex(i);
switch (sMapToConstant.get(attr)) {
case TRANSITION_PATH_ROTATE:
mPathRotate = a.getFloat(attr, mPathRotate);
break;
case PATH_MOTION_ARC:
mPathMotionArc = a.getInt(attr, mPathMotionArc);
break;
case TRANSITION_EASING:
TypedValue type = a.peekValue(attr);
if (type.type == TypedValue.TYPE_STRING) {
mTransitionEasing = a.getString(attr);
} else {
mTransitionEasing = Easing.NAMED_EASING[a.getInteger(attr, 0)];
}
break;
case MOTION_DRAW_PATH:
mDrawPath = a.getInt(attr, 0);
break;
case ANIMATE_RELATIVE_TO:
mAnimateRelativeTo = lookupID(a, attr, mAnimateRelativeTo);
break;
case ANIMATE_CIRCLE_ANGLE_TO:
mAnimateCircleAngleTo = a.getInteger(attr, mAnimateCircleAngleTo);
break;
case MOTION_STAGGER:
mMotionStagger = a.getFloat(attr, mMotionStagger);
break;
case QUANTIZE_MOTION_STEPS:
mQuantizeMotionSteps = a.getInteger(attr, mQuantizeMotionSteps);
break;
case QUANTIZE_MOTION_PHASE:
mQuantizeMotionPhase = a.getFloat(attr, mQuantizeMotionPhase);
break;
case QUANTIZE_MOTION_INTERPOLATOR:
type = a.peekValue(attr);
if (type.type == TypedValue.TYPE_REFERENCE) {
mQuantizeInterpolatorID = a.getResourceId(attr, -1);
if (mQuantizeInterpolatorID != -1) {
mQuantizeInterpolatorType = INTERPOLATOR_REFERENCE_ID;
}
} else if (type.type == TypedValue.TYPE_STRING) {
mQuantizeInterpolatorString = a.getString(attr);
if (mQuantizeInterpolatorString.indexOf("/") > 0) {
mQuantizeInterpolatorID = a.getResourceId(attr, -1);
mQuantizeInterpolatorType = INTERPOLATOR_REFERENCE_ID;
} else {
mQuantizeInterpolatorType = SPLINE_STRING;
}
} else {
mQuantizeInterpolatorType = a.getInteger(attr, mQuantizeInterpolatorID);
}
break;
}
}
a.recycle();
}
}
/**
*
*/
public static class Constraint {
int mViewId;
String mTargetString;
public final PropertySet propertySet = new PropertySet();
public final Motion motion = new Motion();
public final Layout layout = new Layout();
public final Transform transform = new Transform();
public HashMap<String, ConstraintAttribute> mCustomConstraints = new HashMap<>();
Delta mDelta;
static class Delta {
private static final int INITIAL_BOOLEAN = 4;
private static final int INITIAL_INT = 10;
private static final int INITIAL_FLOAT = 10;
private static final int INITIAL_STRING = 5;
int[] mTypeInt = new int[INITIAL_INT];
int[] mValueInt = new int[INITIAL_INT];
int mCountInt = 0;
void add(int type, int value) {
if (mCountInt >= mTypeInt.length) {
mTypeInt = Arrays.copyOf(mTypeInt, mTypeInt.length * 2);
mValueInt = Arrays.copyOf(mValueInt, mValueInt.length * 2);
}
mTypeInt[mCountInt] = type;
mValueInt[mCountInt++] = value;
}
int[] mTypeFloat = new int[INITIAL_FLOAT];
float[] mValueFloat = new float[INITIAL_FLOAT];
int mCountFloat = 0;
void add(int type, float value) {
if (mCountFloat >= mTypeFloat.length) {
mTypeFloat = Arrays.copyOf(mTypeFloat, mTypeFloat.length * 2);
mValueFloat = Arrays.copyOf(mValueFloat, mValueFloat.length * 2);
}
mTypeFloat[mCountFloat] = type;
mValueFloat[mCountFloat++] = value;
}
int[] mTypeString = new int[INITIAL_STRING];
String[] mValueString = new String[INITIAL_STRING];
int mCountString = 0;
void add(int type, String value) {
if (mCountString >= mTypeString.length) {
mTypeString = Arrays.copyOf(mTypeString, mTypeString.length * 2);
mValueString = Arrays.copyOf(mValueString, mValueString.length * 2);
}
mTypeString[mCountString] = type;
mValueString[mCountString++] = value;
}
int[] mTypeBoolean = new int[INITIAL_BOOLEAN];
boolean[] mValueBoolean = new boolean[INITIAL_BOOLEAN];
int mCountBoolean = 0;
void add(int type, boolean value) {
if (mCountBoolean >= mTypeBoolean.length) {
mTypeBoolean = Arrays.copyOf(mTypeBoolean, mTypeBoolean.length * 2);
mValueBoolean = Arrays.copyOf(mValueBoolean, mValueBoolean.length * 2);
}
mTypeBoolean[mCountBoolean] = type;
mValueBoolean[mCountBoolean++] = value;
}
void applyDelta(Constraint c) {
for (int i = 0; i < mCountInt; i++) {
setDeltaValue(c, mTypeInt[i], mValueInt[i]);
}
for (int i = 0; i < mCountFloat; i++) {
setDeltaValue(c, mTypeFloat[i], mValueFloat[i]);
}
for (int i = 0; i < mCountString; i++) {
setDeltaValue(c, mTypeString[i], mValueString[i]);
}
for (int i = 0; i < mCountBoolean; i++) {
setDeltaValue(c, mTypeBoolean[i], mValueBoolean[i]);
}
}
@SuppressLint("LogConditional")
void printDelta(String tag) {
Log.v(tag, "int");
for (int i = 0; i < mCountInt; i++) {
Log.v(tag, mTypeInt[i] + " = " + mValueInt[i]);
}
Log.v(tag, "float");
for (int i = 0; i < mCountFloat; i++) {
Log.v(tag, mTypeFloat[i] + " = " + mValueFloat[i]);
}
Log.v(tag, "strings");
for (int i = 0; i < mCountString; i++) {
Log.v(tag, mTypeString[i] + " = " + mValueString[i]);
}
Log.v(tag, "boolean");
for (int i = 0; i < mCountBoolean; i++) {
Log.v(tag, mTypeBoolean[i] + " = " + mValueBoolean[i]);
}
}
}
/**
* Apply a delta to a constraint
* @param c
*/
public void applyDelta(Constraint c) {
if (mDelta != null) {
mDelta.applyDelta(c);
}
}
/**
* Apply a delta file
* @param tag
*/
public void printDelta(String tag) {
if (mDelta != null) {
mDelta.printDelta(tag);
} else {
Log.v(tag, "DELTA IS NULL");
}
}
private ConstraintAttribute get(String attributeName, AttributeType attributeType) {
ConstraintAttribute ret;
if (mCustomConstraints.containsKey(attributeName)) {
ret = mCustomConstraints.get(attributeName);
if (ret.getType() != attributeType) {
throw new IllegalArgumentException(
"ConstraintAttribute is already a " + ret.getType().name());
}
} else {
ret = new ConstraintAttribute(attributeName, attributeType);
mCustomConstraints.put(attributeName, ret);
}
return ret;
}
private void setStringValue(String attributeName, String value) {
get(attributeName, AttributeType.STRING_TYPE).setStringValue(value);
}
private void setFloatValue(String attributeName, float value) {
get(attributeName, AttributeType.FLOAT_TYPE).setFloatValue(value);
}
private void setIntValue(String attributeName, int value) {
get(attributeName, AttributeType.INT_TYPE).setIntValue(value);
}
private void setColorValue(String attributeName, int value) {
get(attributeName, AttributeType.COLOR_TYPE).setColorValue(value);
}
/**
* Return a copy of the Constraint
* @return
*/
@Override
public Constraint clone() {
Constraint clone = new Constraint();
clone.layout.copyFrom(layout);
clone.motion.copyFrom(motion);
clone.propertySet.copyFrom(propertySet);
clone.transform.copyFrom(transform);
clone.mViewId = mViewId;
clone.mDelta = mDelta;
return clone;
}
private void fillFromConstraints(ConstraintHelper helper,
int viewId,
Constraints.LayoutParams param) {
fillFromConstraints(viewId, param);
if (helper instanceof Barrier) {
layout.mHelperType = BARRIER_TYPE;
Barrier barrier = (Barrier) helper;
layout.mBarrierDirection = barrier.getType();
layout.mReferenceIds = barrier.getReferencedIds();
layout.mBarrierMargin = barrier.getMargin();
}
}
private void fillFromConstraints(int viewId, Constraints.LayoutParams param) {
fillFrom(viewId, param);
propertySet.alpha = param.alpha;
transform.rotation = param.rotation;
transform.rotationX = param.rotationX;
transform.rotationY = param.rotationY;
transform.scaleX = param.scaleX;
transform.scaleY = param.scaleY;
transform.transformPivotX = param.transformPivotX;
transform.transformPivotY = param.transformPivotY;
transform.translationX = param.translationX;
transform.translationY = param.translationY;
transform.translationZ = param.translationZ;
transform.elevation = param.elevation;
transform.applyElevation = param.applyElevation;
}
private void fillFrom(int viewId, ConstraintLayout.LayoutParams param) {
mViewId = viewId;
layout.leftToLeft = param.leftToLeft;
layout.leftToRight = param.leftToRight;
layout.rightToLeft = param.rightToLeft;
layout.rightToRight = param.rightToRight;
layout.topToTop = param.topToTop;
layout.topToBottom = param.topToBottom;
layout.bottomToTop = param.bottomToTop;
layout.bottomToBottom = param.bottomToBottom;
layout.baselineToBaseline = param.baselineToBaseline;
layout.baselineToTop = param.baselineToTop;
layout.baselineToBottom = param.baselineToBottom;
layout.startToEnd = param.startToEnd;
layout.startToStart = param.startToStart;
layout.endToStart = param.endToStart;
layout.endToEnd = param.endToEnd;
layout.horizontalBias = param.horizontalBias;
layout.verticalBias = param.verticalBias;
layout.dimensionRatio = param.dimensionRatio;
layout.circleConstraint = param.circleConstraint;
layout.circleRadius = param.circleRadius;
layout.circleAngle = param.circleAngle;
layout.editorAbsoluteX = param.editorAbsoluteX;
layout.editorAbsoluteY = param.editorAbsoluteY;
layout.orientation = param.orientation;
layout.guidePercent = param.guidePercent;
layout.guideBegin = param.guideBegin;
layout.guideEnd = param.guideEnd;
layout.mWidth = param.width;
layout.mHeight = param.height;
layout.leftMargin = param.leftMargin;
layout.rightMargin = param.rightMargin;
layout.topMargin = param.topMargin;
layout.bottomMargin = param.bottomMargin;
layout.baselineMargin = param.baselineMargin;
layout.verticalWeight = param.verticalWeight;
layout.horizontalWeight = param.horizontalWeight;
layout.verticalChainStyle = param.verticalChainStyle;
layout.horizontalChainStyle = param.horizontalChainStyle;
layout.constrainedWidth = param.constrainedWidth;
layout.constrainedHeight = param.constrainedHeight;
layout.widthDefault = param.matchConstraintDefaultWidth;
layout.heightDefault = param.matchConstraintDefaultHeight;
layout.widthMax = param.matchConstraintMaxWidth;
layout.heightMax = param.matchConstraintMaxHeight;
layout.widthMin = param.matchConstraintMinWidth;
layout.heightMin = param.matchConstraintMinHeight;
layout.widthPercent = param.matchConstraintPercentWidth;
layout.heightPercent = param.matchConstraintPercentHeight;
layout.mConstraintTag = param.constraintTag;
layout.goneTopMargin = param.goneTopMargin;
layout.goneBottomMargin = param.goneBottomMargin;
layout.goneLeftMargin = param.goneLeftMargin;
layout.goneRightMargin = param.goneRightMargin;
layout.goneStartMargin = param.goneStartMargin;
layout.goneEndMargin = param.goneEndMargin;
layout.goneBaselineMargin = param.goneBaselineMargin;
layout.mWrapBehavior = param.wrapBehaviorInParent;
layout.endMargin = param.getMarginEnd();
layout.startMargin = param.getMarginStart();
}
/**
* apply ConstraintSet to the layout params
* @param param
*/
public void applyTo(ConstraintLayout.LayoutParams param) {
param.leftToLeft = layout.leftToLeft;
param.leftToRight = layout.leftToRight;
param.rightToLeft = layout.rightToLeft;
param.rightToRight = layout.rightToRight;
param.topToTop = layout.topToTop;
param.topToBottom = layout.topToBottom;
param.bottomToTop = layout.bottomToTop;
param.bottomToBottom = layout.bottomToBottom;
param.baselineToBaseline = layout.baselineToBaseline;
param.baselineToTop = layout.baselineToTop;
param.baselineToBottom = layout.baselineToBottom;
param.startToEnd = layout.startToEnd;
param.startToStart = layout.startToStart;
param.endToStart = layout.endToStart;
param.endToEnd = layout.endToEnd;
param.leftMargin = layout.leftMargin;
param.rightMargin = layout.rightMargin;
param.topMargin = layout.topMargin;
param.bottomMargin = layout.bottomMargin;
param.goneStartMargin = layout.goneStartMargin;
param.goneEndMargin = layout.goneEndMargin;
param.goneTopMargin = layout.goneTopMargin;
param.goneBottomMargin = layout.goneBottomMargin;
param.horizontalBias = layout.horizontalBias;
param.verticalBias = layout.verticalBias;
param.circleConstraint = layout.circleConstraint;
param.circleRadius = layout.circleRadius;
param.circleAngle = layout.circleAngle;
param.dimensionRatio = layout.dimensionRatio;
param.editorAbsoluteX = layout.editorAbsoluteX;
param.editorAbsoluteY = layout.editorAbsoluteY;
param.verticalWeight = layout.verticalWeight;
param.horizontalWeight = layout.horizontalWeight;
param.verticalChainStyle = layout.verticalChainStyle;
param.horizontalChainStyle = layout.horizontalChainStyle;
param.constrainedWidth = layout.constrainedWidth;
param.constrainedHeight = layout.constrainedHeight;
param.matchConstraintDefaultWidth = layout.widthDefault;
param.matchConstraintDefaultHeight = layout.heightDefault;
param.matchConstraintMaxWidth = layout.widthMax;
param.matchConstraintMaxHeight = layout.heightMax;
param.matchConstraintMinWidth = layout.widthMin;
param.matchConstraintMinHeight = layout.heightMin;
param.matchConstraintPercentWidth = layout.widthPercent;
param.matchConstraintPercentHeight = layout.heightPercent;
param.orientation = layout.orientation;
param.guidePercent = layout.guidePercent;
param.guideBegin = layout.guideBegin;
param.guideEnd = layout.guideEnd;
param.width = layout.mWidth;
param.height = layout.mHeight;
if (layout.mConstraintTag != null) {
param.constraintTag = layout.mConstraintTag;
}
param.wrapBehaviorInParent = layout.mWrapBehavior;
param.setMarginStart(layout.startMargin);
param.setMarginEnd(layout.endMargin);
param.validate();
}
}
/**
* Copy the constraints from a layout.
*
* @param context the context for the layout inflation
* @param constraintLayoutId the id of the layout file
*/
public void clone(Context context, int constraintLayoutId) {
clone((ConstraintLayout) LayoutInflater.from(context).inflate(constraintLayoutId, null));
}
/**
* Copy the constraints from a layout.
*
* @param set constraint set to copy
*/
public void clone(ConstraintSet set) {
mConstraints.clear();
for (Integer key : set.mConstraints.keySet()) {
Constraint constraint = set.mConstraints.get(key);
if (constraint == null) {
continue;
}
mConstraints.put(key, constraint.clone());
}
}
/**
* Copy the layout parameters of a ConstraintLayout.
*
* @param constraintLayout The ConstraintLayout to be copied
*/
public void clone(ConstraintLayout constraintLayout) {
int count = constraintLayout.getChildCount();
mConstraints.clear();
for (int i = 0; i < count; i++) {
View view = constraintLayout.getChildAt(i);
ConstraintLayout.LayoutParams param =
(ConstraintLayout.LayoutParams) view.getLayoutParams();
int id = view.getId();
if (mForceId && id == -1) {
throw new RuntimeException("All children of ConstraintLayout must "
+ "have ids to use ConstraintSet");
}
if (!mConstraints.containsKey(id)) {
mConstraints.put(id, new Constraint());
}
Constraint constraint = mConstraints.get(id);
if (constraint == null) {
continue;
}
constraint.mCustomConstraints =
ConstraintAttribute.extractAttributes(mSavedAttributes, view);
constraint.fillFrom(id, param);
constraint.propertySet.visibility = view.getVisibility();
constraint.propertySet.alpha = view.getAlpha();
constraint.transform.rotation = view.getRotation();
constraint.transform.rotationX = view.getRotationX();
constraint.transform.rotationY = view.getRotationY();
constraint.transform.scaleX = view.getScaleX();
constraint.transform.scaleY = view.getScaleY();
float pivotX = view.getPivotX(); // we assume it is not set if set to 0.0
float pivotY = view.getPivotY(); // we assume it is not set if set to 0.0
if (pivotX != 0.0 || pivotY != 0.0) {
constraint.transform.transformPivotX = pivotX;
constraint.transform.transformPivotY = pivotY;
}
constraint.transform.translationX = view.getTranslationX();
constraint.transform.translationY = view.getTranslationY();
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
constraint.transform.translationZ = view.getTranslationZ();
if (constraint.transform.applyElevation) {
constraint.transform.elevation = view.getElevation();
}
}
if (view instanceof Barrier) {
Barrier barrier = ((Barrier) view);
constraint.layout.mBarrierAllowsGoneWidgets = barrier.getAllowsGoneWidget();
constraint.layout.mReferenceIds = barrier.getReferencedIds();
constraint.layout.mBarrierDirection = barrier.getType();
constraint.layout.mBarrierMargin = barrier.getMargin();
}
}
}
/**
* Copy the layout parameters of a ConstraintLayout.
*
* @param constraints The ConstraintLayout to be copied
*/
public void clone(Constraints constraints) {
int count = constraints.getChildCount();
mConstraints.clear();
for (int i = 0; i < count; i++) {
View view = constraints.getChildAt(i);
Constraints.LayoutParams param = (Constraints.LayoutParams) view.getLayoutParams();
int id = view.getId();
if (mForceId && id == -1) {
throw new RuntimeException("All children of ConstraintLayout "
+ "must have ids to use ConstraintSet");
}
if (!mConstraints.containsKey(id)) {
mConstraints.put(id, new Constraint());
}
Constraint constraint = mConstraints.get(id);
if (constraint == null) {
continue;
}
if (view instanceof ConstraintHelper) {
ConstraintHelper helper = (ConstraintHelper) view;
constraint.fillFromConstraints(helper, id, param);
}
constraint.fillFromConstraints(id, param);
}
}
/**
* Apply the constraints to a ConstraintLayout.
*
* @param constraintLayout to be modified
*/
public void applyTo(ConstraintLayout constraintLayout) {
applyToInternal(constraintLayout, true);
constraintLayout.setConstraintSet(null);
constraintLayout.requestLayout();
}
/**
* Apply the constraints to a ConstraintLayout.
*
* @param constraintLayout to be modified
*/
public void applyToWithoutCustom(ConstraintLayout constraintLayout) {
applyToInternal(constraintLayout, false);
constraintLayout.setConstraintSet(null);
}
/**
* Apply custom attributes alone
*
* @param constraintLayout
*/
public void applyCustomAttributes(ConstraintLayout constraintLayout) {
int count = constraintLayout.getChildCount();
for (int i = 0; i < count; i++) {
View view = constraintLayout.getChildAt(i);
int id = view.getId();
if (!mConstraints.containsKey(id)) {
Log.w(TAG, "id unknown " + Debug.getName(view));
continue;
}
if (mForceId && id == -1) {
throw new RuntimeException("All children of ConstraintLayout "
+ "must have ids to use ConstraintSet");
}
if (mConstraints.containsKey(id)) {
Constraint constraint = mConstraints.get(id);
if (constraint == null) {
continue;
}
ConstraintAttribute.setAttributes(view, constraint.mCustomConstraints);
}
}
}
/**
* Apply Layout to Helper widget
*
* @param helper
* @param child
* @param layoutParams
* @param mapIdToWidget
*/
public void applyToHelper(ConstraintHelper helper, ConstraintWidget child,
LayoutParams layoutParams,
SparseArray<ConstraintWidget> mapIdToWidget) {
int id = helper.getId();
if (mConstraints.containsKey(id)) {
Constraint constraint = mConstraints.get(id);
if (constraint != null && child instanceof HelperWidget) {
HelperWidget helperWidget = (HelperWidget) child;
helper.loadParameters(constraint, helperWidget, layoutParams, mapIdToWidget);
}
}
}
/**
* Fill in a ConstraintLayout LayoutParam based on the id.
*
* @param id Id of the view
* @param layoutParams LayoutParams to be filled
*/
public void applyToLayoutParams(int id, ConstraintLayout.LayoutParams layoutParams) {
if (mConstraints.containsKey(id)) {
Constraint constraint = mConstraints.get(id);
if (constraint != null) {
constraint.applyTo(layoutParams);
}
}
}
/**
* Used to set constraints when used by constraint layout
*/
void applyToInternal(ConstraintLayout constraintLayout, boolean applyPostLayout) {
int count = constraintLayout.getChildCount();
HashSet<Integer> used = new HashSet<Integer>(mConstraints.keySet());
for (int i = 0; i < count; i++) {
View view = constraintLayout.getChildAt(i);
int id = view.getId();
if (!mConstraints.containsKey(id)) {
Log.w(TAG, "id unknown " + Debug.getName(view));
continue;
}
if (mForceId && id == -1) {
throw new RuntimeException("All children of ConstraintLayout "
+ "must have ids to use ConstraintSet");
}
if (id == -1) {
continue;
}
if (mConstraints.containsKey(id)) {
used.remove(id);
Constraint constraint = mConstraints.get(id);
if (constraint == null) {
continue;
}
if (view instanceof Barrier) {
constraint.layout.mHelperType = BARRIER_TYPE;
Barrier barrier = (Barrier) view;
barrier.setId(id);
barrier.setType(constraint.layout.mBarrierDirection);
barrier.setMargin(constraint.layout.mBarrierMargin);
barrier.setAllowsGoneWidget(constraint.layout.mBarrierAllowsGoneWidgets);
if (constraint.layout.mReferenceIds != null) {
barrier.setReferencedIds(constraint.layout.mReferenceIds);
} else if (constraint.layout.mReferenceIdString != null) {
constraint.layout.mReferenceIds = convertReferenceString(barrier,
constraint.layout.mReferenceIdString);
barrier.setReferencedIds(constraint.layout.mReferenceIds);
}
}
ConstraintLayout.LayoutParams param = (ConstraintLayout.LayoutParams) view
.getLayoutParams();
param.validate();
constraint.applyTo(param);
if (applyPostLayout) {
ConstraintAttribute.setAttributes(view, constraint.mCustomConstraints);
}
view.setLayoutParams(param);
if (constraint.propertySet.mVisibilityMode == VISIBILITY_MODE_NORMAL) {
view.setVisibility(constraint.propertySet.visibility);
}
view.setAlpha(constraint.propertySet.alpha);
view.setRotation(constraint.transform.rotation);
view.setRotationX(constraint.transform.rotationX);
view.setRotationY(constraint.transform.rotationY);
view.setScaleX(constraint.transform.scaleX);
view.setScaleY(constraint.transform.scaleY);
if (constraint.transform.transformPivotTarget != UNSET) {
View layout = (View) view.getParent();
View center = layout.findViewById(
constraint.transform.transformPivotTarget);
if (center != null) {
float cy = (center.getTop() + center.getBottom()) / 2.0f;
float cx = (center.getLeft() + center.getRight()) / 2.0f;
if (view.getRight() - view.getLeft() > 0
&& view.getBottom() - view.getTop() > 0) {
float px = (cx - view.getLeft());
float py = (cy - view.getTop());
view.setPivotX(px);
view.setPivotY(py);
}
}
} else {
if (!Float.isNaN(constraint.transform.transformPivotX)) {
view.setPivotX(constraint.transform.transformPivotX);
}
if (!Float.isNaN(constraint.transform.transformPivotY)) {
view.setPivotY(constraint.transform.transformPivotY);
}
}
view.setTranslationX(constraint.transform.translationX);
view.setTranslationY(constraint.transform.translationY);
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
view.setTranslationZ(constraint.transform.translationZ);
if (constraint.transform.applyElevation) {
view.setElevation(constraint.transform.elevation);
}
}
} else {
Log.v(TAG, "WARNING NO CONSTRAINTS for view " + id);
}
}
for (Integer id : used) {
Constraint constraint = mConstraints.get(id);
if (constraint == null) {
continue;
}
if (constraint.layout.mHelperType == BARRIER_TYPE) {
Barrier barrier = new Barrier(constraintLayout.getContext());
barrier.setId(id);
if (constraint.layout.mReferenceIds != null) {
barrier.setReferencedIds(constraint.layout.mReferenceIds);
} else if (constraint.layout.mReferenceIdString != null) {
constraint.layout.mReferenceIds = convertReferenceString(barrier,
constraint.layout.mReferenceIdString);
barrier.setReferencedIds(constraint.layout.mReferenceIds);
}
barrier.setType(constraint.layout.mBarrierDirection);
barrier.setMargin(constraint.layout.mBarrierMargin);
LayoutParams param = constraintLayout
.generateDefaultLayoutParams();
barrier.validateParams();
constraint.applyTo(param);
constraintLayout.addView(barrier, param);
}
if (constraint.layout.mIsGuideline) {
Guideline g = new Guideline(constraintLayout.getContext());
g.setId(id);
ConstraintLayout.LayoutParams param =
constraintLayout.generateDefaultLayoutParams();
constraint.applyTo(param);
constraintLayout.addView(g, param);
}
}
for (int i = 0; i < count; i++) {
View view = constraintLayout.getChildAt(i);
if (view instanceof ConstraintHelper) {
ConstraintHelper constraintHelper = (ConstraintHelper) view;
constraintHelper.applyLayoutFeaturesInConstraintSet(constraintLayout);
}
}
}
/**
* Center widget between the other two widgets.
* (for sides see: {@link #TOP}, {@link #BOTTOM}, {@link #START},
* {@link #END}, {@link #LEFT}, {@link #RIGHT})
* Note, sides must be all vertical or horizontal sides.
*
* @param centerID ID of the widget to be centered
* @param firstID ID of the first widget to connect the left or top of the widget to
* @param firstSide the side of the widget to connect to
* @param firstMargin the connection margin
* @param secondId the ID of the second widget to connect to right or top of the widget to
* @param secondSide the side of the widget to connect to
* @param secondMargin the connection margin
* @param bias the ratio between two connections
*/
public void center(int centerID,
int firstID, int firstSide, int firstMargin,
int secondId, int secondSide, int secondMargin,
float bias) {
// Error checking
if (firstMargin < 0) {
throw new IllegalArgumentException("margin must be > 0");
}
if (secondMargin < 0) {
throw new IllegalArgumentException("margin must be > 0");
}
if (bias <= 0 || bias > 1) {
throw new IllegalArgumentException("bias must be between 0 and 1 inclusive");
}
if (firstSide == LEFT || firstSide == RIGHT) {
connect(centerID, LEFT, firstID, firstSide, firstMargin);
connect(centerID, RIGHT, secondId, secondSide, secondMargin);
Constraint constraint = mConstraints.get(centerID);
if (constraint != null) {
constraint.layout.horizontalBias = bias;
}
} else if (firstSide == START || firstSide == END) {
connect(centerID, START, firstID, firstSide, firstMargin);
connect(centerID, END, secondId, secondSide, secondMargin);
Constraint constraint = mConstraints.get(centerID);
if (constraint != null) {
constraint.layout.horizontalBias = bias;
}
} else {
connect(centerID, TOP, firstID, firstSide, firstMargin);
connect(centerID, BOTTOM, secondId, secondSide, secondMargin);
Constraint constraint = mConstraints.get(centerID);
if (constraint != null) {
constraint.layout.verticalBias = bias;
}
}
}
/**
* Centers the widget horizontally to the left and right side on another widgets sides.
* (for sides see: {@link #START}, {@link #END}, {@link #LEFT}, {@link #RIGHT})
*
* @param centerID ID of widget to be centered
* @param leftId The Id of the widget on the left side
* @param leftSide The side of the leftId widget to connect to
* @param leftMargin The margin on the left side
* @param rightId The Id of the widget on the right side
* @param rightSide The side of the rightId widget to connect to
* @param rightMargin The margin on the right side
* @param bias The ratio of the space on the left vs.
* right sides 0.5 is centered (default)
*/
public void centerHorizontally(int centerID,
int leftId,
int leftSide,
int leftMargin,
int rightId,
int rightSide,
int rightMargin,
float bias) {
connect(centerID, LEFT, leftId, leftSide, leftMargin);
connect(centerID, RIGHT, rightId, rightSide, rightMargin);
Constraint constraint = mConstraints.get(centerID);
if (constraint != null) {
constraint.layout.horizontalBias = bias;
}
}
/**
* Centers the widgets horizontally to the left and right side on another widgets sides.
* (for sides see: {@link #START}, {@link #END},
* {@link #LEFT}, {@link #RIGHT})
*
* @param centerID ID of widget to be centered
* @param startId The Id of the widget on the start side (left in non rtl languages)
* @param startSide The side of the startId widget to connect to
* @param startMargin The margin on the start side
* @param endId The Id of the widget on the start side (left in non rtl languages)
* @param endSide The side of the endId widget to connect to
* @param endMargin The margin on the end side
* @param bias The ratio of the space on the start vs end side 0.5 is centered (default)
*/
public void centerHorizontallyRtl(int centerID, int startId, int startSide, int startMargin,
int endId, int endSide, int endMargin, float bias) {
connect(centerID, START, startId, startSide, startMargin);
connect(centerID, END, endId, endSide, endMargin);
Constraint constraint = mConstraints.get(centerID);
if (constraint != null) {
constraint.layout.horizontalBias = bias;
}
}
/**
* Centers the widgets vertically to the top and bottom side on another widgets sides.
* (for sides see: {@link #TOP}, {@link #BOTTOM})
*
* @param centerID ID of widget to be centered
* @param topId The Id of the widget on the top side
* @param topSide The side of the leftId widget to connect to
* @param topMargin The margin on the top side
* @param bottomId The Id of the widget on the bottom side
* @param bottomSide The side of the bottomId widget to connect to
* @param bottomMargin The margin on the bottom side
* @param bias The ratio of the space on the top vs.
* bottom sides 0.5 is centered (default)
*/
public void centerVertically(int centerID, int topId, int topSide, int topMargin, int bottomId,
int bottomSide, int bottomMargin, float bias) {
connect(centerID, TOP, topId, topSide, topMargin);
connect(centerID, BOTTOM, bottomId, bottomSide, bottomMargin);
Constraint constraint = mConstraints.get(centerID);
if (constraint != null) {
constraint.layout.verticalBias = bias;
}
}
/**
* Spaces a set of widgets vertically between the view topId and bottomId.
* Widgets can be spaced with weights.
* This operation sets all the related margins to 0.
* <p>
* (for sides see: {@link #TOP}, {@link #BOTTOM})
*
* @param topId The id of the widget to connect to or PARENT_ID
* @param topSide the side of the start to connect to
* @param bottomId The id of the widget to connect to or PARENT_ID
* @param bottomSide the side of the right to connect to
* @param chainIds widgets to use as a chain
* @param weights can be null
* @param style set the style of the chain
*/
public void createVerticalChain(int topId,
int topSide,
int bottomId,
int bottomSide,
int[] chainIds,
float[] weights,
int style) {
if (chainIds.length < 2) {
throw new IllegalArgumentException("must have 2 or more widgets in a chain");
}
if (weights != null && weights.length != chainIds.length) {
throw new IllegalArgumentException("must have 2 or more widgets in a chain");
}
if (weights != null) {
get(chainIds[0]).layout.verticalWeight = weights[0];
}
get(chainIds[0]).layout.verticalChainStyle = style;
connect(chainIds[0], TOP, topId, topSide, 0);
for (int i = 1; i < chainIds.length; i++) {
connect(chainIds[i], TOP, chainIds[i - 1], BOTTOM, 0);
connect(chainIds[i - 1], BOTTOM, chainIds[i], TOP, 0);
if (weights != null) {
get(chainIds[i]).layout.verticalWeight = weights[i];
}
}
connect(chainIds[chainIds.length - 1], BOTTOM, bottomId, bottomSide, 0);
}
/**
* Spaces a set of widgets horizontally between the view startID and endId.
* Widgets can be spaced with weights.
* This operation sets all the related margins to 0.
* <p>
* (for sides see: {@link #START}, {@link #END},
* {@link #LEFT}, {@link #RIGHT})
*
* @param leftId The id of the widget to connect to or PARENT_ID
* @param leftSide the side of the start to connect to
* @param rightId The id of the widget to connect to or PARENT_ID
* @param rightSide the side of the right to connect to
* @param chainIds The widgets in the chain
* @param weights The weight to assign to each element in the chain or null
* @param style The type of chain
*/
public void createHorizontalChain(int leftId,
int leftSide,
int rightId,
int rightSide,
int[] chainIds,
float[] weights,
int style) {
createHorizontalChain(leftId, leftSide, rightId, rightSide,
chainIds, weights, style, LEFT, RIGHT);
}
/**
* Spaces a set of widgets horizontal between the view startID and endId.
* Widgets can be spaced with weights.
* (for sides see: {@link #START}, {@link #END},
* {@link #LEFT}, {@link #RIGHT})
*
* @param startId The id of the widget to connect to or PARENT_ID
* @param startSide the side of the start to connect to
* @param endId The id of the widget to connect to or PARENT_ID
* @param endSide the side of the end to connect to
* @param chainIds The widgets in the chain
* @param weights The weight to assign to each element in the chain or null
* @param style The type of chain
*/
public void createHorizontalChainRtl(int startId,
int startSide,
int endId,
int endSide,
int[] chainIds,
float[] weights,
int style) {
createHorizontalChain(startId, startSide, endId, endSide,
chainIds, weights, style, START, END);
}
private void createHorizontalChain(int leftId,
int leftSide,
int rightId,
int rightSide,
int[] chainIds,
float[] weights,
int style, int left, int right) {
if (chainIds.length < 2) {
throw new IllegalArgumentException("must have 2 or more widgets in a chain");
}
if (weights != null && weights.length != chainIds.length) {
throw new IllegalArgumentException("must have 2 or more widgets in a chain");
}
if (weights != null) {
get(chainIds[0]).layout.horizontalWeight = weights[0];
}
get(chainIds[0]).layout.horizontalChainStyle = style;
connect(chainIds[0], left, leftId, leftSide, UNSET);
for (int i = 1; i < chainIds.length; i++) {
connect(chainIds[i], left, chainIds[i - 1], right, UNSET);
connect(chainIds[i - 1], right, chainIds[i], left, UNSET);
if (weights != null) {
get(chainIds[i]).layout.horizontalWeight = weights[i];
}
}
connect(chainIds[chainIds.length - 1], right, rightId, rightSide,
UNSET);
}
/**
* Create a constraint between two widgets.
* (for sides see: {@link #TOP}, {@link #BOTTOM}, {@link #START}, {@link #END},
* {@link #LEFT}, {@link #RIGHT}, {@link #BASELINE})
*
* @param startID the ID of the widget to be constrained
* @param startSide the side of the widget to constrain
* @param endID the id of the widget to constrain to
* @param endSide the side of widget to constrain to
* @param margin the margin to constrain (margin must be positive)
*/
public void connect(int startID, int startSide, int endID, int endSide, int margin) {
if (!mConstraints.containsKey(startID)) {
mConstraints.put(startID, new Constraint());
}
Constraint constraint = mConstraints.get(startID);
if (constraint == null) {
return;
}
switch (startSide) {
case LEFT:
if (endSide == LEFT) {
constraint.layout.leftToLeft = endID;
constraint.layout.leftToRight = Layout.UNSET;
} else if (endSide == RIGHT) {
constraint.layout.leftToRight = endID;
constraint.layout.leftToLeft = Layout.UNSET;
} else {
throw new IllegalArgumentException("Left to "
+ sideToString(endSide) + " undefined");
}
constraint.layout.leftMargin = margin;
break;
case RIGHT:
if (endSide == LEFT) {
constraint.layout.rightToLeft = endID;
constraint.layout.rightToRight = Layout.UNSET;
} else if (endSide == RIGHT) {
constraint.layout.rightToRight = endID;
constraint.layout.rightToLeft = Layout.UNSET;
} else {
throw new IllegalArgumentException("right to "
+ sideToString(endSide) + " undefined");
}
constraint.layout.rightMargin = margin;
break;
case TOP:
if (endSide == TOP) {
constraint.layout.topToTop = endID;
constraint.layout.topToBottom = Layout.UNSET;
constraint.layout.baselineToBaseline = Layout.UNSET;
constraint.layout.baselineToTop = Layout.UNSET;
constraint.layout.baselineToBottom = Layout.UNSET;
} else if (endSide == BOTTOM) {
constraint.layout.topToBottom = endID;
constraint.layout.topToTop = Layout.UNSET;
constraint.layout.baselineToBaseline = Layout.UNSET;
constraint.layout.baselineToTop = Layout.UNSET;
constraint.layout.baselineToBottom = Layout.UNSET;
} else {
throw new IllegalArgumentException("right to "
+ sideToString(endSide) + " undefined");
}
constraint.layout.topMargin = margin;
break;
case BOTTOM:
if (endSide == BOTTOM) {
constraint.layout.bottomToBottom = endID;
constraint.layout.bottomToTop = Layout.UNSET;
constraint.layout.baselineToBaseline = Layout.UNSET;
constraint.layout.baselineToTop = Layout.UNSET;
constraint.layout.baselineToBottom = Layout.UNSET;
} else if (endSide == TOP) {
constraint.layout.bottomToTop = endID;
constraint.layout.bottomToBottom = Layout.UNSET;
constraint.layout.baselineToBaseline = Layout.UNSET;
constraint.layout.baselineToTop = Layout.UNSET;
constraint.layout.baselineToBottom = Layout.UNSET;
} else {
throw new IllegalArgumentException("right to "
+ sideToString(endSide) + " undefined");
}
constraint.layout.bottomMargin = margin;
break;
case BASELINE:
if (endSide == BASELINE) {
constraint.layout.baselineToBaseline = endID;
constraint.layout.bottomToBottom = Layout.UNSET;
constraint.layout.bottomToTop = Layout.UNSET;
constraint.layout.topToTop = Layout.UNSET;
constraint.layout.topToBottom = Layout.UNSET;
} else if (endSide == TOP) {
constraint.layout.baselineToTop = endID;
constraint.layout.bottomToBottom = Layout.UNSET;
constraint.layout.bottomToTop = Layout.UNSET;
constraint.layout.topToTop = Layout.UNSET;
constraint.layout.topToBottom = Layout.UNSET;
} else if (endSide == BOTTOM) {
constraint.layout.baselineToBottom = endID;
constraint.layout.bottomToBottom = Layout.UNSET;
constraint.layout.bottomToTop = Layout.UNSET;
constraint.layout.topToTop = Layout.UNSET;
constraint.layout.topToBottom = Layout.UNSET;
} else {
throw new IllegalArgumentException("right to "
+ sideToString(endSide) + " undefined");
}
break;
case START:
if (endSide == START) {
constraint.layout.startToStart = endID;
constraint.layout.startToEnd = Layout.UNSET;
} else if (endSide == END) {
constraint.layout.startToEnd = endID;
constraint.layout.startToStart = Layout.UNSET;
} else {
throw new IllegalArgumentException("right to "
+ sideToString(endSide) + " undefined");
}
constraint.layout.startMargin = margin;
break;
case END:
if (endSide == END) {
constraint.layout.endToEnd = endID;
constraint.layout.endToStart = Layout.UNSET;
} else if (endSide == START) {
constraint.layout.endToStart = endID;
constraint.layout.endToEnd = Layout.UNSET;
} else {
throw new IllegalArgumentException("right to "
+ sideToString(endSide) + " undefined");
}
constraint.layout.endMargin = margin;
break;
default:
throw new IllegalArgumentException(
sideToString(startSide) + " to " + sideToString(endSide) + " unknown");
}
}
/**
* Create a constraint between two widgets.
* (for sides see: {@link #TOP}, {@link #BOTTOM}, {@link #START},
* {@link #END}, {@link #LEFT}, {@link #RIGHT}, {@link #BASELINE})
*
* @param startID the ID of the widget to be constrained
* @param startSide the side of the widget to constrain
* @param endID the id of the widget to constrain to
* @param endSide the side of widget to constrain to
*/
public void connect(int startID, int startSide, int endID, int endSide) {
if (!mConstraints.containsKey(startID)) {
mConstraints.put(startID, new Constraint());
}
Constraint constraint = mConstraints.get(startID);
if (constraint == null) {
return;
}
switch (startSide) {
case LEFT:
if (endSide == LEFT) {
constraint.layout.leftToLeft = endID;
constraint.layout.leftToRight = Layout.UNSET;
} else if (endSide == RIGHT) {
constraint.layout.leftToRight = endID;
constraint.layout.leftToLeft = Layout.UNSET;
} else {
throw new IllegalArgumentException("left to "
+ sideToString(endSide) + " undefined");
}
break;
case RIGHT:
if (endSide == LEFT) {
constraint.layout.rightToLeft = endID;
constraint.layout.rightToRight = Layout.UNSET;
} else if (endSide == RIGHT) {
constraint.layout.rightToRight = endID;
constraint.layout.rightToLeft = Layout.UNSET;
} else {
throw new IllegalArgumentException("right to "
+ sideToString(endSide) + " undefined");
}
break;
case TOP:
if (endSide == TOP) {
constraint.layout.topToTop = endID;
constraint.layout.topToBottom = Layout.UNSET;
constraint.layout.baselineToBaseline = Layout.UNSET;
constraint.layout.baselineToTop = Layout.UNSET;
constraint.layout.baselineToBottom = Layout.UNSET;
} else if (endSide == BOTTOM) {
constraint.layout.topToBottom = endID;
constraint.layout.topToTop = Layout.UNSET;
constraint.layout.baselineToBaseline = Layout.UNSET;
constraint.layout.baselineToTop = Layout.UNSET;
constraint.layout.baselineToBottom = Layout.UNSET;
} else {
throw new IllegalArgumentException("right to "
+ sideToString(endSide) + " undefined");
}
break;
case BOTTOM:
if (endSide == BOTTOM) {
constraint.layout.bottomToBottom = endID;
constraint.layout.bottomToTop = Layout.UNSET;
constraint.layout.baselineToBaseline = Layout.UNSET;
constraint.layout.baselineToTop = Layout.UNSET;
constraint.layout.baselineToBottom = Layout.UNSET;
} else if (endSide == TOP) {
constraint.layout.bottomToTop = endID;
constraint.layout.bottomToBottom = Layout.UNSET;
constraint.layout.baselineToBaseline = Layout.UNSET;
constraint.layout.baselineToTop = Layout.UNSET;
constraint.layout.baselineToBottom = Layout.UNSET;
} else {
throw new IllegalArgumentException("right to "
+ sideToString(endSide) + " undefined");
}
break;
case BASELINE:
if (endSide == BASELINE) {
constraint.layout.baselineToBaseline = endID;
constraint.layout.bottomToBottom = Layout.UNSET;
constraint.layout.bottomToTop = Layout.UNSET;
constraint.layout.topToTop = Layout.UNSET;
constraint.layout.topToBottom = Layout.UNSET;
} else if (endSide == TOP) {
constraint.layout.baselineToTop = endID;
constraint.layout.bottomToBottom = Layout.UNSET;
constraint.layout.bottomToTop = Layout.UNSET;
constraint.layout.topToTop = Layout.UNSET;
constraint.layout.topToBottom = Layout.UNSET;
} else if (endSide == BOTTOM) {
constraint.layout.baselineToBottom = endID;
constraint.layout.bottomToBottom = Layout.UNSET;
constraint.layout.bottomToTop = Layout.UNSET;
constraint.layout.topToTop = Layout.UNSET;
constraint.layout.topToBottom = Layout.UNSET;
} else {
throw new IllegalArgumentException("right to "
+ sideToString(endSide) + " undefined");
}
break;
case START:
if (endSide == START) {
constraint.layout.startToStart = endID;
constraint.layout.startToEnd = Layout.UNSET;
} else if (endSide == END) {
constraint.layout.startToEnd = endID;
constraint.layout.startToStart = Layout.UNSET;
} else {
throw new IllegalArgumentException("right to "
+ sideToString(endSide) + " undefined");
}
break;
case END:
if (endSide == END) {
constraint.layout.endToEnd = endID;
constraint.layout.endToStart = Layout.UNSET;
} else if (endSide == START) {
constraint.layout.endToStart = endID;
constraint.layout.endToEnd = Layout.UNSET;
} else {
throw new IllegalArgumentException("right to "
+ sideToString(endSide) + " undefined");
}
break;
default:
throw new IllegalArgumentException(
sideToString(startSide) + " to " + sideToString(endSide) + " unknown");
}
}
/**
* Centers the view horizontally relative to toView's position.
*
* @param viewId ID of view to center Horizontally
* @param toView ID of view to center on (or in)
*/
public void centerHorizontally(int viewId, int toView) {
if (toView == PARENT_ID) {
center(viewId, PARENT_ID, ConstraintSet.LEFT, 0, PARENT_ID,
ConstraintSet.RIGHT, 0, 0.5f);
} else {
center(viewId, toView, ConstraintSet.RIGHT, 0, toView,
ConstraintSet.LEFT, 0, 0.5f);
}
}
/**
* Centers the view horizontally relative to toView's position.
*
* @param viewId ID of view to center Horizontally
* @param toView ID of view to center on (or in)
*/
public void centerHorizontallyRtl(int viewId, int toView) {
if (toView == PARENT_ID) {
center(viewId, PARENT_ID, ConstraintSet.START, 0, PARENT_ID,
ConstraintSet.END, 0, 0.5f);
} else {
center(viewId, toView, ConstraintSet.END, 0, toView,
ConstraintSet.START, 0, 0.5f);
}
}
/**
* Centers the view vertically relative to toView's position.
*
* @param viewId ID of view to center Horizontally
* @param toView ID of view to center on (or in)
*/
public void centerVertically(int viewId, int toView) {
if (toView == PARENT_ID) {
center(viewId, PARENT_ID, ConstraintSet.TOP, 0, PARENT_ID,
ConstraintSet.BOTTOM, 0, 0.5f);
} else {
center(viewId, toView, ConstraintSet.BOTTOM, 0, toView, ConstraintSet.TOP,
0, 0.5f);
}
}
/**
* Remove all constraints from this view.
*
* @param viewId ID of view to remove all connections to
*/
public void clear(int viewId) {
mConstraints.remove(viewId);
}
/**
* Remove a constraint from this view.
*
* @param viewId ID of view to center on (or in)
* @param anchor the Anchor to remove constraint from
*/
public void clear(int viewId, int anchor) {
if (mConstraints.containsKey(viewId)) {
Constraint constraint = mConstraints.get(viewId);
if (constraint == null) {
return;
}
switch (anchor) {
case LEFT:
constraint.layout.leftToRight = Layout.UNSET;
constraint.layout.leftToLeft = Layout.UNSET;
constraint.layout.leftMargin = Layout.UNSET;
constraint.layout.goneLeftMargin = Layout.UNSET_GONE_MARGIN;
break;
case RIGHT:
constraint.layout.rightToRight = Layout.UNSET;
constraint.layout.rightToLeft = Layout.UNSET;
constraint.layout.rightMargin = Layout.UNSET;
constraint.layout.goneRightMargin = Layout.UNSET_GONE_MARGIN;
break;
case TOP:
constraint.layout.topToBottom = Layout.UNSET;
constraint.layout.topToTop = Layout.UNSET;
constraint.layout.topMargin = 0;
constraint.layout.goneTopMargin = Layout.UNSET_GONE_MARGIN;
break;
case BOTTOM:
constraint.layout.bottomToTop = Layout.UNSET;
constraint.layout.bottomToBottom = Layout.UNSET;
constraint.layout.bottomMargin = 0;
constraint.layout.goneBottomMargin = Layout.UNSET_GONE_MARGIN;
break;
case BASELINE:
constraint.layout.baselineToBaseline = Layout.UNSET;
constraint.layout.baselineToTop = Layout.UNSET;
constraint.layout.baselineToBottom = Layout.UNSET;
constraint.layout.baselineMargin = 0;
constraint.layout.goneBaselineMargin = Layout.UNSET_GONE_MARGIN;
break;
case START:
constraint.layout.startToEnd = Layout.UNSET;
constraint.layout.startToStart = Layout.UNSET;
constraint.layout.startMargin = 0;
constraint.layout.goneStartMargin = Layout.UNSET_GONE_MARGIN;
break;
case END:
constraint.layout.endToStart = Layout.UNSET;
constraint.layout.endToEnd = Layout.UNSET;
constraint.layout.endMargin = 0;
constraint.layout.goneEndMargin = Layout.UNSET_GONE_MARGIN;
break;
case CIRCLE_REFERENCE:
constraint.layout.circleAngle = Layout.UNSET;
constraint.layout.circleRadius = Layout.UNSET;
constraint.layout.circleConstraint = Layout.UNSET;
break;
default:
throw new IllegalArgumentException("unknown constraint");
}
}
}
/**
* Sets the margin.
*
* @param viewId ID of view to adjust the margin on
* @param anchor The side to adjust the margin on
* @param value The new value for the margin
*/
public void setMargin(int viewId, int anchor, int value) {
Constraint constraint = get(viewId);
switch (anchor) {
case LEFT:
constraint.layout.leftMargin = value;
break;
case RIGHT:
constraint.layout.rightMargin = value;
break;
case TOP:
constraint.layout.topMargin = value;
break;
case BOTTOM:
constraint.layout.bottomMargin = value;
break;
case BASELINE:
constraint.layout.baselineMargin = value;
break;
case START:
constraint.layout.startMargin = value;
break;
case END:
constraint.layout.endMargin = value;
break;
default:
throw new IllegalArgumentException("unknown constraint");
}
}
/**
* Sets the gone margin.
*
* @param viewId ID of view to adjust the margin on
* @param anchor The side to adjust the margin on
* @param value The new value for the margin
*/
public void setGoneMargin(int viewId, int anchor, int value) {
Constraint constraint = get(viewId);
switch (anchor) {
case LEFT:
constraint.layout.goneLeftMargin = value;
break;
case RIGHT:
constraint.layout.goneRightMargin = value;
break;
case TOP:
constraint.layout.goneTopMargin = value;
break;
case BOTTOM:
constraint.layout.goneBottomMargin = value;
break;
case BASELINE:
constraint.layout.goneBaselineMargin = value;
break;
case START:
constraint.layout.goneStartMargin = value;
break;
case END:
constraint.layout.goneEndMargin = value;
break;
default:
throw new IllegalArgumentException("unknown constraint");
}
}
/**
* Adjust the horizontal bias of the view (used with views constrained on left and right).
*
* @param viewId ID of view to adjust the horizontal
* @param bias the new bias 0.5 is in the middle
*/
public void setHorizontalBias(int viewId, float bias) {
get(viewId).layout.horizontalBias = bias;
}
/**
* Adjust the vertical bias of the view (used with views constrained on left and right).
*
* @param viewId ID of view to adjust the vertical
* @param bias the new bias 0.5 is in the middle
*/
public void setVerticalBias(int viewId, float bias) {
get(viewId).layout.verticalBias = bias;
}
/**
* Constrains the views aspect ratio.
* For Example a HD screen is 16 by 9 = 16/(float)9 = 1.777f.
*
* @param viewId ID of view to constrain
* @param ratio The ratio of the width to height (width / height)
*/
public void setDimensionRatio(int viewId, String ratio) {
get(viewId).layout.dimensionRatio = ratio;
}
/**
* Adjust the visibility of a view.
*
* @param viewId ID of view to adjust the vertical
* @param visibility the visibility
*/
public void setVisibility(int viewId, int visibility) {
get(viewId).propertySet.visibility = visibility;
}
/**
* ConstraintSet will not setVisibility. {@link #VISIBILITY_MODE_IGNORE} or {@link
* #VISIBILITY_MODE_NORMAL}.
*
* @param viewId ID of view
* @param visibilityMode
*/
public void setVisibilityMode(int viewId, int visibilityMode) {
get(viewId).propertySet.mVisibilityMode = visibilityMode;
}
/**
* ConstraintSet will not setVisibility. {@link #VISIBILITY_MODE_IGNORE} or {@link
* #VISIBILITY_MODE_NORMAL}.
*
* @param viewId ID of view
*/
public int getVisibilityMode(int viewId) {
return get(viewId).propertySet.mVisibilityMode;
}
/**
* Get the visibility flag set in this view
*
* @param viewId the id of the view
* @return the visibility constraint for the view
*/
public int getVisibility(int viewId) {
return get(viewId).propertySet.visibility;
}
/**
* Get the height set in the view
*
* @param viewId the id of the view
* @return return the height constraint of the view
*/
public int getHeight(int viewId) {
return get(viewId).layout.mHeight;
}
/**
* Get the width set in the view
*
* @param viewId the id of the view
* @return return the width constraint of the view
*/
public int getWidth(int viewId) {
return get(viewId).layout.mWidth;
}
/**
* Adjust the alpha of a view.
*
* @param viewId ID of view to adjust the vertical
* @param alpha the alpha
*/
public void setAlpha(int viewId, float alpha) {
get(viewId).propertySet.alpha = alpha;
}
/**
* return with the constraint set will apply elevation for the specified view.
*
* @return true if the elevation will be set on this view (default is false)
*/
public boolean getApplyElevation(int viewId) {
return get(viewId).transform.applyElevation;
}
/**
* set if elevation will be applied to the view.
* Elevation logic is based on style and animation. By default it is not used because it would
* lead to unexpected results.
*
* @param apply true if this constraint set applies elevation to this view
*/
public void setApplyElevation(int viewId, boolean apply) {
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
get(viewId).transform.applyElevation = apply;
}
}
/**
* Adjust the elevation of a view.
*
* @param viewId ID of view to adjust the elevation
* @param elevation the elevation
*/
public void setElevation(int viewId, float elevation) {
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
get(viewId).transform.elevation = elevation;
get(viewId).transform.applyElevation = true;
}
}
/**
* Adjust the post-layout rotation about the Z axis of a view.
*
* @param viewId ID of view to adjust th Z rotation
* @param rotation the rotation about the X axis
*/
public void setRotation(int viewId, float rotation) {
get(viewId).transform.rotation = rotation;
}
/**
* Adjust the post-layout rotation about the X axis of a view.
*
* @param viewId ID of view to adjust th X rotation
* @param rotationX the rotation about the X axis
*/
public void setRotationX(int viewId, float rotationX) {
get(viewId).transform.rotationX = rotationX;
}
/**
* Adjust the post-layout rotation about the Y axis of a view.
*
* @param viewId ID of view to adjust the Y rotation
* @param rotationY the rotationY
*/
public void setRotationY(int viewId, float rotationY) {
get(viewId).transform.rotationY = rotationY;
}
/**
* Adjust the post-layout scale in X of a view.
*
* @param viewId ID of view to adjust the scale in X
* @param scaleX the scale in X
*/
public void setScaleX(int viewId, float scaleX) {
get(viewId).transform.scaleX = scaleX;
}
/**
* Adjust the post-layout scale in Y of a view.
*
* @param viewId ID of view to adjust the scale in Y
* @param scaleY the scale in Y
*/
public void setScaleY(int viewId, float scaleY) {
get(viewId).transform.scaleY = scaleY;
}
/**
* Set X location of the pivot point around which the view will rotate and scale.
* use Float.NaN to clear the pivot value.
* Note: once an actual View has had its pivot set it cannot be cleared.
*
* @param viewId ID of view to adjust the transforms pivot point about X
* @param transformPivotX X location of the pivot point.
*/
public void setTransformPivotX(int viewId, float transformPivotX) {
get(viewId).transform.transformPivotX = transformPivotX;
}
/**
* Set Y location of the pivot point around which the view will rotate and scale.
* use Float.NaN to clear the pivot value.
* Note: once an actual View has had its pivot set it cannot be cleared.
*
* @param viewId ID of view to adjust the transforms pivot point about Y
* @param transformPivotY Y location of the pivot point.
*/
public void setTransformPivotY(int viewId, float transformPivotY) {
get(viewId).transform.transformPivotY = transformPivotY;
}
/**
* Set X,Y location of the pivot point around which the view will rotate and scale.
* use Float.NaN to clear the pivot value.
* Note: once an actual View has had its pivot set it cannot be cleared.
*
* @param viewId ID of view to adjust the transforms pivot point
* @param transformPivotX X location of the pivot point.
* @param transformPivotY Y location of the pivot point.
*/
public void setTransformPivot(int viewId, float transformPivotX, float transformPivotY) {
Constraint constraint = get(viewId);
constraint.transform.transformPivotY = transformPivotY;
constraint.transform.transformPivotX = transformPivotX;
}
/**
* Adjust the post-layout X translation of a view.
*
* @param viewId ID of view to translate in X
* @param translationX the translation in X
*/
public void setTranslationX(int viewId, float translationX) {
get(viewId).transform.translationX = translationX;
}
/**
* Adjust the post-layout Y translation of a view.
*
* @param viewId ID of view to to translate in Y
* @param translationY the translation in Y
*/
public void setTranslationY(int viewId, float translationY) {
get(viewId).transform.translationY = translationY;
}
/**
* Adjust the post-layout translation of a view.
*
* @param viewId ID of view to adjust its translation in X & Y
* @param translationX the translation in X
* @param translationY the translation in Y
*/
public void setTranslation(int viewId, float translationX, float translationY) {
Constraint constraint = get(viewId);
constraint.transform.translationX = translationX;
constraint.transform.translationY = translationY;
}
/**
* Adjust the translation in Z of a view.
*
* @param viewId ID of view to adjust
* @param translationZ the translationZ
*/
public void setTranslationZ(int viewId, float translationZ) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
get(viewId).transform.translationZ = translationZ;
}
}
/**
*
*/
public void setEditorAbsoluteX(int viewId, int position) {
get(viewId).layout.editorAbsoluteX = position;
}
/**
*
*/
public void setEditorAbsoluteY(int viewId, int position) {
get(viewId).layout.editorAbsoluteY = position;
}
/**
* Sets the wrap behavior of the widget in the parent's wrap computation
*/
public void setLayoutWrapBehavior(int viewId, int behavior) {
if (behavior >= 0 && behavior <= ConstraintWidget.WRAP_BEHAVIOR_SKIPPED) {
get(viewId).layout.mWrapBehavior = behavior;
}
}
/**
* Sets the height of the view. It can be a dimension, {@link #WRAP_CONTENT} or {@link
* #MATCH_CONSTRAINT}.
*
* @param viewId ID of view to adjust its height
* @param height the height of the view
*/
public void constrainHeight(int viewId, int height) {
get(viewId).layout.mHeight = height;
}
/**
* Sets the width of the view. It can be a dimension, {@link #WRAP_CONTENT} or {@link
* #MATCH_CONSTRAINT}.
*
* @param viewId ID of view to adjust its width
* @param width the width of the view
*/
public void constrainWidth(int viewId, int width) {
get(viewId).layout.mWidth = width;
}
/**
* Constrain the view on a circle constraint
*
* @param viewId ID of the view we constrain
* @param id ID of the view we constrain relative to
* @param radius the radius of the circle in degrees
* @param angle the angle
*/
public void constrainCircle(int viewId, int id, int radius, float angle) {
Constraint constraint = get(viewId);
constraint.layout.circleConstraint = id;
constraint.layout.circleRadius = radius;
constraint.layout.circleAngle = angle;
}
/**
* Sets the maximum height of the view. It is a dimension, It is only applicable if height is
* #MATCH_CONSTRAINT}.
*
* @param viewId ID of view to adjust it height
* @param height the maximum height of the constraint
*/
public void constrainMaxHeight(int viewId, int height) {
get(viewId).layout.heightMax = height;
}
/**
* Sets the maximum width of the view. It is a dimension, It is only applicable if width is
* #MATCH_CONSTRAINT}.
*
* @param viewId ID of view to adjust its max height
* @param width the maximum width of the view
*/
public void constrainMaxWidth(int viewId, int width) {
get(viewId).layout.widthMax = width;
}
/**
* Sets the height of the view. It is a dimension, It is only applicable if height is
* #MATCH_CONSTRAINT}.
*
* @param viewId ID of view to adjust its min height
* @param height the minimum height of the view
*/
public void constrainMinHeight(int viewId, int height) {
get(viewId).layout.heightMin = height;
}
/**
* Sets the width of the view. It is a dimension, It is only applicable if width is
* #MATCH_CONSTRAINT}.
*
* @param viewId ID of view to adjust its min height
* @param width the minimum width of the view
*/
public void constrainMinWidth(int viewId, int width) {
get(viewId).layout.widthMin = width;
}
/**
* Sets the width of the view as a percentage of the parent.
*
* @param viewId
* @param percent
*/
public void constrainPercentWidth(int viewId, float percent) {
get(viewId).layout.widthPercent = percent;
}
/**
* Sets the height of the view as a percentage of the parent.
*
* @param viewId
* @param percent
*/
public void constrainPercentHeight(int viewId, float percent) {
get(viewId).layout.heightPercent = percent;
}
/**
* Sets how the height is calculated ether MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD.
* Default is spread.
*
* @param viewId ID of view to adjust its matchConstraintDefaultHeight
* @param height MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD
*/
public void constrainDefaultHeight(int viewId, int height) {
get(viewId).layout.heightDefault = height;
}
/**
* Sets how the width is calculated ether MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD.
* Default is spread.
*
* @param viewId ID of view to adjust its matchConstraintDefaultWidth
* @param constrained if true with will be constrained
*/
public void constrainedWidth(int viewId, boolean constrained) {
get(viewId).layout.constrainedWidth = constrained;
}
/**
* Sets how the height is calculated ether MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD.
* Default is spread.
*
* @param viewId ID of view to adjust its matchConstraintDefaultHeight
* @param constrained if true height will be constrained
*/
public void constrainedHeight(int viewId, boolean constrained) {
get(viewId).layout.constrainedHeight = constrained;
}
/**
* Sets how the width is calculated ether MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD.
* Default is spread.
*
* @param viewId ID of view to adjust its matchConstraintDefaultWidth
* @param width SPREAD or WRAP
*/
public void constrainDefaultWidth(int viewId, int width) {
get(viewId).layout.widthDefault = width;
}
/**
* The child's weight that we can use to distribute the available horizontal space
* in a chain, if the dimension behaviour is set to MATCH_CONSTRAINT
*
* @param viewId ID of view to adjust its HorizontalWeight
* @param weight the weight that we can use to distribute the horizontal space
*/
public void setHorizontalWeight(int viewId, float weight) {
get(viewId).layout.horizontalWeight = weight;
}
/**
* The child's weight that we can use to distribute the available vertical space
* in a chain, if the dimension behaviour is set to MATCH_CONSTRAINT
*
* @param viewId ID of view to adjust its VerticalWeight
* @param weight the weight that we can use to distribute the vertical space
*/
public void setVerticalWeight(int viewId, float weight) {
get(viewId).layout.verticalWeight = weight;
}
/**
* How the elements of the horizontal chain will be positioned. if the dimension
* behaviour is set to MATCH_CONSTRAINT. The possible values are:
*
* <ul>
* <li>{@link #CHAIN_SPREAD} -- the elements will be spread out</li>
* <li>{@link #CHAIN_SPREAD_INSIDE} -- similar, but the endpoints of the chain will not
* be spread out</li>
* <li>{@link #CHAIN_PACKED} -- the elements of the chain will be packed together. The
* horizontal bias attribute of the child will then affect the positioning of the packed
* elements</li>
* </ul>
*
* @param viewId ID of view to adjust its HorizontalChainStyle
* @param chainStyle the weight that we can use to distribute the horizontal space
*/
public void setHorizontalChainStyle(int viewId, int chainStyle) {
get(viewId).layout.horizontalChainStyle = chainStyle;
}
/**
* How the elements of the vertical chain will be positioned. in a chain, if the dimension
* behaviour is set to MATCH_CONSTRAINT
*
* <ul>
* <li>{@link #CHAIN_SPREAD} -- the elements will be spread out</li>
* <li>{@link #CHAIN_SPREAD_INSIDE} -- similar, but the endpoints of the chain will not
* be spread out</li>
* <li>{@link #CHAIN_PACKED} -- the elements of the chain will be packed together. The
* vertical bias attribute of the child will then affect the positioning of the packed
* elements</li>
* </ul>
*
* @param viewId ID of view to adjust its VerticalChainStyle
* @param chainStyle the weight that we can use to distribute the horizontal space
*/
public void setVerticalChainStyle(int viewId, int chainStyle) {
get(viewId).layout.verticalChainStyle = chainStyle;
}
/**
* Adds a view to a horizontal chain.
*
* @param viewId view to add
* @param leftId view in chain to the left
* @param rightId view in chain to the right
*/
public void addToHorizontalChain(int viewId, int leftId, int rightId) {
connect(viewId, LEFT, leftId, (leftId == PARENT_ID) ? LEFT : RIGHT, 0);
connect(viewId, RIGHT, rightId, (rightId == PARENT_ID) ? RIGHT : LEFT, 0);
if (leftId != PARENT_ID) {
connect(leftId, RIGHT, viewId, LEFT, 0);
}
if (rightId != PARENT_ID) {
connect(rightId, LEFT, viewId, RIGHT, 0);
}
}
/**
* Adds a view to a horizontal chain.
*
* @param viewId view to add
* @param leftId view to the start side
* @param rightId view to the end side
*/
public void addToHorizontalChainRTL(int viewId, int leftId, int rightId) {
connect(viewId, START, leftId, (leftId == PARENT_ID) ? START : END, 0);
connect(viewId, END, rightId, (rightId == PARENT_ID) ? END : START, 0);
if (leftId != PARENT_ID) {
connect(leftId, END, viewId, START, 0);
}
if (rightId != PARENT_ID) {
connect(rightId, START, viewId, END, 0);
}
}
/**
* Adds a view to a vertical chain.
*
* @param viewId view to add to a vertical chain
* @param topId view above.
* @param bottomId view below
*/
public void addToVerticalChain(int viewId, int topId, int bottomId) {
connect(viewId, TOP, topId, (topId == PARENT_ID) ? TOP : BOTTOM, 0);
connect(viewId, BOTTOM, bottomId, (bottomId == PARENT_ID) ? BOTTOM : TOP, 0);
if (topId != PARENT_ID) {
connect(topId, BOTTOM, viewId, TOP, 0);
}
if (bottomId != PARENT_ID) {
connect(bottomId, TOP, viewId, BOTTOM, 0);
}
}
/**
* Removes a view from a vertical chain.
* This assumes the view is connected to a vertical chain.
* Its behaviour is undefined if not part of a vertical chain.
*
* @param viewId the view to be removed
*/
public void removeFromVerticalChain(int viewId) {
if (mConstraints.containsKey(viewId)) {
Constraint constraint = mConstraints.get(viewId);
if (constraint == null) {
return;
}
int topId = constraint.layout.topToBottom;
int bottomId = constraint.layout.bottomToTop;
if (topId != Layout.UNSET || bottomId != Layout.UNSET) {
if (topId != Layout.UNSET && bottomId != Layout.UNSET) {
// top and bottom connected to views
connect(topId, BOTTOM, bottomId, TOP, 0);
connect(bottomId, TOP, topId, BOTTOM, 0);
} else if (constraint.layout.bottomToBottom != Layout.UNSET) {
// top connected to view. Bottom connected to parent
connect(topId, BOTTOM, constraint.layout.bottomToBottom, BOTTOM, 0);
} else if (constraint.layout.topToTop != Layout.UNSET) {
// bottom connected to view. Top connected to parent
connect(bottomId, TOP, constraint.layout.topToTop, TOP, 0);
}
}
}
clear(viewId, TOP);
clear(viewId, BOTTOM);
}
/**
* Removes a view from a horizontal chain.
* This assumes the view is connected to a horizontal chain.
* Its behaviour is undefined if not part of a horizontal chain.
*
* @param viewId the view to be removed
*/
public void removeFromHorizontalChain(int viewId) {
if (mConstraints.containsKey(viewId)) {
Constraint constraint = mConstraints.get(viewId);
if (constraint == null) {
return;
}
int leftId = constraint.layout.leftToRight;
int rightId = constraint.layout.rightToLeft;
if (leftId != Layout.UNSET || rightId != Layout.UNSET) {
if (leftId != Layout.UNSET && rightId != Layout.UNSET) {
// left and right connected to views
connect(leftId, RIGHT, rightId, LEFT, 0);
connect(rightId, LEFT, leftId, RIGHT, 0);
} else if (constraint.layout.rightToRight != Layout.UNSET) {
// left connected to view. right connected to parent
connect(leftId, RIGHT, constraint.layout.rightToRight, RIGHT, 0);
} else if (constraint.layout.leftToLeft != Layout.UNSET) {
// right connected to view. left connected to parent
connect(rightId, LEFT, constraint.layout.leftToLeft, LEFT, 0);
}
clear(viewId, LEFT);
clear(viewId, RIGHT);
} else {
int startId = constraint.layout.startToEnd;
int endId = constraint.layout.endToStart;
if (startId != Layout.UNSET || endId != Layout.UNSET) {
if (startId != Layout.UNSET && endId != Layout.UNSET) {
// start and end connected to views
connect(startId, END, endId, START, 0);
connect(endId, START, leftId, END, 0);
} else if (endId != Layout.UNSET) {
if (constraint.layout.rightToRight != Layout.UNSET) {
// left connected to view. right connected to parent
connect(leftId, END, constraint.layout.rightToRight, END, 0);
} else if (constraint.layout.leftToLeft != Layout.UNSET) {
// right connected to view. left connected to parent
connect(endId, START, constraint.layout.leftToLeft, START, 0);
}
}
}
clear(viewId, START);
clear(viewId, END);
}
}
}
/**
* Creates a ConstraintLayout virtual object. Currently only horizontal or vertical GuideLines.
*
* @param guidelineID ID of guideline to create
* @param orientation the Orientation of the guideline
*/
public void create(int guidelineID, int orientation) {
Constraint constraint = get(guidelineID);
constraint.layout.mIsGuideline = true;
constraint.layout.orientation = orientation;
}
/**
* Creates a ConstraintLayout Barrier object.
*
* @param id
* @param direction Barrier.{LEFT,RIGHT,TOP,BOTTOM,START,END}
* @param referenced
*/
public void createBarrier(int id, int direction, int margin, int... referenced) {
Constraint constraint = get(id);
constraint.layout.mHelperType = BARRIER_TYPE;
constraint.layout.mBarrierDirection = direction;
constraint.layout.mBarrierMargin = margin;
constraint.layout.mIsGuideline = false;
constraint.layout.mReferenceIds = referenced;
}
/**
* Set the guideline's distance form the top or left edge.
*
* @param guidelineID ID of the guideline
* @param margin the distance to the top or left edge
*/
public void setGuidelineBegin(int guidelineID, int margin) {
get(guidelineID).layout.guideBegin = margin;
get(guidelineID).layout.guideEnd = Layout.UNSET;
get(guidelineID).layout.guidePercent = Layout.UNSET;
}
/**
* Set a guideline's distance to end.
*
* @param guidelineID ID of the guideline
* @param margin the margin to the right or bottom side of container
*/
public void setGuidelineEnd(int guidelineID, int margin) {
get(guidelineID).layout.guideEnd = margin;
get(guidelineID).layout.guideBegin = Layout.UNSET;
get(guidelineID).layout.guidePercent = Layout.UNSET;
}
/**
* Set a Guideline's percent.
*
* @param guidelineID ID of the guideline
* @param ratio the ratio between the gap on the left and right
* 0.0 is top/left 0.5 is middle
*/
public void setGuidelinePercent(int guidelineID, float ratio) {
get(guidelineID).layout.guidePercent = ratio;
get(guidelineID).layout.guideEnd = Layout.UNSET;
get(guidelineID).layout.guideBegin = Layout.UNSET;
}
/**
* get the reference id's of a helper.
*
* @param id
* @return array of id's
*/
public int[] getReferencedIds(int id) {
Constraint constraint = get(id);
if (constraint.layout.mReferenceIds == null) {
return new int[0];
}
return Arrays.copyOf(constraint.layout.mReferenceIds,
constraint.layout.mReferenceIds.length);
}
/**
* sets the reference id's of a barrier.
*
* @param id
* @param referenced
*/
public void setReferencedIds(int id, int... referenced) {
Constraint constraint = get(id);
constraint.layout.mReferenceIds = referenced;
}
/**
* SEt tye type of barier
* @param id
* @param type
*/
public void setBarrierType(int id, int type) {
Constraint constraint = get(id);
constraint.layout.mHelperType = type;
}
/**
* Remove the attribute
* @param attributeName
*/
public void removeAttribute(String attributeName) {
mSavedAttributes.remove(attributeName);
}
/**
* Set the value of an attribute of type int
* @param viewId
* @param attributeName
* @param value
*/
public void setIntValue(int viewId, String attributeName, int value) {
get(viewId).setIntValue(attributeName, value);
}
/**
* Set the value of an attribute of type color
* @param viewId
* @param attributeName
* @param value
*/
public void setColorValue(int viewId, String attributeName, int value) {
get(viewId).setColorValue(attributeName, value);
}
/**
* Set the value of an attribute of type float
* @param viewId
* @param attributeName
* @param value
*/
public void setFloatValue(int viewId, String attributeName, float value) {
get(viewId).setFloatValue(attributeName, value);
}
/**
* Set the value of an attribute of type string
* @param viewId
* @param attributeName
* @param value
*/
public void setStringValue(int viewId, String attributeName, String value) {
get(viewId).setStringValue(attributeName, value);
}
private void addAttributes(AttributeType attributeType, String... attributeName) {
ConstraintAttribute constraintAttribute = null;
for (int i = 0; i < attributeName.length; i++) {
if (mSavedAttributes.containsKey(attributeName[i])) {
constraintAttribute = mSavedAttributes.get(attributeName[i]);
if (constraintAttribute == null) {
continue;
}
if (constraintAttribute.getType() != attributeType) {
throw new IllegalArgumentException(
"ConstraintAttribute is already a "
+ constraintAttribute.getType().name());
}
} else {
constraintAttribute = new ConstraintAttribute(attributeName[i], attributeType);
mSavedAttributes.put(attributeName[i], constraintAttribute);
}
}
}
/**
* Parse int
* @param set
* @param attributes
*/
public void parseIntAttributes(Constraint set, String attributes) {
String[] sp = attributes.split(",");
for (int i = 0; i < sp.length; i++) {
String[] attr = sp[i].split("=");
if (attr.length != 2) {
Log.w(TAG, " Unable to parse " + sp[i]);
} else {
set.setFloatValue(attr[0], Integer.decode(attr[1]));
}
}
}
/**
* Parse color
* @param set
* @param attributes
*/
public void parseColorAttributes(Constraint set, String attributes) {
String[] sp = attributes.split(",");
for (int i = 0; i < sp.length; i++) {
String[] attr = sp[i].split("=");
if (attr.length != 2) {
Log.w(TAG, " Unable to parse " + sp[i]);
} else {
set.setColorValue(attr[0], Color.parseColor(attr[1]));
}
}
}
/**
* Parse floats
* @param set
* @param attributes
*/
public void parseFloatAttributes(Constraint set, String attributes) {
String[] sp = attributes.split(",");
for (int i = 0; i < sp.length; i++) {
String[] attr = sp[i].split("=");
if (attr.length != 2) {
Log.w(TAG, " Unable to parse " + sp[i]);
} else {
set.setFloatValue(attr[0], Float.parseFloat(attr[1]));
}
}
}
/**
* Parse string
* @param set
* @param attributes
*/
public void parseStringAttributes(Constraint set, String attributes) {
String[] sp = splitString(attributes);
for (int i = 0; i < sp.length; i++) {
String[] attr = sp[i].split("=");
Log.w(TAG, " Unable to parse " + sp[i]);
set.setStringValue(attr[0], attr[1]);
}
}
private static String[] splitString(String str) {
char[] chars = str.toCharArray();
ArrayList<String> list = new ArrayList<>();
boolean inDouble = false;
int start = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == ',' && !inDouble) {
list.add(new String(chars, start, i - start));
start = i + 1;
} else if (chars[i] == '"') {
inDouble = !inDouble;
}
}
list.add(new String(chars, start, chars.length - start));
return list.toArray(new String[list.size()]);
}
/**
* Add attribute of type Int
* @param attributeName
*/
public void addIntAttributes(String... attributeName) {
addAttributes(AttributeType.INT_TYPE, attributeName);
}
/**
* Add attribute of type Color
* @param attributeName
*/
public void addColorAttributes(String... attributeName) {
addAttributes(AttributeType.COLOR_TYPE, attributeName);
}
/**
* Add attribute of type float
* @param attributeName
*/
public void addFloatAttributes(String... attributeName) {
addAttributes(AttributeType.FLOAT_TYPE, attributeName);
}
/**
* Add attribute of type string
* @param attributeName
*/
public void addStringAttributes(String... attributeName) {
addAttributes(AttributeType.STRING_TYPE, attributeName);
}
private Constraint get(int id) {
if (!mConstraints.containsKey(id)) {
mConstraints.put(id, new Constraint());
}
return mConstraints.get(id);
}
private String sideToString(int side) {
switch (side) {
case LEFT:
return "left";
case RIGHT:
return "right";
case TOP:
return "top";
case BOTTOM:
return "bottom";
case BASELINE:
return "baseline";
case START:
return "start";
case END:
return "end";
}
return "undefined";
}
/**
* Load a constraint set from a constraintSet.xml file.
* Note. Do NOT use this to load a layout file.
* It will fail silently as there is no efficient way to differentiate.
*
* @param context the context for the inflation
* @param resourceId id of xml file in res/xml/
*/
public void load(Context context, int resourceId) {
Resources res = context.getResources();
XmlPullParser parser = res.getXml(resourceId);
try {
for (int eventType = parser.getEventType();
eventType != XmlResourceParser.END_DOCUMENT;
eventType = parser.next()) {
switch (eventType) {
case XmlResourceParser.START_DOCUMENT:
case XmlResourceParser.END_TAG:
case XmlResourceParser.TEXT:
break;
case XmlResourceParser.START_TAG:
String tagName = parser.getName();
Constraint constraint = fillFromAttributeList(context,
Xml.asAttributeSet(parser), false);
if (tagName.equalsIgnoreCase("Guideline")) {
constraint.layout.mIsGuideline = true;
}
if (DEBUG) {
Log.v(TAG, Debug.getLoc()
+ " cache " + Debug.getName(context, constraint.mViewId)
+ " " + constraint.mViewId);
}
mConstraints.put(constraint.mViewId, constraint);
break;
}
}
} catch (XmlPullParserException e) {
Log.e(TAG, "Error parsing resource: " + resourceId, e);
} catch (IOException e) {
Log.e(TAG, "Error parsing resource: " + resourceId, e);
}
}
/**
* Load a constraint set from a constraintSet.xml file
*
* @param context the context for the inflation
* @param parser id of xml file in res/xml/
*/
public void load(Context context, XmlPullParser parser) {
String tagName = null;
try {
Constraint constraint = null;
for (int eventType = parser.getEventType();
eventType != XmlResourceParser.END_DOCUMENT;
eventType = parser.next()) {
switch (eventType) {
case XmlResourceParser.START_DOCUMENT:
String document = parser.getName();
break;
case XmlResourceParser.START_TAG:
tagName = parser.getName();
if (DEBUG) {
Log.v(TAG, Debug.getLoc() + " " + document + " tagName=" + tagName);
}
switch (tagName) {
case "Constraint":
constraint = fillFromAttributeList(context,
Xml.asAttributeSet(parser), false);
break;
case "ConstraintOverride":
constraint = fillFromAttributeList(context,
Xml.asAttributeSet(parser), true);
break;
case "Guideline":
constraint = fillFromAttributeList(context,
Xml.asAttributeSet(parser), false);
constraint.layout.mIsGuideline = true;
constraint.layout.mApply = true;
break;
case "Barrier":
constraint = fillFromAttributeList(context,
Xml.asAttributeSet(parser), false);
constraint.layout.mHelperType = BARRIER_TYPE;
break;
case "PropertySet":
if (constraint == null) {
throw new RuntimeException(ERROR_MESSAGE
+ parser.getLineNumber());
}
constraint.propertySet.fillFromAttributeList(context,
Xml.asAttributeSet(parser));
break;
case "Transform":
if (constraint == null) {
throw new RuntimeException(ERROR_MESSAGE
+ parser.getLineNumber());
}
constraint.transform.fillFromAttributeList(context,
Xml.asAttributeSet(parser));
break;
case "Layout":
if (constraint == null) {
throw new RuntimeException(ERROR_MESSAGE
+ parser.getLineNumber());
}
constraint.layout.fillFromAttributeList(context,
Xml.asAttributeSet(parser));
break;
case "Motion":
if (constraint == null) {
throw new RuntimeException(ERROR_MESSAGE
+ parser.getLineNumber());
}
constraint.motion.fillFromAttributeList(context,
Xml.asAttributeSet(parser));
break;
case "CustomAttribute":
case "CustomMethod":
if (constraint == null) {
throw new RuntimeException(ERROR_MESSAGE
+ parser.getLineNumber());
}
ConstraintAttribute.parse(context, parser,
constraint.mCustomConstraints);
break;
}
// if (tagName.equalsIgnoreCase("Constraint")) {
// constraint = fillFromAttributeList(context,
// Xml.asAttributeSet(parser));
// } else if (tagName.equalsIgnoreCase("Guideline")) {
// constraint = fillFromAttributeList(context,
// Xml.asAttributeSet(parser));
// constraint.layout.mIsGuideline = true;
// } else if (tagName.equalsIgnoreCase("CustomAttribute")) {
// ConstraintAttribute.parse(context, parser,
// constraint.mCustomConstraints);
// }
break;
case XmlResourceParser.END_TAG:
tagName = parser.getName();
switch (tagName.toLowerCase(Locale.ROOT)) {
case "constraintset":
return;
case "constraint":
case "constraintoverride":
case "guideline":
mConstraints.put(constraint.mViewId, constraint);
constraint = null;
}
tagName = null;
break;
case XmlResourceParser.TEXT:
break;
}
}
} catch (XmlPullParserException e) {
Log.e(TAG, "Error parsing XML resource", e);
} catch (IOException e) {
Log.e(TAG, "Error parsing XML resource", e);
}
}
private static int lookupID(TypedArray a, int index, int def) {
int ret = a.getResourceId(index, def);
if (ret == Layout.UNSET) {
ret = a.getInt(index, Layout.UNSET);
}
return ret;
}
private Constraint fillFromAttributeList(Context context,
AttributeSet attrs,
boolean override) {
Constraint c = new Constraint();
TypedArray a = context.obtainStyledAttributes(attrs,
override ? R.styleable.ConstraintOverride : R.styleable.Constraint);
populateConstraint(c, a, override);
a.recycle();
return c;
}
/**
* Used to read a ConstraintDelta
*
* @param context
* @param parser
* @return
*/
public static Constraint buildDelta(Context context, XmlPullParser parser) {
AttributeSet attrs = Xml.asAttributeSet(parser);
Constraint c = new Constraint();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ConstraintOverride);
populateOverride(c, a);
a.recycle();
return c;
}
private static void populateOverride(Constraint c, TypedArray a) {
final int count = a.getIndexCount();
TypedValue type;
Constraint.Delta delta = new Constraint.Delta();
c.mDelta = delta;
c.motion.mApply = false;
c.layout.mApply = false;
c.propertySet.mApply = false;
c.transform.mApply = false;
for (int i = 0; i < count; i++) {
int attr = a.getIndex(i);
int attrType = sOverrideMapToConstant.get(attr);
if (DEBUG) {
Log.v(TAG, Debug.getLoc() + " > " + attrType + " " + getDebugName(attrType));
}
switch (attrType) {
case EDITOR_ABSOLUTE_X:
delta.add(EDITOR_ABSOLUTE_X,
a.getDimensionPixelOffset(attr, c.layout.editorAbsoluteX));
break;
case EDITOR_ABSOLUTE_Y:
delta.add(EDITOR_ABSOLUTE_Y,
a.getDimensionPixelOffset(attr, c.layout.editorAbsoluteY));
break;
case GUIDE_BEGIN:
delta.add(GUIDE_BEGIN, a.getDimensionPixelOffset(attr, c.layout.guideBegin));
break;
case GUIDE_END:
delta.add(GUIDE_END, a.getDimensionPixelOffset(attr, c.layout.guideEnd));
break;
case GUIDE_PERCENT:
delta.add(GUIDE_PERCENT, a.getFloat(attr, c.layout.guidePercent));
break;
case GUIDELINE_USE_RTL:
delta.add(GUIDELINE_USE_RTL, a.getBoolean(attr, c.layout.guidelineUseRtl));
break;
case ORIENTATION:
delta.add(ORIENTATION, a.getInt(attr, c.layout.orientation));
break;
case CIRCLE_RADIUS:
delta.add(CIRCLE_RADIUS, a.getDimensionPixelSize(attr, c.layout.circleRadius));
break;
case CIRCLE_ANGLE:
delta.add(CIRCLE_ANGLE, a.getFloat(attr, c.layout.circleAngle));
break;
case GONE_LEFT_MARGIN:
delta.add(GONE_LEFT_MARGIN,
a.getDimensionPixelSize(attr, c.layout.goneLeftMargin));
break;
case GONE_TOP_MARGIN:
delta.add(GONE_TOP_MARGIN,
a.getDimensionPixelSize(attr, c.layout.goneTopMargin));
break;
case GONE_RIGHT_MARGIN:
delta.add(GONE_RIGHT_MARGIN,
a.getDimensionPixelSize(attr, c.layout.goneRightMargin));
break;
case GONE_BOTTOM_MARGIN:
delta.add(GONE_BOTTOM_MARGIN,
a.getDimensionPixelSize(attr, c.layout.goneBottomMargin));
break;
case GONE_START_MARGIN:
delta.add(GONE_START_MARGIN,
a.getDimensionPixelSize(attr, c.layout.goneStartMargin));
break;
case GONE_END_MARGIN:
delta.add(GONE_END_MARGIN,
a.getDimensionPixelSize(attr, c.layout.goneEndMargin));
break;
case GONE_BASELINE_MARGIN:
delta.add(GONE_BASELINE_MARGIN,
a.getDimensionPixelSize(attr, c.layout.goneBaselineMargin));
break;
case HORIZONTAL_BIAS:
delta.add(HORIZONTAL_BIAS, a.getFloat(attr, c.layout.horizontalBias));
break;
case VERTICAL_BIAS:
delta.add(VERTICAL_BIAS, a.getFloat(attr, c.layout.verticalBias));
break;
case LEFT_MARGIN:
delta.add(LEFT_MARGIN, a.getDimensionPixelSize(attr, c.layout.leftMargin));
break;
case RIGHT_MARGIN:
delta.add(RIGHT_MARGIN, a.getDimensionPixelSize(attr, c.layout.rightMargin));
break;
case START_MARGIN:
delta.add(START_MARGIN,
a.getDimensionPixelSize(attr, c.layout.startMargin));
break;
case END_MARGIN:
delta.add(END_MARGIN, a.getDimensionPixelSize(attr, c.layout.endMargin));
break;
case TOP_MARGIN:
delta.add(TOP_MARGIN, a.getDimensionPixelSize(attr, c.layout.topMargin));
break;
case BOTTOM_MARGIN:
delta.add(BOTTOM_MARGIN, a.getDimensionPixelSize(attr, c.layout.bottomMargin));
break;
case BASELINE_MARGIN:
delta.add(BASELINE_MARGIN,
a.getDimensionPixelSize(attr, c.layout.baselineMargin));
break;
case LAYOUT_WIDTH:
delta.add(LAYOUT_WIDTH, a.getLayoutDimension(attr, c.layout.mWidth));
break;
case LAYOUT_HEIGHT:
delta.add(LAYOUT_HEIGHT, a.getLayoutDimension(attr, c.layout.mHeight));
break;
case LAYOUT_CONSTRAINT_WIDTH:
ConstraintSet.parseDimensionConstraints(delta, a, attr, HORIZONTAL);
break;
case LAYOUT_CONSTRAINT_HEIGHT:
ConstraintSet.parseDimensionConstraints(delta, a, attr, VERTICAL);
break;
case LAYOUT_WRAP_BEHAVIOR:
delta.add(LAYOUT_WRAP_BEHAVIOR, a.getInt(attr, c.layout.mWrapBehavior));
break;
case WIDTH_DEFAULT:
delta.add(WIDTH_DEFAULT, a.getInt(attr, c.layout.widthDefault));
break;
case HEIGHT_DEFAULT:
delta.add(HEIGHT_DEFAULT, a.getInt(attr, c.layout.heightDefault));
break;
case HEIGHT_MAX:
delta.add(HEIGHT_MAX, a.getDimensionPixelSize(attr, c.layout.heightMax));
break;
case WIDTH_MAX:
delta.add(WIDTH_MAX, a.getDimensionPixelSize(attr, c.layout.widthMax));
break;
case HEIGHT_MIN:
delta.add(HEIGHT_MIN, a.getDimensionPixelSize(attr, c.layout.heightMin));
break;
case WIDTH_MIN:
delta.add(WIDTH_MIN, a.getDimensionPixelSize(attr, c.layout.widthMin));
break;
case CONSTRAINED_WIDTH:
delta.add(CONSTRAINED_WIDTH, a.getBoolean(attr, c.layout.constrainedWidth));
break;
case CONSTRAINED_HEIGHT:
delta.add(CONSTRAINED_HEIGHT, a.getBoolean(attr, c.layout.constrainedHeight));
break;
case LAYOUT_VISIBILITY:
delta.add(LAYOUT_VISIBILITY,
VISIBILITY_FLAGS[a.getInt(attr, c.propertySet.visibility)]);
break;
case VISIBILITY_MODE:
delta.add(VISIBILITY_MODE, a.getInt(attr, c.propertySet.mVisibilityMode));
break;
case ALPHA:
delta.add(ALPHA, a.getFloat(attr, c.propertySet.alpha));
break;
case ELEVATION:
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
delta.add(ELEVATION, true);
delta.add(ELEVATION, a.getDimension(attr, c.transform.elevation));
}
break;
case ROTATION:
delta.add(ROTATION, a.getFloat(attr, c.transform.rotation));
break;
case ROTATION_X:
delta.add(ROTATION_X, a.getFloat(attr, c.transform.rotationX));
break;
case ROTATION_Y:
delta.add(ROTATION_Y, a.getFloat(attr, c.transform.rotationY));
break;
case SCALE_X:
delta.add(SCALE_X, a.getFloat(attr, c.transform.scaleX));
break;
case SCALE_Y:
delta.add(SCALE_Y, a.getFloat(attr, c.transform.scaleY));
break;
case TRANSFORM_PIVOT_X:
delta.add(TRANSFORM_PIVOT_X, a.getDimension(attr, c.transform.transformPivotX));
break;
case TRANSFORM_PIVOT_Y:
delta.add(TRANSFORM_PIVOT_Y, a.getDimension(attr, c.transform.transformPivotY));
break;
case TRANSLATION_X:
delta.add(TRANSLATION_X, a.getDimension(attr, c.transform.translationX));
break;
case TRANSLATION_Y:
delta.add(TRANSLATION_Y, a.getDimension(attr, c.transform.translationY));
break;
case TRANSLATION_Z:
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
delta.add(TRANSLATION_Z, a.getDimension(attr, c.transform.translationZ));
}
break;
case TRANSFORM_PIVOT_TARGET:
delta.add(TRANSFORM_PIVOT_TARGET,
lookupID(a, attr, c.transform.transformPivotTarget));
break;
case VERTICAL_WEIGHT:
delta.add(VERTICAL_WEIGHT, a.getFloat(attr, c.layout.verticalWeight));
break;
case HORIZONTAL_WEIGHT:
delta.add(HORIZONTAL_WEIGHT, a.getFloat(attr, c.layout.horizontalWeight));
break;
case VERTICAL_STYLE:
delta.add(VERTICAL_STYLE, a.getInt(attr, c.layout.verticalChainStyle));
break;
case HORIZONTAL_STYLE:
delta.add(HORIZONTAL_STYLE, a.getInt(attr, c.layout.horizontalChainStyle));
break;
case VIEW_ID:
c.mViewId = a.getResourceId(attr, c.mViewId);
delta.add(VIEW_ID, c.mViewId);
break;
case MOTION_TARGET:
if (MotionLayout.IS_IN_EDIT_MODE) {
c.mViewId = a.getResourceId(attr, c.mViewId);
if (c.mViewId == -1) {
c.mTargetString = a.getString(attr);
}
} else {
if (a.peekValue(attr).type == TypedValue.TYPE_STRING) {
c.mTargetString = a.getString(attr);
} else {
c.mViewId = a.getResourceId(attr, c.mViewId);
}
}
break;
case DIMENSION_RATIO:
delta.add(DIMENSION_RATIO, a.getString(attr));
break;
case WIDTH_PERCENT:
delta.add(WIDTH_PERCENT, a.getFloat(attr, 1));
break;
case HEIGHT_PERCENT:
delta.add(HEIGHT_PERCENT, a.getFloat(attr, 1));
break;
case PROGRESS:
delta.add(PROGRESS, a.getFloat(attr, c.propertySet.mProgress));
break;
case ANIMATE_RELATIVE_TO:
delta.add(ANIMATE_RELATIVE_TO,
lookupID(a, attr, c.motion.mAnimateRelativeTo));
break;
case ANIMATE_CIRCLE_ANGLE_TO:
delta.add(ANIMATE_CIRCLE_ANGLE_TO,
a.getInteger(attr, c.motion.mAnimateCircleAngleTo));
break;
case TRANSITION_EASING:
type = a.peekValue(attr);
if (type.type == TypedValue.TYPE_STRING) {
delta.add(TRANSITION_EASING, a.getString(attr));
} else {
delta.add(TRANSITION_EASING,
Easing.NAMED_EASING[a.getInteger(attr, 0)]);
}
break;
case PATH_MOTION_ARC:
delta.add(PATH_MOTION_ARC, a.getInt(attr, c.motion.mPathMotionArc));
break;
case TRANSITION_PATH_ROTATE:
delta.add(TRANSITION_PATH_ROTATE, a.getFloat(attr, c.motion.mPathRotate));
break;
case MOTION_STAGGER:
delta.add(MOTION_STAGGER, a.getFloat(attr, c.motion.mMotionStagger));
break;
case QUANTIZE_MOTION_STEPS:
delta.add(QUANTIZE_MOTION_STEPS, a.getInteger(attr,
c.motion.mQuantizeMotionSteps));
break;
case QUANTIZE_MOTION_PHASE:
delta.add(QUANTIZE_MOTION_PHASE, a.getFloat(attr,
c.motion.mQuantizeMotionPhase));
break;
case QUANTIZE_MOTION_INTERPOLATOR:
type = a.peekValue(attr);
if (type.type == TypedValue.TYPE_REFERENCE) {
c.motion.mQuantizeInterpolatorID = a.getResourceId(attr, -1);
delta.add(QUANTIZE_MOTION_INTERPOLATOR_ID,
c.motion.mQuantizeInterpolatorID);
if (c.motion.mQuantizeInterpolatorID != -1) {
c.motion.mQuantizeInterpolatorType = Motion.INTERPOLATOR_REFERENCE_ID;
delta.add(QUANTIZE_MOTION_INTERPOLATOR_TYPE,
c.motion.mQuantizeInterpolatorType);
}
} else if (type.type == TypedValue.TYPE_STRING) {
c.motion.mQuantizeInterpolatorString = a.getString(attr);
delta.add(QUANTIZE_MOTION_INTERPOLATOR_STR,
c.motion.mQuantizeInterpolatorString);
if (c.motion.mQuantizeInterpolatorString.indexOf("/") > 0) {
c.motion.mQuantizeInterpolatorID = a.getResourceId(attr, -1);
delta.add(QUANTIZE_MOTION_INTERPOLATOR_ID,
c.motion.mQuantizeInterpolatorID);
c.motion.mQuantizeInterpolatorType = Motion.INTERPOLATOR_REFERENCE_ID;
delta.add(QUANTIZE_MOTION_INTERPOLATOR_TYPE,
c.motion.mQuantizeInterpolatorType);
} else {
c.motion.mQuantizeInterpolatorType = Motion.SPLINE_STRING;
delta.add(QUANTIZE_MOTION_INTERPOLATOR_TYPE,
c.motion.mQuantizeInterpolatorType);
}
} else {
c.motion.mQuantizeInterpolatorType =
a.getInteger(attr, c.motion.mQuantizeInterpolatorID);
delta.add(QUANTIZE_MOTION_INTERPOLATOR_TYPE,
c.motion.mQuantizeInterpolatorType);
}
break;
case DRAW_PATH:
delta.add(DRAW_PATH, a.getInt(attr, 0));
break;
case CHAIN_USE_RTL:
Log.e(TAG, "CURRENTLY UNSUPPORTED"); // TODO add support or remove
// TODO add support or remove
// c.mChainUseRtl = a.getBoolean(attr,c.mChainUseRtl);
break;
case BARRIER_DIRECTION:
delta.add(BARRIER_DIRECTION, a.getInt(attr, c.layout.mBarrierDirection));
break;
case BARRIER_MARGIN:
delta.add(BARRIER_MARGIN, a.getDimensionPixelSize(attr,
c.layout.mBarrierMargin));
break;
case CONSTRAINT_REFERENCED_IDS:
delta.add(CONSTRAINT_REFERENCED_IDS, a.getString(attr));
break;
case CONSTRAINT_TAG:
delta.add(CONSTRAINT_TAG, a.getString(attr));
break;
case BARRIER_ALLOWS_GONE_WIDGETS:
delta.add(BARRIER_ALLOWS_GONE_WIDGETS, a.getBoolean(attr,
c.layout.mBarrierAllowsGoneWidgets));
break;
case UNUSED:
Log.w(TAG,
"unused attribute 0x" + Integer.toHexString(attr)
+ " " + sMapToConstant.get(attr));
break;
default:
Log.w(TAG,
"Unknown attribute 0x" + Integer.toHexString(attr)
+ " " + sMapToConstant.get(attr));
}
}
}
private static void setDeltaValue(Constraint c, int type, float value) {
switch (type) {
case GUIDE_PERCENT:
c.layout.guidePercent = value;
break;
case CIRCLE_ANGLE:
c.layout.circleAngle = value;
break;
case HORIZONTAL_BIAS:
c.layout.horizontalBias = value;
break;
case VERTICAL_BIAS:
c.layout.verticalBias = value;
break;
case ALPHA:
c.propertySet.alpha = value;
break;
case ELEVATION:
c.transform.elevation = value;
c.transform.applyElevation = true;
break;
case ROTATION:
c.transform.rotation = value;
break;
case ROTATION_X:
c.transform.rotationX = value;
break;
case ROTATION_Y:
c.transform.rotationY = value;
break;
case SCALE_X:
c.transform.scaleX = value;
break;
case SCALE_Y:
c.transform.scaleY = value;
break;
case TRANSFORM_PIVOT_X:
c.transform.transformPivotX = value;
break;
case TRANSFORM_PIVOT_Y:
c.transform.transformPivotY = value;
break;
case TRANSLATION_X:
c.transform.translationX = value;
break;
case TRANSLATION_Y:
c.transform.translationY = value;
break;
case TRANSLATION_Z:
c.transform.translationZ = value;
break;
case VERTICAL_WEIGHT:
c.layout.verticalWeight = value;
break;
case HORIZONTAL_WEIGHT:
c.layout.horizontalWeight = value;
break;
case WIDTH_PERCENT:
c.layout.widthPercent = value;
break;
case HEIGHT_PERCENT:
c.layout.heightPercent = value;
break;
case PROGRESS:
c.propertySet.mProgress = value;
break;
case TRANSITION_PATH_ROTATE:
c.motion.mPathRotate = value;
break;
case MOTION_STAGGER:
c.motion.mMotionStagger = value;
break;
case QUANTIZE_MOTION_PHASE:
c.motion.mQuantizeMotionPhase = value;
break;
case UNUSED:
break;
default:
Log.w(TAG,
"Unknown attribute 0x");
}
}
private static void setDeltaValue(Constraint c, int type, int value) {
switch (type) {
case EDITOR_ABSOLUTE_X:
c.layout.editorAbsoluteX = value;
break;
case EDITOR_ABSOLUTE_Y:
c.layout.editorAbsoluteY = value;
break;
case LAYOUT_WRAP_BEHAVIOR:
c.layout.mWrapBehavior = value;
break;
case GUIDE_BEGIN:
c.layout.guideBegin = value;
break;
case GUIDE_END:
c.layout.guideEnd = value;
break;
case ORIENTATION:
c.layout.orientation = value;
break;
case CIRCLE:
c.layout.circleConstraint = value;
break;
case CIRCLE_RADIUS:
c.layout.circleRadius = value;
break;
case GONE_LEFT_MARGIN:
c.layout.goneLeftMargin = value;
break;
case GONE_TOP_MARGIN:
c.layout.goneTopMargin = value;
break;
case GONE_RIGHT_MARGIN:
c.layout.goneRightMargin = value;
break;
case GONE_BOTTOM_MARGIN:
c.layout.goneBottomMargin = value;
break;
case GONE_START_MARGIN:
c.layout.goneStartMargin = value;
break;
case GONE_END_MARGIN:
c.layout.goneEndMargin = value;
break;
case GONE_BASELINE_MARGIN:
c.layout.goneBaselineMargin = value;
break;
case LEFT_MARGIN:
c.layout.leftMargin = value;
break;
case RIGHT_MARGIN:
c.layout.rightMargin = value;
break;
case START_MARGIN:
c.layout.startMargin = value;
break;
case END_MARGIN:
c.layout.endMargin = value;
break;
case TOP_MARGIN:
c.layout.topMargin = value;
break;
case BOTTOM_MARGIN:
c.layout.bottomMargin = value;
break;
case BASELINE_MARGIN:
c.layout.baselineMargin = value;
break;
case LAYOUT_WIDTH:
c.layout.mWidth = value;
break;
case LAYOUT_HEIGHT:
c.layout.mHeight = value;
break;
case WIDTH_DEFAULT:
c.layout.widthDefault = value;
break;
case HEIGHT_DEFAULT:
c.layout.heightDefault = value;
break;
case HEIGHT_MAX:
c.layout.heightMax = value;
break;
case WIDTH_MAX:
c.layout.widthMax = value;
break;
case HEIGHT_MIN:
c.layout.heightMin = value;
break;
case WIDTH_MIN:
c.layout.widthMin = value;
break;
case LAYOUT_VISIBILITY:
c.propertySet.visibility = value;
break;
case VISIBILITY_MODE:
c.propertySet.mVisibilityMode = value;
break;
case TRANSFORM_PIVOT_TARGET:
c.transform.transformPivotTarget = value;
break;
case VERTICAL_STYLE:
c.layout.verticalChainStyle = value;
break;
case HORIZONTAL_STYLE:
c.layout.horizontalChainStyle = value;
break;
case VIEW_ID:
c.mViewId = value;
break;
case ANIMATE_RELATIVE_TO:
c.motion.mAnimateRelativeTo = value;
break;
case ANIMATE_CIRCLE_ANGLE_TO:
c.motion.mAnimateCircleAngleTo = value;
break;
case PATH_MOTION_ARC:
c.motion.mPathMotionArc = value;
break;
case QUANTIZE_MOTION_STEPS:
c.motion.mQuantizeMotionSteps = value;
break;
case QUANTIZE_MOTION_INTERPOLATOR_TYPE:
c.motion.mQuantizeInterpolatorType = value;
break;
case QUANTIZE_MOTION_INTERPOLATOR_ID:
c.motion.mQuantizeInterpolatorID = value;
break;
case DRAW_PATH:
c.motion.mDrawPath = value;
break;
case BARRIER_DIRECTION:
c.layout.mBarrierDirection = value;
break;
case BARRIER_MARGIN:
c.layout.mBarrierMargin = value;
break;
case UNUSED:
break;
default:
Log.w(TAG,
"Unknown attribute 0x");
}
}
private static void setDeltaValue(Constraint c, int type, String value) {
switch (type) {
case DIMENSION_RATIO:
c.layout.dimensionRatio = value;
break;
case TRANSITION_EASING:
c.motion.mTransitionEasing = value;
break;
case QUANTIZE_MOTION_INTERPOLATOR_STR:
c.motion.mQuantizeInterpolatorString = value;
break;
case CONSTRAINT_REFERENCED_IDS:
c.layout.mReferenceIdString = value;
// If a string is defined, clear up the reference ids array
c.layout.mReferenceIds = null;
break;
case CONSTRAINT_TAG:
c.layout.mConstraintTag = value;
break;
case UNUSED:
break;
default:
Log.w(TAG,
"Unknown attribute 0x");
}
}
private static void setDeltaValue(Constraint c, int type, boolean value) {
switch (type) {
case CONSTRAINED_WIDTH:
c.layout.constrainedWidth = value;
break;
case CONSTRAINED_HEIGHT:
c.layout.constrainedHeight = value;
break;
case ELEVATION:
c.transform.applyElevation = value;
break;
case BARRIER_ALLOWS_GONE_WIDGETS:
c.layout.mBarrierAllowsGoneWidgets = value;
break;
case UNUSED:
break;
default:
Log.w(TAG, "Unknown attribute 0x");
}
}
private void populateConstraint(Constraint c, TypedArray a, boolean override) {
if (override) {
populateOverride(c, a);
return;
}
final int count = a.getIndexCount();
for (int i = 0; i < count; i++) {
int attr = a.getIndex(i);
if (DEBUG) { // USEFUL when adding features to track tags being parsed
try {
Field[] campos = R.styleable.class.getFields();
boolean found = false;
for (Field f : campos) {
try {
if (f.getType().isPrimitive()
&& attr == f.getInt(null) && f.getName()
.contains("Constraint_")) {
found = true;
if (DEBUG) {
Log.v(TAG, "L id " + f.getName() + " #" + attr);
}
break;
}
} catch (Exception e) {
}
}
if (!found) {
campos = android.R.attr.class.getFields();
for (Field f : campos) {
try {
if (f.getType().isPrimitive() && attr == f.getInt(null)
&& f.getName()
.contains("Constraint_")) {
found = false;
if (DEBUG) {
Log.v(TAG, "x id " + f.getName());
}
break;
}
} catch (Exception e) {
}
}
}
if (!found) {
Log.v(TAG, " ? " + attr);
}
} catch (Exception e) {
Log.v(TAG, " " + e.toString());
}
}
if (attr != R.styleable.Constraint_android_id
&& R.styleable.Constraint_android_layout_marginStart != attr
&& R.styleable.Constraint_android_layout_marginEnd != attr) {
c.motion.mApply = true;
c.layout.mApply = true;
c.propertySet.mApply = true;
c.transform.mApply = true;
}
switch (sMapToConstant.get(attr)) {
case LEFT_TO_LEFT:
c.layout.leftToLeft = lookupID(a, attr, c.layout.leftToLeft);
break;
case LEFT_TO_RIGHT:
c.layout.leftToRight = lookupID(a, attr, c.layout.leftToRight);
break;
case RIGHT_TO_LEFT:
c.layout.rightToLeft = lookupID(a, attr, c.layout.rightToLeft);
break;
case RIGHT_TO_RIGHT:
c.layout.rightToRight = lookupID(a, attr, c.layout.rightToRight);
break;
case TOP_TO_TOP:
c.layout.topToTop = lookupID(a, attr, c.layout.topToTop);
break;
case TOP_TO_BOTTOM:
c.layout.topToBottom = lookupID(a, attr, c.layout.topToBottom);
break;
case BOTTOM_TO_TOP:
c.layout.bottomToTop = lookupID(a, attr, c.layout.bottomToTop);
break;
case BOTTOM_TO_BOTTOM:
c.layout.bottomToBottom = lookupID(a, attr, c.layout.bottomToBottom);
break;
case BASELINE_TO_BASELINE:
c.layout.baselineToBaseline = lookupID(a, attr, c.layout.baselineToBaseline);
break;
case BASELINE_TO_TOP:
c.layout.baselineToTop = lookupID(a, attr, c.layout.baselineToTop);
break;
case BASELINE_TO_BOTTOM:
c.layout.baselineToBottom = lookupID(a, attr, c.layout.baselineToBottom);
break;
case EDITOR_ABSOLUTE_X:
c.layout.editorAbsoluteX = a.getDimensionPixelOffset(attr,
c.layout.editorAbsoluteX);
break;
case EDITOR_ABSOLUTE_Y:
c.layout.editorAbsoluteY = a.getDimensionPixelOffset(attr,
c.layout.editorAbsoluteY);
break;
case GUIDE_BEGIN:
c.layout.guideBegin = a.getDimensionPixelOffset(attr, c.layout.guideBegin);
break;
case GUIDE_END:
c.layout.guideEnd = a.getDimensionPixelOffset(attr, c.layout.guideEnd);
break;
case GUIDE_PERCENT:
c.layout.guidePercent = a.getFloat(attr, c.layout.guidePercent);
break;
case ORIENTATION:
c.layout.orientation = a.getInt(attr, c.layout.orientation);
break;
case START_TO_END:
c.layout.startToEnd = lookupID(a, attr, c.layout.startToEnd);
break;
case START_TO_START:
c.layout.startToStart = lookupID(a, attr, c.layout.startToStart);
break;
case END_TO_START:
c.layout.endToStart = lookupID(a, attr, c.layout.endToStart);
break;
case END_TO_END:
c.layout.endToEnd = lookupID(a, attr, c.layout.endToEnd);
break;
case CIRCLE:
c.layout.circleConstraint = lookupID(a, attr, c.layout.circleConstraint);
break;
case CIRCLE_RADIUS:
c.layout.circleRadius = a.getDimensionPixelSize(attr, c.layout.circleRadius);
break;
case CIRCLE_ANGLE:
c.layout.circleAngle = a.getFloat(attr, c.layout.circleAngle);
break;
case GONE_LEFT_MARGIN:
c.layout.goneLeftMargin = a.getDimensionPixelSize(attr,
c.layout.goneLeftMargin);
break;
case GONE_TOP_MARGIN:
c.layout.goneTopMargin = a.getDimensionPixelSize(attr, c.layout.goneTopMargin);
break;
case GONE_RIGHT_MARGIN:
c.layout.goneRightMargin = a.getDimensionPixelSize(attr,
c.layout.goneRightMargin);
break;
case GONE_BOTTOM_MARGIN:
c.layout.goneBottomMargin = a.getDimensionPixelSize(attr,
c.layout.goneBottomMargin);
break;
case GONE_START_MARGIN:
c.layout.goneStartMargin =
a.getDimensionPixelSize(attr, c.layout.goneStartMargin);
break;
case GONE_END_MARGIN:
c.layout.goneEndMargin = a.getDimensionPixelSize(attr, c.layout.goneEndMargin);
break;
case GONE_BASELINE_MARGIN:
c.layout.goneBaselineMargin = a.getDimensionPixelSize(attr,
c.layout.goneBaselineMargin);
break;
case HORIZONTAL_BIAS:
c.layout.horizontalBias = a.getFloat(attr, c.layout.horizontalBias);
break;
case VERTICAL_BIAS:
c.layout.verticalBias = a.getFloat(attr, c.layout.verticalBias);
break;
case LEFT_MARGIN:
c.layout.leftMargin = a.getDimensionPixelSize(attr, c.layout.leftMargin);
break;
case RIGHT_MARGIN:
c.layout.rightMargin = a.getDimensionPixelSize(attr, c.layout.rightMargin);
break;
case START_MARGIN:
c.layout.startMargin = a.getDimensionPixelSize(attr, c.layout.startMargin);
break;
case END_MARGIN:
c.layout.endMargin = a.getDimensionPixelSize(attr, c.layout.endMargin);
break;
case TOP_MARGIN:
c.layout.topMargin = a.getDimensionPixelSize(attr, c.layout.topMargin);
break;
case BOTTOM_MARGIN:
c.layout.bottomMargin = a.getDimensionPixelSize(attr, c.layout.bottomMargin);
break;
case BASELINE_MARGIN:
c.layout.baselineMargin = a.getDimensionPixelSize(attr,
c.layout.baselineMargin);
break;
case LAYOUT_WIDTH:
c.layout.mWidth = a.getLayoutDimension(attr, c.layout.mWidth);
break;
case LAYOUT_HEIGHT:
c.layout.mHeight = a.getLayoutDimension(attr, c.layout.mHeight);
break;
case LAYOUT_CONSTRAINT_WIDTH:
ConstraintSet.parseDimensionConstraints(c.layout, a, attr, HORIZONTAL);
break;
case LAYOUT_CONSTRAINT_HEIGHT:
ConstraintSet.parseDimensionConstraints(c.layout, a, attr, VERTICAL);
break;
case LAYOUT_WRAP_BEHAVIOR:
c.layout.mWrapBehavior = a.getInt(attr, c.layout.mWrapBehavior);
break;
case WIDTH_DEFAULT:
c.layout.widthDefault = a.getInt(attr, c.layout.widthDefault);
break;
case HEIGHT_DEFAULT:
c.layout.heightDefault = a.getInt(attr, c.layout.heightDefault);
break;
case HEIGHT_MAX:
c.layout.heightMax = a.getDimensionPixelSize(attr, c.layout.heightMax);
break;
case WIDTH_MAX:
c.layout.widthMax = a.getDimensionPixelSize(attr, c.layout.widthMax);
break;
case HEIGHT_MIN:
c.layout.heightMin = a.getDimensionPixelSize(attr, c.layout.heightMin);
break;
case WIDTH_MIN:
c.layout.widthMin = a.getDimensionPixelSize(attr, c.layout.widthMin);
break;
case CONSTRAINED_WIDTH:
c.layout.constrainedWidth = a.getBoolean(attr, c.layout.constrainedWidth);
break;
case CONSTRAINED_HEIGHT:
c.layout.constrainedHeight = a.getBoolean(attr, c.layout.constrainedHeight);
break;
case LAYOUT_VISIBILITY:
c.propertySet.visibility = a.getInt(attr, c.propertySet.visibility);
c.propertySet.visibility = VISIBILITY_FLAGS[c.propertySet.visibility];
break;
case VISIBILITY_MODE:
c.propertySet.mVisibilityMode = a.getInt(attr, c.propertySet.mVisibilityMode);
break;
case ALPHA:
c.propertySet.alpha = a.getFloat(attr, c.propertySet.alpha);
break;
case ELEVATION:
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
c.transform.applyElevation = true;
c.transform.elevation = a.getDimension(attr, c.transform.elevation);
}
break;
case ROTATION:
c.transform.rotation = a.getFloat(attr, c.transform.rotation);
break;
case ROTATION_X:
c.transform.rotationX = a.getFloat(attr, c.transform.rotationX);
break;
case ROTATION_Y:
c.transform.rotationY = a.getFloat(attr, c.transform.rotationY);
break;
case SCALE_X:
c.transform.scaleX = a.getFloat(attr, c.transform.scaleX);
break;
case SCALE_Y:
c.transform.scaleY = a.getFloat(attr, c.transform.scaleY);
break;
case TRANSFORM_PIVOT_X:
c.transform.transformPivotX = a.getDimension(attr, c.transform.transformPivotX);
break;
case TRANSFORM_PIVOT_Y:
c.transform.transformPivotY = a.getDimension(attr, c.transform.transformPivotY);
break;
case TRANSLATION_X:
c.transform.translationX = a.getDimension(attr, c.transform.translationX);
break;
case TRANSLATION_Y:
c.transform.translationY = a.getDimension(attr, c.transform.translationY);
break;
case TRANSLATION_Z:
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
c.transform.translationZ = a.getDimension(attr, c.transform.translationZ);
}
break;
case TRANSFORM_PIVOT_TARGET:
c.transform.transformPivotTarget =
lookupID(a, attr, c.transform.transformPivotTarget);
break;
case VERTICAL_WEIGHT:
c.layout.verticalWeight = a.getFloat(attr, c.layout.verticalWeight);
break;
case HORIZONTAL_WEIGHT:
c.layout.horizontalWeight = a.getFloat(attr, c.layout.horizontalWeight);
break;
case VERTICAL_STYLE:
c.layout.verticalChainStyle = a.getInt(attr, c.layout.verticalChainStyle);
break;
case HORIZONTAL_STYLE:
c.layout.horizontalChainStyle = a.getInt(attr, c.layout.horizontalChainStyle);
break;
case VIEW_ID:
c.mViewId = a.getResourceId(attr, c.mViewId);
break;
case DIMENSION_RATIO:
c.layout.dimensionRatio = a.getString(attr);
break;
case WIDTH_PERCENT:
c.layout.widthPercent = a.getFloat(attr, 1);
break;
case HEIGHT_PERCENT:
c.layout.heightPercent = a.getFloat(attr, 1);
break;
case PROGRESS:
c.propertySet.mProgress = a.getFloat(attr, c.propertySet.mProgress);
break;
case ANIMATE_RELATIVE_TO:
c.motion.mAnimateRelativeTo = lookupID(a, attr, c.motion.mAnimateRelativeTo);
break;
case ANIMATE_CIRCLE_ANGLE_TO:
c.motion.mAnimateCircleAngleTo =
a.getInteger(attr, c.motion.mAnimateCircleAngleTo);
break;
case TRANSITION_EASING:
TypedValue type = a.peekValue(attr);
if (type.type == TypedValue.TYPE_STRING) {
c.motion.mTransitionEasing = a.getString(attr);
} else {
c.motion.mTransitionEasing =
Easing.NAMED_EASING[a.getInteger(attr, 0)];
}
break;
case PATH_MOTION_ARC:
c.motion.mPathMotionArc = a.getInt(attr, c.motion.mPathMotionArc);
break;
case TRANSITION_PATH_ROTATE:
c.motion.mPathRotate = a.getFloat(attr, c.motion.mPathRotate);
break;
case MOTION_STAGGER:
c.motion.mMotionStagger = a.getFloat(attr, c.motion.mMotionStagger);
break;
case QUANTIZE_MOTION_STEPS:
c.motion.mQuantizeMotionSteps = a.getInteger(attr,
c.motion.mQuantizeMotionSteps);
break;
case QUANTIZE_MOTION_PHASE:
c.motion.mQuantizeMotionPhase = a.getFloat(attr, c.motion.mQuantizeMotionPhase);
break;
case QUANTIZE_MOTION_INTERPOLATOR:
type = a.peekValue(attr);
if (type.type == TypedValue.TYPE_REFERENCE) {
c.motion.mQuantizeInterpolatorID = a.getResourceId(attr, -1);
if (c.motion.mQuantizeInterpolatorID != -1) {
c.motion.mQuantizeInterpolatorType = Motion.INTERPOLATOR_REFERENCE_ID;
}
} else if (type.type == TypedValue.TYPE_STRING) {
c.motion.mQuantizeInterpolatorString = a.getString(attr);
if (c.motion.mQuantizeInterpolatorString.indexOf("/") > 0) {
c.motion.mQuantizeInterpolatorID = a.getResourceId(attr, -1);
c.motion.mQuantizeInterpolatorType = Motion.INTERPOLATOR_REFERENCE_ID;
} else {
c.motion.mQuantizeInterpolatorType = Motion.SPLINE_STRING;
}
} else {
c.motion.mQuantizeInterpolatorType = a.getInteger(attr,
c.motion.mQuantizeInterpolatorID);
}
break;
case DRAW_PATH:
c.motion.mDrawPath = a.getInt(attr, 0);
break;
case CHAIN_USE_RTL:
Log.e(TAG, "CURRENTLY UNSUPPORTED"); // TODO add support or remove
// TODO add support or remove c.mChainUseRtl =
// a.getBoolean(attr,c.mChainUseRtl);
break;
case BARRIER_DIRECTION:
c.layout.mBarrierDirection = a.getInt(attr, c.layout.mBarrierDirection);
break;
case BARRIER_MARGIN:
c.layout.mBarrierMargin = a.getDimensionPixelSize(attr,
c.layout.mBarrierMargin);
break;
case CONSTRAINT_REFERENCED_IDS:
c.layout.mReferenceIdString = a.getString(attr);
break;
case CONSTRAINT_TAG:
c.layout.mConstraintTag = a.getString(attr);
break;
case BARRIER_ALLOWS_GONE_WIDGETS:
c.layout.mBarrierAllowsGoneWidgets = a.getBoolean(attr,
c.layout.mBarrierAllowsGoneWidgets);
break;
case UNUSED:
Log.w(TAG,
"unused attribute 0x" + Integer.toHexString(attr)
+ " " + sMapToConstant.get(attr));
break;
default:
Log.w(TAG,
"Unknown attribute 0x" + Integer.toHexString(attr)
+ " " + sMapToConstant.get(attr));
}
}
if (c.layout.mReferenceIdString != null) {
// in case the strings are set, make sure to clear up the cached ids
c.layout.mReferenceIds = null;
}
}
private int[] convertReferenceString(View view, String referenceIdString) {
String[] split = referenceIdString.split(",");
Context context = view.getContext();
int[] tags = new int[split.length];
int count = 0;
for (int i = 0; i < split.length; i++) {
String idString = split[i];
idString = idString.trim();
int tag = 0;
try {
Class res = R.id.class;
Field field = res.getField(idString);
tag = field.getInt(null);
} catch (Exception e) {
// Do nothing
}
if (tag == 0) {
tag = context.getResources().getIdentifier(idString, "id",
context.getPackageName());
}
if (tag == 0 && view.isInEditMode() && view.getParent() instanceof ConstraintLayout) {
ConstraintLayout constraintLayout = (ConstraintLayout) view.getParent();
Object value = constraintLayout.getDesignInformation(0, idString);
if (value != null && value instanceof Integer) {
tag = (Integer) value;
}
}
tags[count++] = tag;
}
if (count != split.length) {
tags = Arrays.copyOf(tags, count);
}
return tags;
}
/**
*
*/
public Constraint getConstraint(int id) {
if (mConstraints.containsKey(id)) {
return mConstraints.get(id);
}
return null;
}
/**
*
*/
public int[] getKnownIds() {
Integer[] arr = mConstraints.keySet().toArray(new Integer[0]);
int[] array = new int[arr.length];
for (int i = 0; i < array.length; i++) {
array[i] = arr[i];
}
return array;
}
/**
* Enforce id are required for all ConstraintLayout children to use ConstraintSet.
* default = true;
*/
public boolean isForceId() {
return mForceId;
}
/**
* Enforce id are required for all ConstraintLayout children to use ConstraintSet.
* default = true;
*
* @param forceId
*/
public void setForceId(boolean forceId) {
this.mForceId = forceId;
}
/**
* If true perform validation checks when parsing ConstraintSets
* This will slow down parsing and should only be used for debugging
*
* @param validate
*/
public void setValidateOnParse(boolean validate) {
mValidate = validate;
}
/**
* If true perform validation checks when parsing ConstraintSets
* This will slow down parsing and should only be used for debugging
*
* @return validate
*/
public boolean isValidateOnParse() {
return mValidate;
}
/**
* Dump the contents
*
* @param scene
* @param ids
*/
public void dump(MotionScene scene, int... ids) {
Set<Integer> keys = mConstraints.keySet();
HashSet<Integer> set;
if (ids.length != 0) {
set = new HashSet<Integer>();
for (int id : ids) {
set.add(id);
}
} else {
set = new HashSet<>(keys);
}
System.out.println(set.size() + " constraints");
StringBuilder stringBuilder = new StringBuilder();
for (Integer id : set.toArray(new Integer[0])) {
Constraint constraint = mConstraints.get(id);
if (constraint == null) {
continue;
}
stringBuilder.append("<Constraint id=");
stringBuilder.append(id);
stringBuilder.append(" \n");
constraint.layout.dump(scene, stringBuilder);
stringBuilder.append("/>\n");
}
System.out.println(stringBuilder.toString());
}
/**
* Construct a user friendly error string
*
* @param context the context
* @param resourceId the xml being parsed
* @param pullParser the XML parser
* @return
*/
static String getLine(Context context, int resourceId, XmlPullParser pullParser) {
return ".(" + Debug.getName(context, resourceId)
+ ".xml:" + pullParser.getLineNumber()
+ ") \"" + pullParser.getName() + "\"";
}
static String getDebugName(int v) {
for (Field field : ConstraintSet.class.getDeclaredFields()) {
if (field.getName().contains("_")
&& field.getType() == int.class
&& java.lang.reflect.Modifier.isStatic(field.getModifiers())
&& java.lang.reflect.Modifier.isFinal(field.getModifiers())) {
int val = 0;
try {
val = field.getInt(null);
if (val == v) {
return field.getName();
}
} catch (IllegalAccessException e) {
Log.e(TAG, "Error accessing ConstraintSet field", e);
}
}
}
return "UNKNOWN";
}
/**
* Write the state to a Writer
* @param writer
* @param layout
* @param flags
* @throws IOException
*/
public void writeState(Writer writer, ConstraintLayout layout, int flags) throws IOException {
writer.write("\n---------------------------------------------\n");
if ((flags & 1) == 1) {
new WriteXmlEngine(writer, layout, flags).writeLayout();
} else {
new WriteJsonEngine(writer, layout, flags).writeLayout();
}
writer.write("\n---------------------------------------------\n");
}
class WriteXmlEngine {
Writer mWriter;
ConstraintLayout mLayout;
Context mContext;
int mFlags;
int mUnknownCount = 0;
final String mLEFT = "'left'";
final String mRIGHT = "'right'";
final String mBASELINE = "'baseline'";
final String mBOTTOM = "'bottom'";
final String mTOP = "'top'";
final String mSTART = "'start'";
final String mEND = "'end'";
WriteXmlEngine(Writer writer, ConstraintLayout layout, int flags) throws IOException {
this.mWriter = writer;
this.mLayout = layout;
this.mContext = layout.getContext();
this.mFlags = flags;
}
void writeLayout() throws IOException {
mWriter.write("\n<ConstraintSet>\n");
for (Integer id : mConstraints.keySet()) {
Constraint c = mConstraints.get(id);
String idName = getName(id);
mWriter.write(" <Constraint");
mWriter.write(SPACE + "android:id" + "=\"" + idName + "\"");
Layout l = c.layout;
writeBaseDimension("android:layout_width", l.mWidth, -5);
writeBaseDimension("android:layout_height", l.mHeight, -5);
writeVariable("app:layout_constraintGuide_begin", l.guideBegin, UNSET);
writeVariable("app:layout_constraintGuide_end", l.guideEnd, UNSET);
writeVariable("app:layout_constraintGuide_percent", l.guidePercent, UNSET);
writeVariable("app:layout_constraintHorizontal_bias",
l.horizontalBias, 0.5f);
writeVariable("app:layout_constraintVertical_bias",
l.verticalBias, 0.5f);
writeVariable("app:layout_constraintDimensionRatio",
l.dimensionRatio, null);
writeXmlConstraint("app:layout_constraintCircle", l.circleConstraint);
writeVariable("app:layout_constraintCircleRadius", l.circleRadius, 0);
writeVariable("app:layout_constraintCircleAngle", l.circleAngle, 0);
writeVariable("android:orientation", l.orientation, UNSET);
writeVariable("app:layout_constraintVertical_weight",
l.verticalWeight, UNSET);
writeVariable("app:layout_constraintHorizontal_weight",
l.horizontalWeight, UNSET);
writeVariable("app:layout_constraintHorizontal_chainStyle",
l.horizontalChainStyle, CHAIN_SPREAD);
writeVariable("app:layout_constraintVertical_chainStyle",
l.verticalChainStyle, CHAIN_SPREAD);
writeVariable("app:barrierDirection", l.mBarrierDirection, UNSET);
writeVariable("app:barrierMargin", l.mBarrierMargin, 0);
writeDimension("app:layout_marginLeft", l.leftMargin, 0);
writeDimension("app:layout_goneMarginLeft",
l.goneLeftMargin, Layout.UNSET_GONE_MARGIN);
writeDimension("app:layout_marginRight", l.rightMargin, 0);
writeDimension("app:layout_goneMarginRight",
l.goneRightMargin, Layout.UNSET_GONE_MARGIN);
writeDimension("app:layout_marginStart", l.startMargin, 0);
writeDimension("app:layout_goneMarginStart",
l.goneStartMargin, Layout.UNSET_GONE_MARGIN);
writeDimension("app:layout_marginEnd", l.endMargin, 0);
writeDimension("app:layout_goneMarginEnd",
l.goneEndMargin, Layout.UNSET_GONE_MARGIN);
writeDimension("app:layout_marginTop", l.topMargin, 0);
writeDimension("app:layout_goneMarginTop",
l.goneTopMargin, Layout.UNSET_GONE_MARGIN);
writeDimension("app:layout_marginBottom", l.bottomMargin, 0);
writeDimension("app:layout_goneMarginBottom",
l.goneBottomMargin, Layout.UNSET_GONE_MARGIN);
writeDimension("app:goneBaselineMargin",
l.goneBaselineMargin, Layout.UNSET_GONE_MARGIN);
writeDimension("app:baselineMargin", l.baselineMargin, 0);
writeBoolen("app:layout_constrainedWidth", l.constrainedWidth, false);
writeBoolen("app:layout_constrainedHeight",
l.constrainedHeight, false);
writeBoolen("app:barrierAllowsGoneWidgets",
l.mBarrierAllowsGoneWidgets, true);
writeVariable("app:layout_wrapBehaviorInParent", l.mWrapBehavior,
ConstraintWidget.WRAP_BEHAVIOR_INCLUDED);
writeXmlConstraint("app:baselineToBaseline", l.baselineToBaseline);
writeXmlConstraint("app:baselineToBottom", l.baselineToBottom);
writeXmlConstraint("app:baselineToTop", l.baselineToTop);
writeXmlConstraint("app:layout_constraintBottom_toBottomOf", l.bottomToBottom);
writeXmlConstraint("app:layout_constraintBottom_toTopOf", l.bottomToTop);
writeXmlConstraint("app:layout_constraintEnd_toEndOf", l.endToEnd);
writeXmlConstraint("app:layout_constraintEnd_toStartOf", l.endToStart);
writeXmlConstraint("app:layout_constraintLeft_toLeftOf", l.leftToLeft);
writeXmlConstraint("app:layout_constraintLeft_toRightOf", l.leftToRight);
writeXmlConstraint("app:layout_constraintRight_toLeftOf", l.rightToLeft);
writeXmlConstraint("app:layout_constraintRight_toRightOf", l.rightToRight);
writeXmlConstraint("app:layout_constraintStart_toEndOf", l.startToEnd);
writeXmlConstraint("app:layout_constraintStart_toStartOf", l.startToStart);
writeXmlConstraint("app:layout_constraintTop_toBottomOf", l.topToBottom);
writeXmlConstraint("app:layout_constraintTop_toTopOf", l.topToTop);
String[] typesConstraintDefault = {"spread", "wrap", "percent"};
writeEnum("app:layout_constraintHeight_default", l.heightDefault,
typesConstraintDefault, ConstraintWidget.MATCH_CONSTRAINT_SPREAD);
writeVariable("app:layout_constraintHeight_percent", l.heightPercent, 1);
writeDimension("app:layout_constraintHeight_min", l.heightMin, 0);
writeDimension("app:layout_constraintHeight_max", l.heightMax, 0);
writeBoolen("android:layout_constrainedHeight",
l.constrainedHeight, false);
writeEnum("app:layout_constraintWidth_default",
l.widthDefault, typesConstraintDefault,
ConstraintWidget.MATCH_CONSTRAINT_SPREAD);
writeVariable("app:layout_constraintWidth_percent", l.widthPercent, 1);
writeDimension("app:layout_constraintWidth_min", l.widthMin, 0);
writeDimension("app:layout_constraintWidth_max", l.widthMax, 0);
writeBoolen("android:layout_constrainedWidth",
l.constrainedWidth, false);
writeVariable("app:layout_constraintVertical_weight",
l.verticalWeight, UNSET);
writeVariable("app:layout_constraintHorizontal_weight",
l.horizontalWeight, UNSET);
writeVariable("app:layout_constraintHorizontal_chainStyle",
l.horizontalChainStyle);
writeVariable("app:layout_constraintVertical_chainStyle",
l.verticalChainStyle);
String[] barrierDir = {"left", "right", "top", "bottom", "start", "end"};
writeEnum("app:barrierDirection", l.mBarrierDirection, barrierDir, UNSET);
writeVariable("app:layout_constraintTag", l.mConstraintTag, null);
if (l.mReferenceIds != null) {
writeVariable("'ReferenceIds'", l.mReferenceIds);
}
mWriter.write(" />\n");
}
mWriter.write("</ConstraintSet>\n");
}
private static final String SPACE = "\n ";
private void writeBoolen(String dimString, boolean val, boolean def) throws IOException {
if (val != def) {
mWriter.write(SPACE + dimString + "=\"" + val + "dp\"");
}
}
private void writeEnum(String dimString,
int val,
String[] types,
int def) throws IOException {
if (val != def) {
mWriter.write(SPACE + dimString + "=\"" + types[val] + "\"");
}
}
private void writeDimension(String dimString, int dim, int def) throws IOException {
if (dim != def) {
mWriter.write(SPACE + dimString + "=\"" + dim + "dp\"");
}
}
private void writeBaseDimension(String dimString, int dim, int def) throws IOException {
if (dim != def) {
if (dim == -2) {
mWriter.write(SPACE + dimString + "=\"wrap_content\"");
} else if (dim == -1) {
mWriter.write(SPACE + dimString + "=\"match_parent\"");
} else {
mWriter.write(SPACE + dimString + "=\"" + dim + "dp\"");
}
}
}
HashMap<Integer, String> mIdMap = new HashMap<>();
String getName(int id) {
if (mIdMap.containsKey(id)) {
return "@+id/" + mIdMap.get(id) + "";
}
if (id == 0) {
return "parent";
}
String name = lookup(id);
mIdMap.put(id, name);
return "@+id/" + name + "";
}
String lookup(int id) {
try {
if (id != -1) {
return mContext.getResources().getResourceEntryName(id);
} else {
return "unknown" + ++mUnknownCount;
}
} catch (Exception ex) {
return "unknown" + ++mUnknownCount;
}
}
void writeXmlConstraint(String str, int leftToLeft) throws IOException {
if (leftToLeft == UNSET) {
return;
}
mWriter.write(SPACE + str);
mWriter.write("=\"" + getName(leftToLeft) + "\"");
}
void writeConstraint(String my, int leftToLeft,
String other,
int margin,
int goneMargin) throws IOException {
if (leftToLeft == UNSET) {
return;
}
mWriter.write(SPACE + my);
mWriter.write(":[");
mWriter.write(getName(leftToLeft));
mWriter.write(" , ");
mWriter.write(other);
if (margin != 0) {
mWriter.write(" , " + margin);
}
mWriter.write("],\n");
}
void writeCircle(int circleConstraint,
float circleAngle,
int circleRadius) throws IOException {
if (circleConstraint == UNSET) {
return;
}
mWriter.write("circle");
mWriter.write(":[");
mWriter.write(getName(circleConstraint));
mWriter.write(", " + circleAngle);
mWriter.write(circleRadius + "]");
}
void writeVariable(String name, int value) throws IOException {
if (value == 0 || value == -1) {
return;
}
mWriter.write(SPACE + name + "=\"" + value + "\"\n");
}
void writeVariable(String name, float value, float def) throws IOException {
if (value == def) {
return;
}
mWriter.write(SPACE + name);
mWriter.write("=\"" + value + "\"");
}
void writeVariable(String name, String value, String def) throws IOException {
if (value == null || value.equals(def)) {
return;
}
mWriter.write(SPACE + name);
mWriter.write("=\"" + value + "\"");
}
void writeVariable(String name, int[] value) throws IOException {
if (value == null) {
return;
}
mWriter.write(SPACE + name);
mWriter.write(":");
for (int i = 0; i < value.length; i++) {
mWriter.write(((i == 0) ? "[" : ", ") + getName(value[i]));
}
mWriter.write("],\n");
}
void writeVariable(String name, String value) throws IOException {
if (value == null) {
return;
}
mWriter.write(name);
mWriter.write(":");
mWriter.write(", " + value);
mWriter.write("\n");
}
}
// ================================== JSON ===============================================
class WriteJsonEngine {
Writer mWriter;
ConstraintLayout mLayout;
Context mContext;
int mFlags;
int mUnknownCount = 0;
final String mLEFT = "'left'";
final String mRIGHT = "'right'";
final String mBASELINE = "'baseline'";
final String mBOTTOM = "'bottom'";
final String mTOP = "'top'";
final String mSTART = "'start'";
final String mEND = "'end'";
private static final String SPACE = " ";
WriteJsonEngine(Writer writer, ConstraintLayout layout, int flags) throws IOException {
this.mWriter = writer;
this.mLayout = layout;
this.mContext = layout.getContext();
this.mFlags = flags;
}
void writeLayout() throws IOException {
mWriter.write("\n\'ConstraintSet\':{\n");
for (Integer id : mConstraints.keySet()) {
Constraint c = mConstraints.get(id);
String idName = getName(id);
mWriter.write(idName + ":{\n");
Layout l = c.layout;
writeDimension("height", l.mHeight, l.heightDefault, l.heightPercent,
l.heightMin, l.heightMax, l.constrainedHeight);
writeDimension("width", l.mWidth, l.widthDefault, l.widthPercent,
l.widthMin, l.widthMax, l.constrainedWidth);
writeConstraint(mLEFT, l.leftToLeft, mLEFT, l.leftMargin, l.goneLeftMargin);
writeConstraint(mLEFT, l.leftToRight, mRIGHT, l.leftMargin, l.goneLeftMargin);
writeConstraint(mRIGHT, l.rightToLeft, mLEFT, l.rightMargin, l.goneRightMargin);
writeConstraint(mRIGHT, l.rightToRight, mRIGHT, l.rightMargin, l.goneRightMargin);
writeConstraint(mBASELINE, l.baselineToBaseline, mBASELINE, UNSET,
l.goneBaselineMargin);
writeConstraint(mBASELINE, l.baselineToTop, mTOP, UNSET, l.goneBaselineMargin);
writeConstraint(mBASELINE, l.baselineToBottom,
mBOTTOM, UNSET, l.goneBaselineMargin);
writeConstraint(mTOP, l.topToBottom, mBOTTOM, l.topMargin, l.goneTopMargin);
writeConstraint(mTOP, l.topToTop, mTOP, l.topMargin, l.goneTopMargin);
writeConstraint(mBOTTOM, l.bottomToBottom, mBOTTOM, l.bottomMargin,
l.goneBottomMargin);
writeConstraint(mBOTTOM, l.bottomToTop, mTOP, l.bottomMargin, l.goneBottomMargin);
writeConstraint(mSTART, l.startToStart, mSTART, l.startMargin, l.goneStartMargin);
writeConstraint(mSTART, l.startToEnd, mEND, l.startMargin, l.goneStartMargin);
writeConstraint(mEND, l.endToStart, mSTART, l.endMargin, l.goneEndMargin);
writeConstraint(mEND, l.endToEnd, mEND, l.endMargin, l.goneEndMargin);
writeVariable("'horizontalBias'", l.horizontalBias, 0.5f);
writeVariable("'verticalBias'", l.verticalBias, 0.5f);
writeCircle(l.circleConstraint, l.circleAngle, l.circleRadius);
writeGuideline(l.orientation, l.guideBegin, l.guideEnd, l.guidePercent);
writeVariable("'dimensionRatio'", l.dimensionRatio);
writeVariable("'barrierMargin'", l.mBarrierMargin);
writeVariable("'type'", l.mHelperType);
writeVariable("'ReferenceId'", l.mReferenceIdString);
writeVariable("'mBarrierAllowsGoneWidgets'",
l.mBarrierAllowsGoneWidgets, true);
writeVariable("'WrapBehavior'", l.mWrapBehavior);
writeVariable("'verticalWeight'", l.verticalWeight);
writeVariable("'horizontalWeight'", l.horizontalWeight);
writeVariable("'horizontalChainStyle'", l.horizontalChainStyle);
writeVariable("'verticalChainStyle'", l.verticalChainStyle);
writeVariable("'barrierDirection'", l.mBarrierDirection);
if (l.mReferenceIds != null) {
writeVariable("'ReferenceIds'", l.mReferenceIds);
}
mWriter.write("}\n");
}
mWriter.write("}\n");
}
private void writeGuideline(int orientation,
int guideBegin,
int guideEnd,
float guidePercent) throws IOException {
writeVariable("'orientation'", orientation);
writeVariable("'guideBegin'", guideBegin);
writeVariable("'guideEnd'", guideEnd);
writeVariable("'guidePercent'", guidePercent);
}
private void writeDimension(String dimString,
int dim,
int dimDefault,
float dimPercent,
int dimMin,
int dimMax,
boolean unusedConstrainedDim) throws IOException {
if (dim == 0) {
if (dimMax != UNSET || dimMin != UNSET) {
switch (dimDefault) {
case 0: // spread
mWriter.write(SPACE + dimString
+ ": {'spread' ," + dimMin + ", " + dimMax + "}\n");
break;
case 1: // wrap
mWriter.write(SPACE + dimString
+ ": {'wrap' ," + dimMin + ", " + dimMax + "}\n");
return;
case 2: // percent
mWriter.write(SPACE + dimString + ": {'" + dimPercent
+ "'% ," + dimMin + ", " + dimMax + "}\n");
return;
}
return;
}
switch (dimDefault) {
case 0: // spread is the default
break;
case 1: // wrap
mWriter.write(SPACE + dimString + ": '???????????',\n");
return;
case 2: // percent
mWriter.write(SPACE + dimString + ": '" + dimPercent + "%',\n");
return;
}
} else if (dim == -2) {
mWriter.write(SPACE + dimString + ": 'wrap'\n");
} else if (dim == -1) {
mWriter.write(SPACE + dimString + ": 'parent'\n");
} else {
mWriter.write(SPACE + dimString + ": " + dim + ",\n");
}
}
HashMap<Integer, String> mIdMap = new HashMap<>();
String getName(int id) {
if (mIdMap.containsKey(id)) {
return "\'" + mIdMap.get(id) + "\'";
}
if (id == 0) {
return "'parent'";
}
String name = lookup(id);
mIdMap.put(id, name);
return "\'" + name + "\'";
}
String lookup(int id) {
try {
if (id != -1) {
return mContext.getResources().getResourceEntryName(id);
} else {
return "unknown" + ++mUnknownCount;
}
} catch (Exception ex) {
return "unknown" + ++mUnknownCount;
}
}
void writeConstraint(String my,
int leftToLeft,
String other,
int margin,
int goneMargin) throws IOException {
if (leftToLeft == UNSET) {
return;
}
mWriter.write(SPACE + my);
mWriter.write(":[");
mWriter.write(getName(leftToLeft));
mWriter.write(" , ");
mWriter.write(other);
if (margin != 0) {
mWriter.write(" , " + margin);
}
mWriter.write("],\n");
}
void writeCircle(int circleConstraint,
float circleAngle,
int circleRadius) throws IOException {
if (circleConstraint == UNSET) {
return;
}
mWriter.write(SPACE + "circle");
mWriter.write(":[");
mWriter.write(getName(circleConstraint));
mWriter.write(", " + circleAngle);
mWriter.write(circleRadius + "]");
}
void writeVariable(String name, int value) throws IOException {
if (value == 0 || value == -1) {
return;
}
mWriter.write(SPACE + name);
mWriter.write(":");
mWriter.write(", " + value);
mWriter.write("\n");
}
void writeVariable(String name, float value) throws IOException {
if (value == UNSET) {
return;
}
mWriter.write(SPACE + name);
mWriter.write(": " + value);
mWriter.write(",\n");
}
void writeVariable(String name, float value, float def) throws IOException {
if (value == def) {
return;
}
mWriter.write(SPACE + name);
mWriter.write(": " + value);
mWriter.write(",\n");
}
void writeVariable(String name, boolean value) throws IOException {
if (!value) {
return;
}
mWriter.write(SPACE + name);
mWriter.write(": " + value);
mWriter.write(",\n");
}
void writeVariable(String name, boolean value , boolean def) throws IOException {
if (value == def) {
return;
}
mWriter.write(SPACE + name);
mWriter.write(": " + value);
mWriter.write(",\n");
}
void writeVariable(String name, int[] value) throws IOException {
if (value == null) {
return;
}
mWriter.write(SPACE + name);
mWriter.write(": ");
for (int i = 0; i < value.length; i++) {
mWriter.write(((i == 0) ? "[" : ", ") + getName(value[i]));
}
mWriter.write("],\n");
}
void writeVariable(String name, String value) throws IOException {
if (value == null) {
return;
}
mWriter.write(SPACE + name);
mWriter.write(":");
mWriter.write(", " + value);
mWriter.write("\n");
}
}
}