public class

ConstraintAttribute

extends java.lang.Object

 java.lang.Object

↳androidx.constraintlayout.widget.ConstraintAttribute

Gradle dependencies

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

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

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

Androidx artifact mapping:

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

Overview

Defines non standard Attributes

Summary

Constructors
publicConstraintAttribute(ConstraintAttribute source, java.lang.Object value)

publicConstraintAttribute(java.lang.String name, ConstraintAttribute.AttributeType attributeType)

publicConstraintAttribute(java.lang.String name, ConstraintAttribute.AttributeType attributeType, java.lang.Object value, boolean method)

Methods
public voidapplyCustom(View view)

Apply custom attributes to the view

public booleandiff(ConstraintAttribute constraintAttribute)

test if the two attributes are different

public static java.util.HashMap<java.lang.String, ConstraintAttribute>extractAttributes(java.util.HashMap<java.lang.String, ConstraintAttribute> base, View view)

extract attributes from the view

public intgetColorValue()

public floatgetFloatValue()

public intgetIntegerValue()

public java.lang.StringgetName()

public java.lang.StringgetStringValue()

public ConstraintAttribute.AttributeTypegetType()

public voidgetValuesToInterpolate(float[] ret[])

populate the float array with colors it will fill 4 values

public floatgetValueToInterpolate()

Transforms value to a float for the purpose of interpolation

public booleanisBooleanValue()

public booleanisContinuous()

Continuous types are interpolated they are fired only at

public booleanisMethod()

public intnumberOfInterpolatedValues()

The number of interpolation values that need to be interpolated Typically 1 but 3 for colors.

public static voidparse(Context context, XmlPullParser parser, java.util.HashMap<java.lang.String, ConstraintAttribute> custom)

parse Custom attributes and fill Custom

public static voidsetAttributes(View view, java.util.HashMap<java.lang.String, ConstraintAttribute> map)

set attributes from map on to the view

public voidsetColorValue(int value)

public voidsetFloatValue(float value)

public voidsetIntValue(int value)

public voidsetStringValue(java.lang.String value)

public voidsetValue(float[] value[])

setValue based on the values in the array

public voidsetValue(java.lang.Object value)

set the value based on casting the object

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public ConstraintAttribute(java.lang.String name, ConstraintAttribute.AttributeType attributeType)

public ConstraintAttribute(java.lang.String name, ConstraintAttribute.AttributeType attributeType, java.lang.Object value, boolean method)

public ConstraintAttribute(ConstraintAttribute source, java.lang.Object value)

Methods

public java.lang.String getName()

public boolean isMethod()

public int getIntegerValue()

public float getFloatValue()

public java.lang.String getStringValue()

public boolean isBooleanValue()

public int getColorValue()

public boolean isContinuous()

Continuous types are interpolated they are fired only at

Returns:

public void setFloatValue(float value)

public void setColorValue(int value)

public void setIntValue(int value)

public void setStringValue(java.lang.String value)

public int numberOfInterpolatedValues()

The number of interpolation values that need to be interpolated Typically 1 but 3 for colors.

Returns:

Typically 1 but 3 for colors.

public float getValueToInterpolate()

Transforms value to a float for the purpose of interpolation

Returns:

interpolation value

public void getValuesToInterpolate(float[] ret[])

populate the float array with colors it will fill 4 values

Parameters:

ret:

public void setValue(float[] value[])

setValue based on the values in the array

Parameters:

value:

public boolean diff(ConstraintAttribute constraintAttribute)

test if the two attributes are different

Parameters:

constraintAttribute:

Returns:

public void setValue(java.lang.Object value)

set the value based on casting the object

Parameters:

value:

public static java.util.HashMap<java.lang.String, ConstraintAttribute> extractAttributes(java.util.HashMap<java.lang.String, ConstraintAttribute> base, View view)

extract attributes from the view

Parameters:

base:
view:

Returns:

public static void setAttributes(View view, java.util.HashMap<java.lang.String, ConstraintAttribute> map)

set attributes from map on to the view

Parameters:

view:
map:

public void applyCustom(View view)

Apply custom attributes to the view

