下面列出了android.util.TypedValue#TYPE_NULL 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Retrieves the styled string value for the attribute at <var>index</var>.
* <p>
* If the attribute is not a string, this method will attempt to coerce
* it to a string.
*
* @param index Index of attribute to retrieve.
*
* @return CharSequence holding string data. May be styled. Returns
* {@code null} if the attribute is not defined or could not be
* coerced to a string.
* @throws RuntimeException if the TypedArray has already been recycled.
*/
public CharSequence getText(@StyleableRes int index) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return null;
} else if (type == TypedValue.TYPE_STRING) {
return loadStringValueAt(index);
}
final TypedValue v = mValue;
if (getValueAt(index, v)) {
return v.coerceToString();
}
// We already checked for TYPE_NULL. This should never happen.
throw new RuntimeException("getText of bad type: 0x" + Integer.toHexString(type));
}
/**
* Retrieve the boolean value for the attribute at <var>index</var>.
* <p>
* If the attribute is an integer value, this method will return whether
* it is equal to zero. If the attribute is not a boolean or integer value,
* this method will attempt to coerce it to an integer using
* {@link Integer#decode(String)} and return whether it is equal to zero.
*
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* cannot be coerced to an integer.
*
* @return Boolean value of the attribute, or defValue if the attribute was
* not defined or could not be coerced to an integer.
* @throws RuntimeException if the TypedArray has already been recycled.
*/
public boolean getBoolean(@StyleableRes int index, boolean defValue) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
return data[index + STYLE_DATA] != 0;
}
final TypedValue v = mValue;
if (getValueAt(index, v)) {
StrictMode.noteResourceMismatch(v);
return XmlUtils.convertValueToBoolean(v.coerceToString(), defValue);
}
// We already checked for TYPE_NULL. This should never happen.
throw new RuntimeException("getBoolean of bad type: 0x" + Integer.toHexString(type));
}
/**
* Retrieve the integer value for the attribute at <var>index</var>.
* <p>
* Unlike {@link #getInt(int, int)}, this method will throw an exception if
* the attribute is defined but is not an integer.
*
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
*
* @return Attribute integer value, or defValue if not defined.
* @throws RuntimeException if the TypedArray has already been recycled.
* @throws UnsupportedOperationException if the attribute is defined but is
* not an integer.
*/
public int getInteger(@StyleableRes int index, int defValue) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
final int attrIndex = index;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
return data[index + STYLE_DATA];
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + attrIndex + ": " + value);
}
throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+ " to integer: type=0x" + Integer.toHexString(type));
}
/**
* Retrieve a dimensional unit attribute at <var>index</var>. Unit
* conversions are based on the current {@link DisplayMetrics}
* associated with the resources this {@link TypedArray} object
* came from.
* <p>
* This method will throw an exception if the attribute is defined but is
* not a dimension.
*
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
*
* @return Attribute dimension value multiplied by the appropriate
* metric, or defValue if not defined.
* @throws RuntimeException if the TypedArray has already been recycled.
* @throws UnsupportedOperationException if the attribute is defined but is
* not an integer.
*
* @see #getDimensionPixelOffset
* @see #getDimensionPixelSize
*/
public float getDimension(@StyleableRes int index, float defValue) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
final int attrIndex = index;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimension(data[index + STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + attrIndex + ": " + value);
}
throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+ " to dimension: type=0x" + Integer.toHexString(type));
}
/**
* Retrieve a dimensional unit attribute at <var>index</var> for use
* as an offset in raw pixels. This is the same as
* {@link #getDimension}, except the returned value is converted to
* integer pixels for you. An offset conversion involves simply
* truncating the base value to an integer.
* <p>
* This method will throw an exception if the attribute is defined but is
* not a dimension.
*
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
*
* @return Attribute dimension value multiplied by the appropriate
* metric and truncated to integer pixels, or defValue if not defined.
* @throws RuntimeException if the TypedArray has already been recycled.
* @throws UnsupportedOperationException if the attribute is defined but is
* not an integer.
*
* @see #getDimension
* @see #getDimensionPixelSize
*/
public int getDimensionPixelOffset(@StyleableRes int index, int defValue) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
final int attrIndex = index;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimensionPixelOffset(data[index + STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + attrIndex + ": " + value);
}
throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+ " to dimension: type=0x" + Integer.toHexString(type));
}
/**
* Retrieve a dimensional unit attribute at <var>index</var> for use
* as a size in raw pixels. This is the same as
* {@link #getDimension}, except the returned value is converted to
* integer pixels for use as a size. A size conversion involves
* rounding the base value, and ensuring that a non-zero base value
* is at least one pixel in size.
* <p>
* This method will throw an exception if the attribute is defined but is
* not a dimension.
*
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
*
* @return Attribute dimension value multiplied by the appropriate
* metric and truncated to integer pixels, or defValue if not defined.
* @throws RuntimeException if the TypedArray has already been recycled.
* @throws UnsupportedOperationException if the attribute is defined but is
* not a dimension.
*
* @see #getDimension
* @see #getDimensionPixelOffset
*/
public int getDimensionPixelSize(@StyleableRes int index, int defValue) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
final int attrIndex = index;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + attrIndex + ": " + value);
}
throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+ " to dimension: type=0x" + Integer.toHexString(type));
}
/**
* Retrieves a fractional unit attribute at <var>index</var>.
*
* @param index Index of attribute to retrieve.
* @param base The base value of this fraction. In other words, a
* standard fraction is multiplied by this value.
* @param pbase The parent base value of this fraction. In other
* words, a parent fraction (nn%p) is multiplied by this
* value.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
*
* @return Attribute fractional value multiplied by the appropriate
* base value, or defValue if not defined.
* @throws RuntimeException if the TypedArray has already been recycled.
* @throws UnsupportedOperationException if the attribute is defined but is
* not a fraction.
*/
public float getFraction(@StyleableRes int index, int base, int pbase, float defValue) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
final int attrIndex = index;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_FRACTION) {
return TypedValue.complexToFraction(data[index + STYLE_DATA], base, pbase);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + attrIndex + ": " + value);
}
throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
+ " to fraction: type=0x" + Integer.toHexString(type));
}
public boolean addColorAttr(StyledAttributesHelper attrs,
int attr, LiveThemeManager.ColorPropertyApplier applier,
ColorStateListApplier colorStateListApplier) {
TypedValue typedValue = new TypedValue();
if (!attrs.getValue(attr, typedValue))
return false;
if (typedValue.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
typedValue.type <= TypedValue.TYPE_LAST_COLOR_INT) {
addColorProperty(typedValue.resourceId, applier);
return true;
} else if (typedValue.type != TypedValue.TYPE_NULL && colorStateListApplier != null) {
try {
ThemedColorStateList th = ThemedColorStateList.createFromXml(
mContext.getResources(),
mContext.getResources().getXml(typedValue.resourceId), getTheme());
th.attachToComponent(this, () ->
colorStateListApplier.onColorStateListChanged(th.createColorStateList()));
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
return false;
}
/**
* Return a mask of the configuration parameters for which the values in
* this typed array may change.
*
* @return Returns a mask of the changing configuration parameters, as
* defined by {@link android.content.pm.ActivityInfo}.
* @throws RuntimeException if the TypedArray has already been recycled.
* @see android.content.pm.ActivityInfo
*/
public @Config int getChangingConfigurations() {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
@Config int changingConfig = 0;
final int[] data = mData;
final int N = length();
for (int i = 0; i < N; i++) {
final int index = i * STYLE_NUM_ENTRIES;
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
continue;
}
changingConfig |= ActivityInfo.activityInfoConfigNativeToJava(
data[index + STYLE_CHANGING_CONFIGURATIONS]);
}
return changingConfig;
}
private boolean getValueAt(int index, TypedValue outValue) {
final int[] data = mData;
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return false;
}
outValue.type = type;
outValue.data = data[index + STYLE_DATA];
outValue.assetCookie = data[index + STYLE_ASSET_COOKIE];
outValue.resourceId = data[index + STYLE_RESOURCE_ID];
outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
data[index + STYLE_CHANGING_CONFIGURATIONS]);
outValue.density = data[index + STYLE_DENSITY];
outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
return true;
}
/**
* Returns a color value specified by the given theme attribute.
*
* @param context
* the required context.
* @param colorAttribute
* a theme attribute such as <code>R.attr.colorBackground</code>.
*
* @return a color. In case of errors <code>Color.CYAN</code> is returned.
*/
@ColorInt
public static int getColor(Context context, int colorAttribute) {
final TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(colorAttribute, outValue, true);
if (isColor(outValue)) {
return outValue.data;
} else if (outValue.type == TypedValue.TYPE_REFERENCE || outValue.type == TypedValue.TYPE_STRING) {
try {
final ColorStateList colors = ContextCompat.getColorStateList(context, outValue.resourceId);
return colors.getDefaultColor();
} catch (Resources.NotFoundException ex) {
Log.d(ThemeUtil.class.getName(), ex.getMessage());
}
} else if (outValue.type == TypedValue.TYPE_NULL) {
return getColorFromStyleable(context, styleableForAttr(colorAttribute));
}
// default to cyan in case of errors
return Color.CYAN;
}
/**
* Retrieves the string value for the attribute at <var>index</var> that is
* not allowed to change with the given configurations.
*
* @param index Index of attribute to retrieve.
* @param allowedChangingConfigs Bit mask of configurations from
* {@link Configuration}.NATIVE_CONFIG_* that are allowed to change.
*
* @return String holding string data. Any styling information is removed.
* Returns {@code null} if the attribute is not defined.
* @throws RuntimeException if the TypedArray has already been recycled.
* @hide
*/
public String getNonConfigurationString(@StyleableRes int index,
@Config int allowedChangingConfigs) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index + STYLE_TYPE];
final @Config int changingConfigs = ActivityInfo.activityInfoConfigNativeToJava(
data[index + STYLE_CHANGING_CONFIGURATIONS]);
if ((changingConfigs & ~allowedChangingConfigs) != 0) {
return null;
}
if (type == TypedValue.TYPE_NULL) {
return null;
} else if (type == TypedValue.TYPE_STRING) {
return loadStringValueAt(index).toString();
}
final TypedValue v = mValue;
if (getValueAt(index, v)) {
final CharSequence cs = v.coerceToString();
return cs != null ? cs.toString() : null;
}
// We already checked for TYPE_NULL. This should never happen.
throw new RuntimeException("getNonConfigurationString of bad type: 0x"
+ Integer.toHexString(type));
}
public ResScalarValue factory(int type, int value, String rawValue) throws IOException {
switch (type) {
case TypedValue.TYPE_NULL:
return new ResReferenceValue(mPackage, 0, null);
case TypedValue.TYPE_REFERENCE:
return newReference(value, rawValue);
case TypedValue.TYPE_ATTRIBUTE:
return newReference(value, rawValue, true);
case TypedValue.TYPE_STRING:
return new ResStringValue(rawValue, value);
case TypedValue.TYPE_FLOAT:
return new ResFloatValue(Float.intBitsToFloat(value), value, rawValue);
case TypedValue.TYPE_DIMENSION:
return new ResDimenValue(value, rawValue);
case TypedValue.TYPE_FRACTION:
return new ResFractionValue(value, rawValue);
case TypedValue.TYPE_INT_BOOLEAN:
return new ResBoolValue(value != 0, value, rawValue);
case 0x07:
return newReference(value, rawValue);
}
if (type >= TypedValue.TYPE_FIRST_COLOR_INT && type <= TypedValue.TYPE_LAST_COLOR_INT) {
return new ResColorValue(value, rawValue);
}
if (type >= TypedValue.TYPE_FIRST_INT && type <= TypedValue.TYPE_LAST_INT) {
return new ResIntValue(value, rawValue, type);
}
throw new IOException("Invalid value type: " + type);
}
public static int getType(TypedArray array, int index) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) return array.getType(index);
else {
TypedValue value = array.peekValue(index);
return value == null ? TypedValue.TYPE_NULL : value.type;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
boolean measure = false;
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY);
final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor;
if (tv.type != TypedValue.TYPE_NULL) {
final int min;
if (tv.type == TypedValue.TYPE_DIMENSION) {
min = (int)tv.getDimension(metrics);
} else if (tv.type == TypedValue.TYPE_FRACTION) {
min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels);
} else {
min = 0;
}
if (width < min) {
widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
measure = true;
}
}
// TODO: Support height?
if (measure) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
/**
* Determines whether there is an attribute at <var>index</var>, returning
* {@code true} if the attribute was explicitly set to {@code @empty} and
* {@code false} only if the attribute was undefined.
*
* @param index Index of attribute to retrieve.
*
* @return True if the attribute has a value or is empty, false otherwise.
* @throws RuntimeException if the TypedArray has already been recycled.
*/
public boolean hasValueOrEmpty(@StyleableRes int index) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index + STYLE_TYPE];
return type != TypedValue.TYPE_NULL
|| data[index + STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
}
public static int getType(TypedArray array, int index) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
return array.getType(index);
else {
TypedValue value = array.peekValue(index);
return value == null ? TypedValue.TYPE_NULL : value.type;
}
}
public ResScalarValue factory(int type, int value, String rawValue) throws AndrolibException {
switch (type) {
case TypedValue.TYPE_NULL:
if (value == TypedValue.DATA_NULL_UNDEFINED) { // Special case $empty as explicitly defined empty value
return new ResStringValue(null, value);
} else if (value == TypedValue.DATA_NULL_EMPTY) {
return new ResEmptyValue(value, rawValue, type);
}
return new ResReferenceValue(mPackage, 0, null);
case TypedValue.TYPE_REFERENCE:
return newReference(value, rawValue);
case TypedValue.TYPE_ATTRIBUTE:
return newReference(value, rawValue, true);
case TypedValue.TYPE_STRING:
return new ResStringValue(rawValue, value);
case TypedValue.TYPE_FLOAT:
return new ResFloatValue(Float.intBitsToFloat(value), value, rawValue);
case TypedValue.TYPE_DIMENSION:
return new ResDimenValue(value, rawValue);
case TypedValue.TYPE_FRACTION:
return new ResFractionValue(value, rawValue);
case TypedValue.TYPE_INT_BOOLEAN:
return new ResBoolValue(value != 0, value, rawValue);
case TypedValue.TYPE_DYNAMIC_REFERENCE:
return newReference(value, rawValue);
case TypedValue.TYPE_DYNAMIC_ATTRIBUTE:
return newReference(value, rawValue, true);
}
if (type >= TypedValue.TYPE_FIRST_COLOR_INT && type <= TypedValue.TYPE_LAST_COLOR_INT) {
return new ResColorValue(value, rawValue);
}
if (type >= TypedValue.TYPE_FIRST_INT && type <= TypedValue.TYPE_LAST_INT) {
return new ResIntValue(value, rawValue, type);
}
throw new AndrolibException("Invalid value type: " + type);
}
private static void resolveAttribute(Theme theme, int attrId, TypedValue outValue, boolean resolveRefs) {
if (CustomThemeHelper.resolveAttribute(attrId, outValue)) return;
if (!theme.resolveAttribute(attrId, outValue, resolveRefs)) outValue.type = TypedValue.TYPE_NULL;
}
/**
* Determines whether there is an attribute at <var>index</var>.
* <p>
* <strong>Note:</strong> If the attribute was set to {@code @empty} or
* {@code @undefined}, this method returns {@code false}.
*
* @param index Index of attribute to retrieve.
*
* @return True if the attribute has a value, false otherwise.
* @throws RuntimeException if the TypedArray has already been recycled.
*/
public boolean hasValue(@StyleableRes int index) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index + STYLE_TYPE];
return type != TypedValue.TYPE_NULL;
}