/*
* 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.widgets.ConstraintWidget;
import androidx.constraintlayout.core.widgets.HelperWidget;
import androidx.constraintlayout.core.motion.utils.Easing;
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;
/**
* This class allows you to define programmatically a set of constraints to be used with {@link ConstraintLayout}.
* <p>
* For details about Constraint behaviour see {@link ConstraintLayout}.
* It lets you create and save constraints, and apply them to an existing ConstraintLayout. ConstraintsSet can be created in various ways:
* <ul>
* <li>
* Manually <br> {@code c = new ConstraintSet(); c.connect(....);}
* </li>
* <li>
* from a R.layout.* object <br> {@code c.clone(context, R.layout.layout1);}
* </li>
* <li>
* from a ConstraintLayout <br> {@code c.clone(constraintLayout);}
* </li>
* </ul><p>
* Example code:<br>
* {@sample resources/examples/ExampleConstraintSet.java Example}
*/
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 = "";
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 right to left 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 mapToConstant = new SparseIntArray();
private static SparseIntArray overrideMapToConstant = 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 {
mapToConstant.append(R.styleable.Constraint_layout_constraintLeft_toLeftOf, LEFT_TO_LEFT);
mapToConstant.append(R.styleable.Constraint_layout_constraintLeft_toRightOf, LEFT_TO_RIGHT);
mapToConstant.append(R.styleable.Constraint_layout_constraintRight_toLeftOf, RIGHT_TO_LEFT);
mapToConstant.append(R.styleable.Constraint_layout_constraintRight_toRightOf, RIGHT_TO_RIGHT);
mapToConstant.append(R.styleable.Constraint_layout_constraintTop_toTopOf, TOP_TO_TOP);
mapToConstant.append(R.styleable.Constraint_layout_constraintTop_toBottomOf, TOP_TO_BOTTOM);
mapToConstant.append(R.styleable.Constraint_layout_constraintBottom_toTopOf, BOTTOM_TO_TOP);
mapToConstant.append(R.styleable.Constraint_layout_constraintBottom_toBottomOf, BOTTOM_TO_BOTTOM);
mapToConstant.append(R.styleable.Constraint_layout_constraintBaseline_toBaselineOf, BASELINE_TO_BASELINE);
mapToConstant.append(R.styleable.Constraint_layout_constraintBaseline_toTopOf, BASELINE_TO_TOP);
mapToConstant.append(R.styleable.Constraint_layout_constraintBaseline_toBottomOf, BASELINE_TO_BOTTOM);
mapToConstant.append(R.styleable.Constraint_layout_editor_absoluteX, EDITOR_ABSOLUTE_X);
mapToConstant.append(R.styleable.Constraint_layout_editor_absoluteY, EDITOR_ABSOLUTE_Y);
mapToConstant.append(R.styleable.Constraint_layout_constraintGuide_begin, GUIDE_BEGIN);
mapToConstant.append(R.styleable.Constraint_layout_constraintGuide_end, GUIDE_END);
mapToConstant.append(R.styleable.Constraint_layout_constraintGuide_percent, GUIDE_PERCENT);
mapToConstant.append(R.styleable.Constraint_guidelineUseRtl, GUIDELINE_USE_RTL);
mapToConstant.append(R.styleable.Constraint_android_orientation, ORIENTATION);
mapToConstant.append(R.styleable.Constraint_layout_constraintStart_toEndOf, START_TO_END);
mapToConstant.append(R.styleable.Constraint_layout_constraintStart_toStartOf, START_TO_START);
mapToConstant.append(R.styleable.Constraint_layout_constraintEnd_toStartOf, END_TO_START);
mapToConstant.append(R.styleable.Constraint_layout_constraintEnd_toEndOf, END_TO_END);
mapToConstant.append(R.styleable.Constraint_layout_goneMarginLeft, GONE_LEFT_MARGIN);
mapToConstant.append(R.styleable.Constraint_layout_goneMarginTop, GONE_TOP_MARGIN);
mapToConstant.append(R.styleable.Constraint_layout_goneMarginRight, GONE_RIGHT_MARGIN);
mapToConstant.append(R.styleable.Constraint_layout_goneMarginBottom, GONE_BOTTOM_MARGIN);
mapToConstant.append(R.styleable.Constraint_layout_goneMarginStart, GONE_START_MARGIN);
mapToConstant.append(R.styleable.Constraint_layout_goneMarginEnd, GONE_END_MARGIN);
mapToConstant.append(R.styleable.Constraint_layout_constraintVertical_weight, VERTICAL_WEIGHT);
mapToConstant.append(R.styleable.Constraint_layout_constraintHorizontal_weight, HORIZONTAL_WEIGHT);
mapToConstant.append(R.styleable.Constraint_layout_constraintHorizontal_chainStyle, HORIZONTAL_STYLE);
mapToConstant.append(R.styleable.Constraint_layout_constraintVertical_chainStyle, VERTICAL_STYLE);
mapToConstant.append(R.styleable.Constraint_layout_constraintHorizontal_bias, HORIZONTAL_BIAS);
mapToConstant.append(R.styleable.Constraint_layout_constraintVertical_bias, VERTICAL_BIAS);
mapToConstant.append(R.styleable.Constraint_layout_constraintDimensionRatio, DIMENSION_RATIO);
mapToConstant.append(R.styleable.Constraint_layout_constraintLeft_creator, UNUSED);
mapToConstant.append(R.styleable.Constraint_layout_constraintTop_creator, UNUSED);
mapToConstant.append(R.styleable.Constraint_layout_constraintRight_creator, UNUSED);
mapToConstant.append(R.styleable.Constraint_layout_constraintBottom_creator, UNUSED);
mapToConstant.append(R.styleable.Constraint_layout_constraintBaseline_creator, UNUSED);
mapToConstant.append(R.styleable.Constraint_android_layout_marginLeft, LEFT_MARGIN);
mapToConstant.append(R.styleable.Constraint_android_layout_marginRight, RIGHT_MARGIN);
mapToConstant.append(R.styleable.Constraint_android_layout_marginStart, START_MARGIN);
mapToConstant.append(R.styleable.Constraint_android_layout_marginEnd, END_MARGIN);
mapToConstant.append(R.styleable.Constraint_android_layout_marginTop, TOP_MARGIN);
mapToConstant.append(R.styleable.Constraint_android_layout_marginBottom, BOTTOM_MARGIN);
mapToConstant.append(R.styleable.Constraint_android_layout_width, LAYOUT_WIDTH);
mapToConstant.append(R.styleable.Constraint_android_layout_height, LAYOUT_HEIGHT);
mapToConstant.append(R.styleable.Constraint_layout_constraintWidth, LAYOUT_CONSTRAINT_WIDTH);
mapToConstant.append(R.styleable.Constraint_layout_constraintHeight, LAYOUT_CONSTRAINT_HEIGHT);
mapToConstant.append(R.styleable.Constraint_android_visibility, LAYOUT_VISIBILITY);
mapToConstant.append(R.styleable.Constraint_android_alpha, ALPHA);
mapToConstant.append(R.styleable.Constraint_android_elevation, ELEVATION);
mapToConstant.append(R.styleable.Constraint_android_rotationX, ROTATION_X);
mapToConstant.append(R.styleable.Constraint_android_rotationY, ROTATION_Y);
mapToConstant.append(R.styleable.Constraint_android_rotation, ROTATION);
mapToConstant.append(R.styleable.Constraint_android_scaleX, SCALE_X);
mapToConstant.append(R.styleable.Constraint_android_scaleY, SCALE_Y);
mapToConstant.append(R.styleable.Constraint_android_transformPivotX, TRANSFORM_PIVOT_X);
mapToConstant.append(R.styleable.Constraint_android_transformPivotY, TRANSFORM_PIVOT_Y);
mapToConstant.append(R.styleable.Constraint_android_translationX, TRANSLATION_X);
mapToConstant.append(R.styleable.Constraint_android_translationY, TRANSLATION_Y);
mapToConstant.append(R.styleable.Constraint_android_translationZ, TRANSLATION_Z);
mapToConstant.append(R.styleable.Constraint_layout_constraintWidth_default, WIDTH_DEFAULT);
mapToConstant.append(R.styleable.Constraint_layout_constraintHeight_default, HEIGHT_DEFAULT);
mapToConstant.append(R.styleable.Constraint_layout_constraintWidth_max, WIDTH_MAX);
mapToConstant.append(R.styleable.Constraint_layout_constraintHeight_max, HEIGHT_MAX);
mapToConstant.append(R.styleable.Constraint_layout_constraintWidth_min, WIDTH_MIN);
mapToConstant.append(R.styleable.Constraint_layout_constraintHeight_min, HEIGHT_MIN);
mapToConstant.append(R.styleable.Constraint_layout_constraintCircle, CIRCLE);
mapToConstant.append(R.styleable.Constraint_layout_constraintCircleRadius, CIRCLE_RADIUS);
mapToConstant.append(R.styleable.Constraint_layout_constraintCircleAngle, CIRCLE_ANGLE);
mapToConstant.append(R.styleable.Constraint_animateRelativeTo, ANIMATE_RELATIVE_TO);
mapToConstant.append(R.styleable.Constraint_transitionEasing, TRANSITION_EASING);
mapToConstant.append(R.styleable.Constraint_drawPath, DRAW_PATH);
mapToConstant.append(R.styleable.Constraint_transitionPathRotate, TRANSITION_PATH_ROTATE);
mapToConstant.append(R.styleable.Constraint_motionStagger, MOTION_STAGGER);
mapToConstant.append(R.styleable.Constraint_android_id, VIEW_ID);
mapToConstant.append(R.styleable.Constraint_motionProgress, PROGRESS);
mapToConstant.append(R.styleable.Constraint_layout_constraintWidth_percent, WIDTH_PERCENT);
mapToConstant.append(R.styleable.Constraint_layout_constraintHeight_percent, HEIGHT_PERCENT);
mapToConstant.append(R.styleable.Constraint_layout_wrapBehaviorInParent, LAYOUT_WRAP_BEHAVIOR);
mapToConstant.append(R.styleable.Constraint_chainUseRtl, CHAIN_USE_RTL);
mapToConstant.append(R.styleable.Constraint_barrierDirection, BARRIER_DIRECTION);
mapToConstant.append(R.styleable.Constraint_barrierMargin, BARRIER_MARGIN);
mapToConstant.append(R.styleable.Constraint_constraint_referenced_ids, CONSTRAINT_REFERENCED_IDS);
mapToConstant.append(R.styleable.Constraint_barrierAllowsGoneWidgets, BARRIER_ALLOWS_GONE_WIDGETS);
mapToConstant.append(R.styleable.Constraint_pathMotionArc, PATH_MOTION_ARC);
mapToConstant.append(R.styleable.Constraint_layout_constraintTag, CONSTRAINT_TAG);
mapToConstant.append(R.styleable.Constraint_visibilityMode, VISIBILITY_MODE);
mapToConstant.append(R.styleable.Constraint_layout_constrainedWidth, CONSTRAINED_WIDTH);
mapToConstant.append(R.styleable.Constraint_layout_constrainedHeight, CONSTRAINED_HEIGHT);
mapToConstant.append(R.styleable.Constraint_polarRelativeTo, ANIMATE_CIRCLE_ANGLE_TO);
mapToConstant.append(R.styleable.Constraint_transformPivotTarget, TRANSFORM_PIVOT_TARGET);
mapToConstant.append(R.styleable.Constraint_quantizeMotionSteps, QUANTIZE_MOTION_STEPS);
mapToConstant.append(R.styleable.Constraint_quantizeMotionPhase, QUANTIZE_MOTION_PHASE);
mapToConstant.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);
*/
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_editor_absoluteY, EDITOR_ABSOLUTE_X);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_editor_absoluteY, EDITOR_ABSOLUTE_Y);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_orientation, ORIENTATION);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_goneMarginLeft, GONE_LEFT_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_goneMarginTop, GONE_TOP_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_goneMarginRight, GONE_RIGHT_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_goneMarginBottom, GONE_BOTTOM_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_goneMarginStart, GONE_START_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_goneMarginEnd, GONE_END_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintVertical_weight, VERTICAL_WEIGHT);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHorizontal_weight, HORIZONTAL_WEIGHT);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHorizontal_chainStyle, HORIZONTAL_STYLE);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintVertical_chainStyle, VERTICAL_STYLE);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHorizontal_bias, HORIZONTAL_BIAS);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintVertical_bias, VERTICAL_BIAS);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintDimensionRatio, DIMENSION_RATIO);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintLeft_creator, UNUSED);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintTop_creator, UNUSED);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintRight_creator, UNUSED);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintBottom_creator, UNUSED);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintBaseline_creator, UNUSED);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginLeft, LEFT_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginRight, RIGHT_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginStart, START_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginEnd, END_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginTop, TOP_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginBottom, BOTTOM_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_width, LAYOUT_WIDTH);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_height, LAYOUT_HEIGHT);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth, LAYOUT_CONSTRAINT_WIDTH);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight, LAYOUT_CONSTRAINT_HEIGHT);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_visibility, LAYOUT_VISIBILITY);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_alpha, ALPHA);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_elevation, ELEVATION);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_rotationX, ROTATION_X);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_rotationY, ROTATION_Y);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_rotation, ROTATION);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_scaleX, SCALE_X);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_scaleY, SCALE_Y);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_transformPivotX, TRANSFORM_PIVOT_X);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_transformPivotY, TRANSFORM_PIVOT_Y);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_translationX, TRANSLATION_X);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_translationY, TRANSLATION_Y);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_translationZ, TRANSLATION_Z);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_default, WIDTH_DEFAULT);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight_default, HEIGHT_DEFAULT);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_max, WIDTH_MAX);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight_max, HEIGHT_MAX);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_min, WIDTH_MIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight_min, HEIGHT_MIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintCircleRadius, CIRCLE_RADIUS);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintCircleAngle, CIRCLE_ANGLE);
overrideMapToConstant.append(R.styleable.ConstraintOverride_animateRelativeTo, ANIMATE_RELATIVE_TO);
overrideMapToConstant.append(R.styleable.ConstraintOverride_transitionEasing, TRANSITION_EASING);
overrideMapToConstant.append(R.styleable.ConstraintOverride_drawPath, DRAW_PATH);
overrideMapToConstant.append(R.styleable.ConstraintOverride_transitionPathRotate, TRANSITION_PATH_ROTATE);
overrideMapToConstant.append(R.styleable.ConstraintOverride_motionStagger, MOTION_STAGGER);
overrideMapToConstant.append(R.styleable.ConstraintOverride_android_id, VIEW_ID);
overrideMapToConstant.append(R.styleable.ConstraintOverride_motionTarget, MOTION_TARGET);
overrideMapToConstant.append(R.styleable.ConstraintOverride_motionProgress, PROGRESS);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_percent, WIDTH_PERCENT);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight_percent, HEIGHT_PERCENT);
overrideMapToConstant.append(R.styleable.ConstraintOverride_chainUseRtl, CHAIN_USE_RTL);
overrideMapToConstant.append(R.styleable.ConstraintOverride_barrierDirection, BARRIER_DIRECTION);
overrideMapToConstant.append(R.styleable.ConstraintOverride_barrierMargin, BARRIER_MARGIN);
overrideMapToConstant.append(R.styleable.ConstraintOverride_constraint_referenced_ids, CONSTRAINT_REFERENCED_IDS);
overrideMapToConstant.append(R.styleable.ConstraintOverride_barrierAllowsGoneWidgets, BARRIER_ALLOWS_GONE_WIDGETS);
overrideMapToConstant.append(R.styleable.ConstraintOverride_pathMotionArc, PATH_MOTION_ARC);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintTag, CONSTRAINT_TAG);
overrideMapToConstant.append(R.styleable.ConstraintOverride_visibilityMode, VISIBILITY_MODE);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constrainedWidth, CONSTRAINED_WIDTH);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constrainedHeight, CONSTRAINED_HEIGHT);
overrideMapToConstant.append(R.styleable.ConstraintOverride_polarRelativeTo, ANIMATE_CIRCLE_ANGLE_TO);
overrideMapToConstant.append(R.styleable.ConstraintOverride_transformPivotTarget, TRANSFORM_PIVOT_TARGET);
overrideMapToConstant.append(R.styleable.ConstraintOverride_quantizeMotionSteps, QUANTIZE_MOTION_STEPS);
overrideMapToConstant.append(R.styleable.ConstraintOverride_quantizeMotionPhase, QUANTIZE_MOTION_PHASE);
overrideMapToConstant.append(R.styleable.ConstraintOverride_quantizeMotionInterpolator, QUANTIZE_MOTION_INTERPOLATOR);
overrideMapToConstant.append(R.styleable.ConstraintOverride_layout_wrapBehaviorInParent, LAYOUT_WRAP_BEHAVIOR);
}
public HashMap<String, ConstraintAttribute> getCustomAttributeSet() {
return mSavedAttributes;
}
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 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
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();
}
}
}
}
}
}
public void applyDeltaFrom(ConstraintSet cs) {
for (Constraint from : cs.mConstraints.values()) {
if (from.mDelta != null) {
if (from.mTargetString != null) {
int count = 0;
for (int key : mConstraints.keySet()) {
Constraint potential = getConstraint(key);
if (potential.layout.mConstraintTag != null) {
if (from.mTargetString.matches(potential.layout.mConstraintTag)) {
from.mDelta.applyDelta(potential);
potential.mCustomConstraints.putAll((HashMap)from.mCustomConstraints.clone());
}
}
}
} else {
Constraint constraint = getConstraint(from.mViewId);
from.mDelta.applyDelta(constraint);
}
}
}
}
/**
* 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.dimensionRatioValue = dimensionRatioValue;
params.dimensionRatioSide = 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
}
}
}
}
}
/**
* @suppress
*/
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;
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 mapToConstant = 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 {
mapToConstant.append(R.styleable.Layout_layout_constraintLeft_toLeftOf, LEFT_TO_LEFT);
mapToConstant.append(R.styleable.Layout_layout_constraintLeft_toRightOf, LEFT_TO_RIGHT);
mapToConstant.append(R.styleable.Layout_layout_constraintRight_toLeftOf, RIGHT_TO_LEFT);
mapToConstant.append(R.styleable.Layout_layout_constraintRight_toRightOf, RIGHT_TO_RIGHT);
mapToConstant.append(R.styleable.Layout_layout_constraintTop_toTopOf, TOP_TO_TOP);
mapToConstant.append(R.styleable.Layout_layout_constraintTop_toBottomOf, TOP_TO_BOTTOM);
mapToConstant.append(R.styleable.Layout_layout_constraintBottom_toTopOf, BOTTOM_TO_TOP);
mapToConstant.append(R.styleable.Layout_layout_constraintBottom_toBottomOf, BOTTOM_TO_BOTTOM);
mapToConstant.append(R.styleable.Layout_layout_constraintBaseline_toBaselineOf, BASELINE_TO_BASELINE);
mapToConstant.append(R.styleable.Layout_layout_editor_absoluteX, EDITOR_ABSOLUTE_X);
mapToConstant.append(R.styleable.Layout_layout_editor_absoluteY, EDITOR_ABSOLUTE_Y);
mapToConstant.append(R.styleable.Layout_layout_constraintGuide_begin, GUIDE_BEGIN);
mapToConstant.append(R.styleable.Layout_layout_constraintGuide_end, GUIDE_END);
mapToConstant.append(R.styleable.Layout_layout_constraintGuide_percent, GUIDE_PERCENT);
mapToConstant.append(R.styleable.Layout_guidelineUseRtl, GUIDE_USE_RTL);
mapToConstant.append(R.styleable.Layout_android_orientation, ORIENTATION);
mapToConstant.append(R.styleable.Layout_layout_constraintStart_toEndOf, START_TO_END);
mapToConstant.append(R.styleable.Layout_layout_constraintStart_toStartOf, START_TO_START);
mapToConstant.append(R.styleable.Layout_layout_constraintEnd_toStartOf, END_TO_START);
mapToConstant.append(R.styleable.Layout_layout_constraintEnd_toEndOf, END_TO_END);
mapToConstant.append(R.styleable.Layout_layout_goneMarginLeft, GONE_LEFT_MARGIN);
mapToConstant.append(R.styleable.Layout_layout_goneMarginTop, GONE_TOP_MARGIN);
mapToConstant.append(R.styleable.Layout_layout_goneMarginRight, GONE_RIGHT_MARGIN);
mapToConstant.append(R.styleable.Layout_layout_goneMarginBottom, GONE_BOTTOM_MARGIN);
mapToConstant.append(R.styleable.Layout_layout_goneMarginStart, GONE_START_MARGIN);
mapToConstant.append(R.styleable.Layout_layout_goneMarginEnd, GONE_END_MARGIN);
mapToConstant.append(R.styleable.Layout_layout_constraintVertical_weight, VERTICAL_WEIGHT);
mapToConstant.append(R.styleable.Layout_layout_constraintHorizontal_weight, HORIZONTAL_WEIGHT);
mapToConstant.append(R.styleable.Layout_layout_constraintHorizontal_chainStyle, HORIZONTAL_STYLE);
mapToConstant.append(R.styleable.Layout_layout_constraintVertical_chainStyle, VERTICAL_STYLE);
mapToConstant.append(R.styleable.Layout_layout_constraintHorizontal_bias, HORIZONTAL_BIAS);
mapToConstant.append(R.styleable.Layout_layout_constraintVertical_bias, VERTICAL_BIAS);
mapToConstant.append(R.styleable.Layout_layout_constraintDimensionRatio, DIMENSION_RATIO);
mapToConstant.append(R.styleable.Layout_layout_constraintLeft_creator, UNUSED);
mapToConstant.append(R.styleable.Layout_layout_constraintTop_creator, UNUSED);
mapToConstant.append(R.styleable.Layout_layout_constraintRight_creator, UNUSED);
mapToConstant.append(R.styleable.Layout_layout_constraintBottom_creator, UNUSED);
mapToConstant.append(R.styleable.Layout_layout_constraintBaseline_creator, UNUSED);
mapToConstant.append(R.styleable.Layout_android_layout_marginLeft, LEFT_MARGIN);
mapToConstant.append(R.styleable.Layout_android_layout_marginRight, RIGHT_MARGIN);
mapToConstant.append(R.styleable.Layout_android_layout_marginStart, START_MARGIN);
mapToConstant.append(R.styleable.Layout_android_layout_marginEnd, END_MARGIN);
mapToConstant.append(R.styleable.Layout_android_layout_marginTop, TOP_MARGIN);
mapToConstant.append(R.styleable.Layout_android_layout_marginBottom, BOTTOM_MARGIN);
mapToConstant.append(R.styleable.Layout_android_layout_width, LAYOUT_WIDTH);
mapToConstant.append(R.styleable.Layout_android_layout_height, LAYOUT_HEIGHT);
mapToConstant.append(R.styleable.Layout_layout_constraintWidth, LAYOUT_CONSTRAINT_WIDTH);
mapToConstant.append(R.styleable.Layout_layout_constraintHeight, LAYOUT_CONSTRAINT_HEIGHT);
mapToConstant.append(R.styleable.Layout_layout_constrainedWidth, LAYOUT_CONSTRAINT_WIDTH);
mapToConstant.append(R.styleable.Layout_layout_constrainedHeight, LAYOUT_CONSTRAINT_HEIGHT);
mapToConstant.append(R.styleable.Layout_layout_wrapBehaviorInParent, LAYOUT_WRAP_BEHAVIOR);
mapToConstant.append(R.styleable.Layout_layout_constraintCircle, CIRCLE);
mapToConstant.append(R.styleable.Layout_layout_constraintCircleRadius, CIRCLE_RADIUS);
mapToConstant.append(R.styleable.Layout_layout_constraintCircleAngle, CIRCLE_ANGLE);
mapToConstant.append(R.styleable.Layout_layout_constraintWidth_percent, WIDTH_PERCENT);
mapToConstant.append(R.styleable.Layout_layout_constraintHeight_percent, HEIGHT_PERCENT);
mapToConstant.append(R.styleable.Layout_chainUseRtl, CHAIN_USE_RTL);
mapToConstant.append(R.styleable.Layout_barrierDirection, BARRIER_DIRECTION);
mapToConstant.append(R.styleable.Layout_barrierMargin, BARRIER_MARGIN);
mapToConstant.append(R.styleable.Layout_constraint_referenced_ids, CONSTRAINT_REFERENCED_IDS);
mapToConstant.append(R.styleable.Layout_barrierAllowsGoneWidgets, BARRIER_ALLOWS_GONE_WIDGETS);
}
void fillFromAttributeList(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Layout);
mApply = true;
final int N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
switch (mapToConstant.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:
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
startMargin = a.getDimensionPixelSize(attr, startMargin);
}
break;
case END_MARGIN:
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
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) + " " + mapToConstant.get(attr));
break;
default:
Log.w(TAG,
"Unknown attribute 0x" + Integer.toHexString(attr) + " " + mapToConstant.get(attr));
}
}
a.recycle();
}
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) {
e.printStackTrace();
}
}
}
}
/**
* @suppress
*/
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;
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 mapToConstant = 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 {
mapToConstant.append(R.styleable.Transform_android_rotation, ROTATION);
mapToConstant.append(R.styleable.Transform_android_rotationX, ROTATION_X);
mapToConstant.append(R.styleable.Transform_android_rotationY, ROTATION_Y);
mapToConstant.append(R.styleable.Transform_android_scaleX, SCALE_X);
mapToConstant.append(R.styleable.Transform_android_scaleY, SCALE_Y);
mapToConstant.append(R.styleable.Transform_android_transformPivotX, TRANSFORM_PIVOT_X);
mapToConstant.append(R.styleable.Transform_android_transformPivotY, TRANSFORM_PIVOT_Y);
mapToConstant.append(R.styleable.Transform_android_translationX, TRANSLATION_X);
mapToConstant.append(R.styleable.Transform_android_translationY, TRANSLATION_Y);
mapToConstant.append(R.styleable.Transform_android_translationZ, TRANSLATION_Z);
mapToConstant.append(R.styleable.Transform_android_elevation, ELEVATION);
mapToConstant.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 N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
switch (mapToConstant.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();
}
}
/**
* @suppress
*/
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;
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 N = a.getIndexCount();
for (int i = 0; i < N; 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();
}
}
/**
* @suppress
*/
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;
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 mapToConstant = 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 {
mapToConstant.append(R.styleable.Motion_motionPathRotate, TRANSITION_PATH_ROTATE);
mapToConstant.append(R.styleable.Motion_pathMotionArc, PATH_MOTION_ARC);
mapToConstant.append(R.styleable.Motion_transitionEasing, TRANSITION_EASING);
mapToConstant.append(R.styleable.Motion_drawPath, MOTION_DRAW_PATH);
mapToConstant.append(R.styleable.Motion_animateRelativeTo, ANIMATE_RELATIVE_TO);
mapToConstant.append(R.styleable.Motion_animateCircleAngleTo, ANIMATE_CIRCLE_ANGLE_TO);
mapToConstant.append(R.styleable.Motion_motionStagger, MOTION_STAGGER);
mapToConstant.append(R.styleable.Motion_quantizeMotionSteps, QUANTIZE_MOTION_STEPS);
mapToConstant.append(R.styleable.Motion_quantizeMotionPhase, QUANTIZE_MOTION_PHASE);
mapToConstant.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 N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
switch (mapToConstant.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();
}
}
/**
* @suppress
*/
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]);
}
}
}
public void applyDelta(Constraint c) {
if (mDelta != null) {
mDelta.applyDelta(c);
}
}
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);
}
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;
int currentApiVersion = android.os.Build.VERSION.SDK_INT;
if (currentApiVersion >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
layout.endMargin = param.getMarginEnd();
layout.startMargin = param.getMarginStart();
}
}
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;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
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();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
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);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
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++) {
int chainId = chainIds[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++) {
int chainId = chainIds[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;
}
}
/**
* @suppress
*/
public void setEditorAbsoluteX(int viewId, int position) {
get(viewId).layout.editorAbsoluteX = position;
}
/**
* @suppress
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 1.1
*/
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
* @since 2.0
*/
public void setReferencedIds(int id, int... referenced) {
Constraint constraint = get(id);
constraint.layout.mReferenceIds = referenced;
}
public void setBarrierType(int id, int type) {
Constraint constraint = get(id);
constraint.layout.mHelperType = type;
}
public void removeAttribute(String attributeName) {
mSavedAttributes.remove(attributeName);
}
public void setIntValue(int viewId, String attributeName, int value) {
get(viewId).setIntValue(attributeName, value);
}
public void setColorValue(int viewId, String attributeName, int value) {
get(viewId).setColorValue(attributeName, value);
}
public void setFloatValue(int viewId, String attributeName, float value) {
get(viewId).setFloatValue(attributeName, 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);
}
}
}
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]));
}
}
}
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]));
}
}
}
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]));
}
}
}
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()]);
}
public void addIntAttributes(String... attributeName) {
addAttributes(AttributeType.INT_TYPE, attributeName);
}
public void addColorAttributes(String... attributeName) {
addAttributes(AttributeType.COLOR_TYPE, attributeName);
}
public void addFloatAttributes(String... attributeName) {
addAttributes(AttributeType.FLOAT_TYPE, 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);
String document = null;
String tagName = null;
try {
for (int eventType = parser.getEventType();
eventType != XmlResourceParser.END_DOCUMENT;
eventType = parser.next()) {
switch (eventType) {
case XmlResourceParser.START_DOCUMENT:
document = parser.getName();
break;
case XmlResourceParser.START_TAG:
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;
case XmlResourceParser.END_TAG:
tagName = null;
break;
case XmlResourceParser.TEXT:
break;
}
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 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() + " view .... 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) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
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(context, 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(context, c, a);
a.recycle();
return c;
}
private static void populateOverride(Context ctx, Constraint c, TypedArray a) {
final int N = 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 < N; i++) {
int attr = a.getIndex(i);
int attrType = overrideMapToConstant.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:
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
delta.add(START_MARGIN, a.getDimensionPixelSize(attr, c.layout.startMargin));
}
break;
case END_MARGIN:
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
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) + " " + mapToConstant.get(attr));
break;
default:
Log.w(TAG,
"Unknown attribute 0x" + Integer.toHexString(attr) + " " + mapToConstant.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(Context ctx, Constraint c, TypedArray a, boolean override) {
if (override) {
populateOverride(ctx, c, a);
return;
}
final int N = a.getIndexCount();
for (int i = 0; i < N; 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 (mapToConstant.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:
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
c.layout.startMargin = a.getDimensionPixelSize(attr, c.layout.startMargin);
}
break;
case END_MARGIN:
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
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) + " " + mapToConstant.get(attr));
break;
default:
Log.w(TAG,
"Unknown attribute 0x" + Integer.toHexString(attr) + " " + mapToConstant.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;
}
/**
* @suppress
*/
public Constraint getConstraint(int id) {
if (mConstraints.containsKey(id)) {
return mConstraints.get(id);
}
return null;
}
/**
* @suppress
*/
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;
}
/**
* 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) {
e.printStackTrace();
}
}
}
return "UNKNOWN";
}
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 writer;
ConstraintLayout layout;
Context context;
int flags;
int unknownCount = 0;
final String LEFT = "'left'";
final String RIGHT = "'right'";
final String BASELINE = "'baseline'";
final String BOTTOM = "'bottom'";
final String TOP = "'top'";
final String START = "'start'";
final String END = "'end'";
WriteXmlEngine(Writer writer, ConstraintLayout layout, int flags) throws IOException {
this.writer = writer;
this.layout = layout;
this.context = layout.getContext();
this.flags = flags;
}
void writeLayout() throws IOException {
writer.write("\n<ConstraintSet>\n");
for (Integer id : mConstraints.keySet()) {
Constraint c = mConstraints.get(id);
String idName = getName(id);
writer.write(" <Constraint");
writer.write(SPACE + "android:id" + "=\"" + idName + "\"");
Layout l = c.layout;
writeBaseDimension("android:layout_width", l.mWidth, -5); // nodefault
writeBaseDimension("android:layout_height", l.mHeight, -5);// nodefault
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);
}
writer.write(" />\n");
}
writer.write("</ConstraintSet>\n");
}
private static final String SPACE = "\n ";
private void writeBoolen(String dimString, boolean val, boolean def) throws IOException {
if (val != def)
writer.write(SPACE + dimString + "=\"" + val + "dp\"");
}
private void writeEnum(String dimString, int val, String[] types, int def) throws IOException {
if (val != def)
writer.write(SPACE + dimString + "=\"" + types[val] + "\"");
}
private void writeDimension(String dimString, int dim, int def) throws IOException {
if (dim != def)
writer.write(SPACE + dimString + "=\"" + dim + "dp\"");
}
private void writeBaseDimension(String dimString, int dim, int def) throws IOException {
if (dim != def) {
if (dim == -2) {
writer.write(SPACE + dimString + "=\"wrap_content\"");
} else if (dim == -1) {
writer.write(SPACE + dimString + "=\"match_parent\"");
} else {
writer.write(SPACE + dimString + "=\"" + dim + "dp\"");
}
}
}
HashMap<Integer, String> idMap = new HashMap<>();
String getName(int id) {
if (idMap.containsKey(id)) {
return "@+id/" + idMap.get(id) + "";
}
if (id == 0) {
return "parent";
}
String name = lookup(id);
idMap.put(id, name);
return "@+id/" + name + "";
}
String lookup(int id) {
try {
if (id != -1) {
return context.getResources().getResourceEntryName(id);
} else {
return "unknown" + (++unknownCount);
}
} catch (Exception ex) {
return "unknown" + (++unknownCount);
}
}
void writeXmlConstraint(String str, int leftToLeft) throws IOException {
if (leftToLeft == UNSET) {
return;
}
writer.write(SPACE + str);
writer.write("=\"" + getName(leftToLeft) + "\"");
}
void writeConstraint(String my, int leftToLeft, String other, int margin, int goneMargin) throws IOException {
if (leftToLeft == UNSET) {
return;
}
writer.write(SPACE + my);
writer.write(":[");
writer.write(getName(leftToLeft));
writer.write(" , ");
writer.write(other);
if (margin != 0) {
writer.write(" , " + margin);
}
writer.write("],\n");
}
void writeCircle(int circleConstraint, float circleAngle, int circleRadius) throws IOException {
if (circleConstraint == UNSET) {
return;
}
writer.write("circle");
writer.write(":[");
writer.write(getName(circleConstraint));
writer.write(", " + circleAngle);
writer.write(circleRadius + "]");
}
void writeVariable(String name, int value) throws IOException {
if (value == 0 || value == -1) {
return;
}
writer.write(SPACE + name + "=\"" + value + "\"\n");
}
void writeVariable(String name, float value, float def) throws IOException {
if (value == def) {
return;
}
writer.write(SPACE + name);
writer.write("=\"" + value + "\"");
}
void writeVariable(String name, String value, String def) throws IOException {
if (value == null || value.equals(def)) {
return;
}
writer.write(SPACE + name);
writer.write("=\"" + value + "\"");
}
void writeVariable(String name, int[] value) throws IOException {
if (value == null) {
return;
}
writer.write(SPACE + name);
writer.write(":");
for (int i = 0; i < value.length; i++) {
writer.write(((i == 0) ? "[" : ", ") + getName(value[i]));
}
writer.write("],\n");
}
void writeVariable(String name, String value) throws IOException {
if (value == null) {
return;
}
writer.write(name);
writer.write(":");
writer.write(", " + value);
writer.write("\n");
}
}
// ================================== JSON ===============================================
class WriteJsonEngine {
Writer writer;
ConstraintLayout layout;
Context context;
int flags;
int unknownCount = 0;
final String LEFT = "'left'";
final String RIGHT = "'right'";
final String BASELINE = "'baseline'";
final String BOTTOM = "'bottom'";
final String TOP = "'top'";
final String START = "'start'";
final String END = "'end'";
private static final String SPACE = " ";
WriteJsonEngine(Writer writer, ConstraintLayout layout, int flags) throws IOException {
this.writer = writer;
this.layout = layout;
this.context = layout.getContext();
this.flags = flags;
}
void writeLayout() throws IOException {
writer.write("\n