Parameters:

view:

public static void parse(Context context, XmlPullParser parser, java.util.HashMap<java.lang.String, ConstraintAttribute> custom)

parse Custom attributes and fill Custom

Parameters:

context:
parser:
custom:

Source

/*
 * Copyright (C) 2017 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.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.util.Xml;
import android.view.View;

import org.xmlpull.v1.XmlPullParser;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;

/**
 * Defines non standard Attributes
 *
 * @DoNotShow
 */
public class ConstraintAttribute {
    private static final String TAG = "TransitionLayout";
    private boolean mMethod = false;
    String mName;
    private AttributeType mType;
    private int mIntegerValue;
    private float mFloatValue;
    private String mStringValue;
    boolean mBooleanValue;
    private int mColorValue;

    public enum AttributeType {
        INT_TYPE,
        FLOAT_TYPE,
        COLOR_TYPE,
        COLOR_DRAWABLE_TYPE,
        STRING_TYPE,
        BOOLEAN_TYPE,
        DIMENSION_TYPE,
        REFERENCE_TYPE
    }

    public String getName() {
        return mName;
    }

    public boolean isMethod() {
        return mMethod;
    }

    public int getIntegerValue() {
        return mIntegerValue;
    }

    public float getFloatValue() {
        return mFloatValue;
    }

    public String getStringValue() {
        return mStringValue;
    }

    public boolean isBooleanValue() {
        return mBooleanValue;
    }

    public int getColorValue() {
        return mColorValue;
    }

    public AttributeType getType() {
        return mType;
    }

    /**
     * Continuous types are interpolated they are fired only at
     * @return
     */
    public boolean isContinuous() {
        switch (mType) {
            case REFERENCE_TYPE:
            case BOOLEAN_TYPE:
            case STRING_TYPE:
                return false;
            default:
                return true;
        }
    }

    public void setFloatValue(float value) {
        mFloatValue = value;
    }

    public void setColorValue(int value) {
        mColorValue = value;
    }

    public void setIntValue(int value) {
        mIntegerValue = value;
    }

    public void setStringValue(String value) {
        mStringValue = value;
    }

    /**
     * The number of interpolation values that need to be interpolated
     * Typically 1 but 3 for colors.
     *
     * @return Typically 1 but 3 for colors.
     */
    public int numberOfInterpolatedValues() {
        switch (mType) {
            case COLOR_TYPE:
            case COLOR_DRAWABLE_TYPE:
                return 4;
            default:
                return 1;
        }
    }

    /**
     * Transforms value to a float for the purpose of interpolation
     *
     * @return interpolation value
     */
    public float getValueToInterpolate() {
        switch (mType) {
            case INT_TYPE:
                return mIntegerValue;
            case FLOAT_TYPE:
                return mFloatValue;
            case COLOR_TYPE:
            case COLOR_DRAWABLE_TYPE:
                throw new RuntimeException("Color does not have a single color to interpolate");
            case STRING_TYPE:
                throw new RuntimeException("Cannot interpolate String");
            case BOOLEAN_TYPE:
                return mBooleanValue ? 1 : 0;
            case DIMENSION_TYPE:
                return mFloatValue;
        }
        return Float.NaN;
    }

    /**
     * populate the float array with colors it will fill 4 values
     * @param ret
     */
    public void getValuesToInterpolate(float[] ret) {
        switch (mType) {
            case INT_TYPE:
                ret[0] = mIntegerValue;
                break;
            case FLOAT_TYPE:
                ret[0] = mFloatValue;
                break;
            case COLOR_DRAWABLE_TYPE:
            case COLOR_TYPE:
                int a = 0xFF & (mColorValue >> 24);
                int r = 0xFF & (mColorValue >> 16);
                int g = 0xFF & (mColorValue >> 8);
                int b = 0xFF & (mColorValue);
                float f_r = (float) Math.pow(r / 255.0f, 2.2);
                float f_g = (float) Math.pow(g / 255.0f, 2.2);
                float f_b = (float) Math.pow(b / 255.0f, 2.2);
                ret[0] = f_r;
                ret[1] = f_g;
                ret[2] = f_b;
                ret[3] = a / 255f;
                break;
            case STRING_TYPE:
                throw new RuntimeException("Color does not have a single color to interpolate");
            case BOOLEAN_TYPE:
                ret[0] = mBooleanValue ? 1 : 0;
                break;
            case DIMENSION_TYPE:
                ret[0] = mFloatValue;
                break;
        }
    }

    /**
     * setValue based on the values in the array
     * @param value
     */
    public void setValue(float[] value) {
        switch (mType) {
            case REFERENCE_TYPE:
            case INT_TYPE:
                mIntegerValue = (int) value[0];
                break;
            case FLOAT_TYPE:
                mFloatValue = value[0];
                break;
            case COLOR_DRAWABLE_TYPE:
            case COLOR_TYPE:
                mColorValue = Color.HSVToColor(value);
                mColorValue = (mColorValue & 0xFFFFFF) | (clamp((int) (0xFF * value[3])) << 24);
                break;
            case STRING_TYPE:
                throw new RuntimeException("Color does not have a single color to interpolate");
            case BOOLEAN_TYPE:
                mBooleanValue = value[0] > 0.5;
                break;
            case DIMENSION_TYPE:
                mFloatValue = value[0];

        }
    }

    /**
     * test if the two attributes are different
     *
     * @param constraintAttribute
     * @return
     */
    public boolean diff(ConstraintAttribute constraintAttribute) {
        if (constraintAttribute == null || mType != constraintAttribute.mType) {
            return false;
        }
        switch (mType) {
            case INT_TYPE:
            case REFERENCE_TYPE:
                return mIntegerValue == constraintAttribute.mIntegerValue;
            case FLOAT_TYPE:
                return mFloatValue == constraintAttribute.mFloatValue;
            case COLOR_TYPE:
            case COLOR_DRAWABLE_TYPE:
                return mColorValue == constraintAttribute.mColorValue;
            case STRING_TYPE:
                return mIntegerValue == constraintAttribute.mIntegerValue;
            case BOOLEAN_TYPE:
                return mBooleanValue == constraintAttribute.mBooleanValue;
            case DIMENSION_TYPE:
                return mFloatValue == constraintAttribute.mFloatValue;
        }
        return false;
    }

    public ConstraintAttribute(String name, AttributeType attributeType) {
        mName = name;
        mType = attributeType;
    }

    public ConstraintAttribute(String name,
                               AttributeType attributeType,
                               Object value,
                               boolean method) {
        mName = name;
        mType = attributeType;
        mMethod = method;
        setValue(value);
    }

    public ConstraintAttribute(ConstraintAttribute source, Object value) {
        mName = source.mName;
        mType = source.mType;
        setValue(value);
    }

    /**
     * set the value based on casting the object
     * @param value
     */
    public void setValue(Object value) {
        switch (mType) {
            case REFERENCE_TYPE:
            case INT_TYPE:
                mIntegerValue = (Integer) value;
                break;
            case FLOAT_TYPE:
                mFloatValue = (Float) value;
                break;
            case COLOR_TYPE:
            case COLOR_DRAWABLE_TYPE:
                mColorValue = (Integer) value;
                break;
            case STRING_TYPE:
                mStringValue = (String) value;
                break;
            case BOOLEAN_TYPE:
                mBooleanValue = (Boolean) value;
                break;
            case DIMENSION_TYPE:
                mFloatValue = (Float) value;
                break;
        }
    }

    /**
     * extract attributes from the view
     * @param base
     * @param view
     * @return
     */
    public static HashMap<String, ConstraintAttribute> extractAttributes(
            HashMap<String, ConstraintAttribute> base, View view) {
        HashMap<String, ConstraintAttribute> ret = new HashMap<>();
        Class<? extends View> viewClass = view.getClass();
        for (String name : base.keySet()) {
            ConstraintAttribute constraintAttribute = base.get(name);

            try {
                if (name.equals("BackgroundColor")) { // hack for getMap set background color
                    ColorDrawable viewColor = (ColorDrawable) view.getBackground();
                    Object val = viewColor.getColor();
                    ret.put(name, new ConstraintAttribute(constraintAttribute, val));
                } else {
                    Method method = viewClass.getMethod("getMap" + name);
                    Object val = method.invoke(view);
                    ret.put(name, new ConstraintAttribute(constraintAttribute, val));
                }

            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    /**
     * set attributes from map on to the view
     * @param view
     * @param map
     */
    public static void setAttributes(View view, HashMap<String, ConstraintAttribute> map) {
        Class<? extends View> viewClass = view.getClass();
        for (String name : map.keySet()) {
            ConstraintAttribute constraintAttribute = map.get(name);
            String methodName = name;
            if (!constraintAttribute.mMethod) {
                methodName = "set" + methodName;
            }
            try {
                Method method;
                switch (constraintAttribute.mType) {
                    case INT_TYPE:
                        method = viewClass.getMethod(methodName, Integer.TYPE);
                        method.invoke(view, constraintAttribute.mIntegerValue);
                        break;
                    case FLOAT_TYPE:
                        method = viewClass.getMethod(methodName, Float.TYPE);
                        method.invoke(view, constraintAttribute.mFloatValue);
                        break;
                    case COLOR_DRAWABLE_TYPE:
                        method = viewClass.getMethod(methodName, Drawable.class);
                        ColorDrawable drawable = new ColorDrawable(); // TODO cache
                        drawable.setColor(constraintAttribute.mColorValue);
                        method.invoke(view, drawable);
                        break;
                    case COLOR_TYPE:
                        method = viewClass.getMethod(methodName, Integer.TYPE);
                        method.invoke(view, constraintAttribute.mColorValue);
                        break;
                    case STRING_TYPE:
                        method = viewClass.getMethod(methodName, CharSequence.class);
                        method.invoke(view, constraintAttribute.mStringValue);
                        break;
                    case BOOLEAN_TYPE:
                        method = viewClass.getMethod(methodName, Boolean.TYPE);
                        method.invoke(view, constraintAttribute.mBooleanValue);
                        break;
                    case DIMENSION_TYPE:
                        method = viewClass.getMethod(methodName, Float.TYPE);
                        method.invoke(view, constraintAttribute.mFloatValue);
                        break;
                    case REFERENCE_TYPE:
                        method = viewClass.getMethod(methodName, Integer.TYPE);
                        method.invoke(view, constraintAttribute.mIntegerValue);
                }
            } catch (NoSuchMethodException e) {
                Log.e(TAG, e.getMessage());
                Log.e(TAG, " Custom Attribute \"" + name
                        + "\" not found on " + viewClass.getName());
                Log.e(TAG, viewClass.getName() + " must have a method " + methodName);
            } catch (IllegalAccessException e) {
                Log.e(TAG, " Custom Attribute \"" + name
                        + "\" not found on " + viewClass.getName());
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                Log.e(TAG, " Custom Attribute \"" + name
                        + "\" not found on " + viewClass.getName());
                e.printStackTrace();
            }
        }
    }

    /**
     * Apply custom attributes to the view
     * @param view
     */
    public void applyCustom(View view) {
        Class<? extends View> viewClass = view.getClass();
        String name = this.mName;
        String methodName = name;
        if (!mMethod) {
            methodName = "set" + methodName;
        }
        try {
            Method method;
            switch (this.mType) {
                case INT_TYPE:
                case REFERENCE_TYPE:
                    method = viewClass.getMethod(methodName, Integer.TYPE);
                    method.invoke(view, this.mIntegerValue);
                    break;
                case FLOAT_TYPE:
                    method = viewClass.getMethod(methodName, Float.TYPE);
                    method.invoke(view, this.mFloatValue);
                    break;
                case COLOR_DRAWABLE_TYPE:
                    method = viewClass.getMethod(methodName, Drawable.class);
                    ColorDrawable drawable = new ColorDrawable(); // TODO cache
                    drawable.setColor(this.mColorValue);
                    method.invoke(view, drawable);
                    break;
                case COLOR_TYPE:
                    method = viewClass.getMethod(methodName, Integer.TYPE);
                    method.invoke(view, this.mColorValue);
                    break;
                case STRING_TYPE:
                    method = viewClass.getMethod(methodName, CharSequence.class);
                    method.invoke(view, this.mStringValue);
                    break;
                case BOOLEAN_TYPE:
                    method = viewClass.getMethod(methodName, Boolean.TYPE);
                    method.invoke(view, this.mBooleanValue);
                    break;
                case DIMENSION_TYPE:
                    method = viewClass.getMethod(methodName, Float.TYPE);
                    method.invoke(view, this.mFloatValue);
                    break;
            }
        } catch (NoSuchMethodException e) {
            Log.e(TAG, e.getMessage());
            Log.e(TAG, " Custom Attribute \"" + name + "\" not found on " + viewClass.getName());
            Log.e(TAG, viewClass.getName() + " must have a method " + methodName);
        } catch (IllegalAccessException e) {
            Log.e(TAG, " Custom Attribute \"" + name + "\" not found on " + viewClass.getName());
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            Log.e(TAG, " Custom Attribute \"" + name + "\" not found on " + viewClass.getName());
            e.printStackTrace();
        }

    }

    private static int clamp(int c) {
        int n = 255;
        c &= ~(c >> 31);
        c -= n;
        c &= (c >> 31);
        c += n;
        return c;
    }

    /**
     * parse Custom attributes and fill Custom
     * @param context
     * @param parser
     * @param custom
     */
    public static void parse(Context context,
                             XmlPullParser parser,
                             HashMap<String, ConstraintAttribute> custom) {
        AttributeSet attributeSet = Xml.asAttributeSet(parser);
        TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.CustomAttribute);
        String name = null;
        boolean method = false;
        Object value = null;
        AttributeType type = null;
        final int count = a.getIndexCount();
        for (int i = 0; i < count; i++) {
            int attr = a.getIndex(i);
            if (attr == R.styleable.CustomAttribute_attributeName) {
                name = a.getString(attr);
                if (name != null && name.length() > 0) {
                    name = Character.toUpperCase(name.charAt(0)) + name.substring(1);
                }
            } else if (attr == R.styleable.CustomAttribute_methodName) {
                method = true;
                name = a.getString(attr);
            } else if (attr == R.styleable.CustomAttribute_customBoolean) {
                value = a.getBoolean(attr, false);
                type = AttributeType.BOOLEAN_TYPE;
            } else if (attr == R.styleable.CustomAttribute_customColorValue) {
                type = AttributeType.COLOR_TYPE;
                value = a.getColor(attr, 0);
            } else if (attr == R.styleable.CustomAttribute_customColorDrawableValue) {
                type = AttributeType.COLOR_DRAWABLE_TYPE;
                value = a.getColor(attr, 0);
            } else if (attr == R.styleable.CustomAttribute_customPixelDimension) {
                type = AttributeType.DIMENSION_TYPE;
                value = TypedValue.applyDimension(
                        TypedValue.COMPLEX_UNIT_DIP,
                        a.getDimension(attr, 0),
                        context.getResources().getDisplayMetrics());
            } else if (attr == R.styleable.CustomAttribute_customDimension) {
                type = AttributeType.DIMENSION_TYPE;
                value = a.getDimension(attr, 0);
            } else if (attr == R.styleable.CustomAttribute_customFloatValue) {
                type = AttributeType.FLOAT_TYPE;
                value = a.getFloat(attr, Float.NaN);
            } else if (attr == R.styleable.CustomAttribute_customIntegerValue) {
                type = AttributeType.INT_TYPE;
                value = a.getInteger(attr, -1);
            } else if (attr == R.styleable.CustomAttribute_customStringValue) {
                type = AttributeType.STRING_TYPE;
                value = a.getString(attr);
            } else if (attr == R.styleable.CustomAttribute_customReference) {
                type = AttributeType.REFERENCE_TYPE;
                int tmp = a.getResourceId(attr, -1);
                if (tmp == -1) {
                    tmp = a.getInt(attr, -1);
                }
                value = tmp;
            }
        }
        if (name != null && value != null) {
            custom.put(name, new ConstraintAttribute(name, type, value, method));
        }
        a.recycle();
    }

}