mirror of
https://github.com/material-components/material-components-android.git
synced 2026-01-16 09:52:53 +08:00
2376 lines
75 KiB
Java
2376 lines
75 KiB
Java
/*
|
|
* Copyright 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
|
|
*
|
|
* https://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 com.google.android.material.chip;
|
|
|
|
import com.google.android.material.R;
|
|
|
|
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
|
|
import static com.google.android.material.theme.overlay.MaterialThemeOverlay.wrap;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.annotation.TargetApi;
|
|
import android.content.Context;
|
|
import android.content.res.ColorStateList;
|
|
import android.content.res.TypedArray;
|
|
import android.graphics.Outline;
|
|
import android.graphics.PorterDuff.Mode;
|
|
import android.graphics.Rect;
|
|
import android.graphics.RectF;
|
|
import android.graphics.Typeface;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.graphics.drawable.InsetDrawable;
|
|
import android.graphics.drawable.RippleDrawable;
|
|
import android.os.Build.VERSION;
|
|
import android.os.Build.VERSION_CODES;
|
|
import android.os.Bundle;
|
|
import androidx.appcompat.widget.AppCompatCheckBox;
|
|
import android.text.TextPaint;
|
|
import android.text.TextUtils;
|
|
import android.text.TextUtils.TruncateAt;
|
|
import android.util.AttributeSet;
|
|
import android.util.Log;
|
|
import android.util.TypedValue;
|
|
import android.view.Gravity;
|
|
import android.view.KeyEvent;
|
|
import android.view.MotionEvent;
|
|
import android.view.PointerIcon;
|
|
import android.view.SoundEffectConstants;
|
|
import android.view.View;
|
|
import android.view.ViewOutlineProvider;
|
|
import android.view.ViewParent;
|
|
import android.view.accessibility.AccessibilityEvent;
|
|
import android.view.accessibility.AccessibilityNodeInfo;
|
|
import android.widget.Button;
|
|
import android.widget.CompoundButton;
|
|
import androidx.annotation.AnimatorRes;
|
|
import androidx.annotation.BoolRes;
|
|
import androidx.annotation.CallSuper;
|
|
import androidx.annotation.ColorRes;
|
|
import androidx.annotation.DimenRes;
|
|
import androidx.annotation.Dimension;
|
|
import androidx.annotation.DrawableRes;
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.annotation.Px;
|
|
import androidx.annotation.RestrictTo;
|
|
import androidx.annotation.StringRes;
|
|
import androidx.annotation.StyleRes;
|
|
import androidx.core.view.ViewCompat;
|
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
|
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat;
|
|
import androidx.customview.widget.ExploreByTouchHelper;
|
|
import com.google.android.material.animation.MotionSpec;
|
|
import com.google.android.material.chip.ChipDrawable.Delegate;
|
|
import com.google.android.material.internal.MaterialCheckable;
|
|
import com.google.android.material.internal.ThemeEnforcement;
|
|
import com.google.android.material.resources.MaterialAttributes;
|
|
import com.google.android.material.resources.MaterialResources;
|
|
import com.google.android.material.resources.TextAppearance;
|
|
import com.google.android.material.resources.TextAppearanceFontCallback;
|
|
import com.google.android.material.ripple.RippleUtils;
|
|
import com.google.android.material.shape.MaterialShapeUtils;
|
|
import com.google.android.material.shape.ShapeAppearanceModel;
|
|
import com.google.android.material.shape.Shapeable;
|
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Chips are compact elements that represent an attribute, text, entity, or action. They allow users
|
|
* to enter information, select a choice, filter content, or trigger an action.
|
|
*
|
|
* <p>The Chip widget is a thin view wrapper around the {@link ChipDrawable}, which contains all of
|
|
* the layout and draw logic. The extra logic exists to support touch, mouse, keyboard, and
|
|
* accessibility navigation. The main chip and close icon are considered to be separate logical
|
|
* sub-views, and contain their own navigation behavior and state.
|
|
*
|
|
* <p>All attributes from {@code R.styleable.Chip} are supported. Do not use the {@code
|
|
* android:background} attribute. It will be ignored because Chip manages its own background
|
|
* Drawable. Also do not use the {@code android:drawableStart} and {@code android:drawableEnd}
|
|
* attributes. They will be ignored because Chip manages its own start ({@code app:chipIcon}) and
|
|
* end ({@code app:closeIcon}) drawables. The basic attributes you can set are:
|
|
*
|
|
* <ul>
|
|
* <li>{@link android.R.attr#checkable android:checkable} - If true, the chip can be toggled. If
|
|
* false, the chip acts like a button.
|
|
* <li>{@link android.R.attr#text android:text} - Sets the text of the chip.
|
|
* <li>{@code app:chipIcon} and {@code app:chipIconEnabled} - Sets the icon of the chip. Usually
|
|
* on the left.
|
|
* <li>{@code app:checkedIcon} and {@code app:checkedIconEnabled} - Sets a custom icon to use when
|
|
* checked. Usually on the left.
|
|
* <li>{@code app:closeIcon} and {@code app:closeIconEnabled} - Sets a custom icon that the user
|
|
* can click to close. Usually on the right.
|
|
* </ul>
|
|
*
|
|
* <p>You can register a listener on the main chip with {@link #setOnClickListener(OnClickListener)}
|
|
* or {@link #setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener)}. You can register
|
|
* a listener on the close icon with {@link #setOnCloseIconClickListener(OnClickListener)}.
|
|
*
|
|
* <p>For proper rendering of the ancestor TextView in RTL mode, call {@link
|
|
* #setLayoutDirection(int)} with <code>View.LAYOUT_DIRECTION_LOCALE</code>. By default, TextView's
|
|
* layout rendering sets the text padding in LTR on initial rendering and it only renders correctly
|
|
* after the layout has been invalidated so you need to ensure that initial rendering has the
|
|
* correct layout.
|
|
*
|
|
* <p>For more information, see the <a
|
|
* href="https://github.com/material-components/material-components-android/blob/master/docs/components/Chip.md">component
|
|
* developer guidance</a> and <a href="https://material.io/components/chips/overview">design
|
|
* guidelines</a>.
|
|
*
|
|
* @see ChipDrawable
|
|
*/
|
|
public class Chip extends AppCompatCheckBox
|
|
implements Delegate, Shapeable, MaterialCheckable<Chip> {
|
|
|
|
private static final String TAG = "Chip";
|
|
|
|
private static final int DEF_STYLE_RES = R.style.Widget_MaterialComponents_Chip_Action;
|
|
|
|
private static final int CHIP_BODY_VIRTUAL_ID = 0;
|
|
private static final int CLOSE_ICON_VIRTUAL_ID = 1;
|
|
private static final Rect EMPTY_BOUNDS = new Rect();
|
|
|
|
private static final int[] SELECTED_STATE = new int[] {android.R.attr.state_selected};
|
|
private static final int[] CHECKABLE_STATE_SET = {android.R.attr.state_checkable};
|
|
|
|
private static final String NAMESPACE_ANDROID = "http://schemas.android.com/apk/res/android";
|
|
|
|
@Nullable private ChipDrawable chipDrawable;
|
|
@Nullable private InsetDrawable insetBackgroundDrawable;
|
|
//noinspection NewApi
|
|
@Nullable private RippleDrawable ripple;
|
|
|
|
@Nullable private OnClickListener onCloseIconClickListener;
|
|
@Nullable private CompoundButton.OnCheckedChangeListener onCheckedChangeListener;
|
|
@Nullable private MaterialCheckable.OnCheckedChangeListener<Chip> onCheckedChangeListenerInternal;
|
|
private boolean deferredCheckedValue;
|
|
private boolean closeIconPressed;
|
|
private boolean closeIconHovered;
|
|
private boolean closeIconFocused;
|
|
private boolean ensureMinTouchTargetSize;
|
|
private int lastLayoutDirection;
|
|
|
|
@Dimension(unit = Dimension.PX)
|
|
private int minTouchTargetSize;
|
|
|
|
@Nullable private CharSequence accessibilityClassName;
|
|
private static final String BUTTON_ACCESSIBILITY_CLASS_NAME = "android.widget.Button";
|
|
private static final String RADIO_BUTTON_ACCESSIBILITY_CLASS_NAME =
|
|
"android.widget.RadioButton";
|
|
private static final String GENERIC_VIEW_ACCESSIBILITY_CLASS_NAME = "android.view.View";
|
|
|
|
@NonNull private final ChipTouchHelper touchHelper;
|
|
private boolean touchHelperEnabled;
|
|
|
|
private final Rect rect = new Rect();
|
|
private final RectF rectF = new RectF();
|
|
private final TextAppearanceFontCallback fontCallback =
|
|
new TextAppearanceFontCallback() {
|
|
@Override
|
|
public void onFontRetrieved(@NonNull Typeface typeface, boolean fontResolvedSynchronously) {
|
|
// Set text to re-trigger internal ellipsize width calculation.
|
|
setText(chipDrawable.shouldDrawText() ? chipDrawable.getText() : getText());
|
|
requestLayout();
|
|
invalidate();
|
|
}
|
|
|
|
@Override
|
|
public void onFontRetrievalFailed(int reason) {}
|
|
};
|
|
|
|
public Chip(Context context) {
|
|
this(context, null);
|
|
}
|
|
|
|
public Chip(Context context, AttributeSet attrs) {
|
|
this(context, attrs, R.attr.chipStyle);
|
|
}
|
|
|
|
public Chip(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
super(wrap(context, attrs, defStyleAttr, DEF_STYLE_RES), attrs, defStyleAttr);
|
|
// Ensure we are using the correctly themed context rather than the context that was passed in.
|
|
context = getContext();
|
|
|
|
validateAttributes(attrs);
|
|
ChipDrawable drawable =
|
|
ChipDrawable.createFromAttributes(
|
|
context, attrs, defStyleAttr, DEF_STYLE_RES);
|
|
initMinTouchTarget(context, attrs, defStyleAttr);
|
|
setChipDrawable(drawable);
|
|
drawable.setElevation(getElevation());
|
|
TypedArray a =
|
|
ThemeEnforcement.obtainStyledAttributes(
|
|
context,
|
|
attrs,
|
|
R.styleable.Chip,
|
|
defStyleAttr,
|
|
DEF_STYLE_RES);
|
|
if (VERSION.SDK_INT < VERSION_CODES.M) {
|
|
// This is necessary to work around a bug that doesn't support themed color referenced in
|
|
// ColorStateList for API level < 23.
|
|
setTextColor(
|
|
MaterialResources.getColorStateList(context, a, R.styleable.Chip_android_textColor));
|
|
}
|
|
boolean hasShapeAppearanceAttribute = a.hasValue(R.styleable.Chip_shapeAppearance);
|
|
a.recycle();
|
|
|
|
touchHelper = new ChipTouchHelper(this);
|
|
updateAccessibilityDelegate();
|
|
if (!hasShapeAppearanceAttribute) {
|
|
initOutlineProvider();
|
|
}
|
|
// Set deferred values
|
|
setChecked(deferredCheckedValue);
|
|
setText(drawable.getText());
|
|
setEllipsize(drawable.getEllipsize());
|
|
|
|
updateTextPaintDrawState();
|
|
|
|
// Chip text should not extend to more than 1 line.
|
|
if (!chipDrawable.shouldDrawText()) {
|
|
setLines(1);
|
|
setHorizontallyScrolling(true);
|
|
}
|
|
// Chip text should be vertically center aligned and start aligned.
|
|
// Final horizontal text origin is set during the onDraw call via canvas translation.
|
|
setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
|
|
// Helps TextView calculate the available text width.
|
|
updatePaddingInternal();
|
|
if (shouldEnsureMinTouchTargetSize()) {
|
|
setMinHeight(minTouchTargetSize);
|
|
}
|
|
lastLayoutDirection = getLayoutDirection();
|
|
|
|
super.setOnCheckedChangeListener(
|
|
(buttonView, isChecked) -> {
|
|
if (onCheckedChangeListenerInternal != null) {
|
|
onCheckedChangeListenerInternal.onCheckedChanged(Chip.this, isChecked);
|
|
}
|
|
if (onCheckedChangeListener != null) {
|
|
onCheckedChangeListener.onCheckedChanged(buttonView, isChecked);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
protected void onAttachedToWindow() {
|
|
super.onAttachedToWindow();
|
|
|
|
MaterialShapeUtils.setParentAbsoluteElevation(this, chipDrawable);
|
|
}
|
|
|
|
@Override
|
|
public void setElevation(float elevation) {
|
|
super.setElevation(elevation);
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setElevation(elevation);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) {
|
|
super.onInitializeAccessibilityNodeInfo(info);
|
|
info.setClassName(getAccessibilityClassName());
|
|
info.setCheckable(isCheckable());
|
|
info.setClickable(isClickable());
|
|
|
|
if (getParent() instanceof ChipGroup) {
|
|
ChipGroup chipGroup = ((ChipGroup) getParent());
|
|
AccessibilityNodeInfoCompat infoCompat = AccessibilityNodeInfoCompat.wrap(info);
|
|
// -1 for unknown column indices in a reflowing layout
|
|
int columnIndex = chipGroup.isSingleLine() ? chipGroup.getIndexOfChip(this) : -1;
|
|
infoCompat.setCollectionItemInfo(
|
|
CollectionItemInfoCompat.obtain(
|
|
/* rowIndex= */ chipGroup.getRowIndex(this),
|
|
/* rowSpan= */ 1,
|
|
/* columnIndex= */ columnIndex,
|
|
/* columnSpan= */ 1,
|
|
/* heading= */ false,
|
|
/* selected= */ isChecked()));
|
|
}
|
|
}
|
|
|
|
// TODO(b/80452017): Due to a11y bug, avoid setting custom ExploreByTouchHelper as delegate
|
|
// unless there's a close/trailing icon. Re-evaluate this once bug is fixed.
|
|
private void updateAccessibilityDelegate() {
|
|
if (hasCloseIcon() && isCloseIconVisible() && onCloseIconClickListener != null) {
|
|
ViewCompat.setAccessibilityDelegate(this, touchHelper);
|
|
touchHelperEnabled = true;
|
|
} else {
|
|
// Avoid setting custom ExploreByTouchHelper if the trailing icon is only decorative.
|
|
ViewCompat.setAccessibilityDelegate(this, null);
|
|
touchHelperEnabled = false;
|
|
}
|
|
}
|
|
|
|
private void initMinTouchTarget(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
|
// Checks if the Chip should meet Android's minimum touch target size.
|
|
TypedArray a =
|
|
ThemeEnforcement.obtainStyledAttributes(
|
|
context,
|
|
attrs,
|
|
R.styleable.Chip,
|
|
defStyleAttr,
|
|
DEF_STYLE_RES);
|
|
ensureMinTouchTargetSize = a.getBoolean(R.styleable.Chip_ensureMinTouchTargetSize, false);
|
|
|
|
float defaultMinTouchTargetSize = MaterialAttributes.resolveMinimumAccessibleTouchTarget(context);
|
|
minTouchTargetSize =
|
|
(int)
|
|
Math.ceil(
|
|
a.getDimension(R.styleable.Chip_chipMinTouchTargetSize, defaultMinTouchTargetSize));
|
|
|
|
a.recycle();
|
|
}
|
|
|
|
/**
|
|
* Updates the paddings to inform {@link android.widget.TextView} how much width the text can
|
|
* occupy.
|
|
*/
|
|
private void updatePaddingInternal() {
|
|
if (TextUtils.isEmpty(getText()) || chipDrawable == null) {
|
|
return;
|
|
}
|
|
int paddingEnd =
|
|
(int)
|
|
(chipDrawable.getChipEndPadding()
|
|
+ chipDrawable.getTextEndPadding()
|
|
+ chipDrawable.calculateCloseIconWidth());
|
|
int paddingStart =
|
|
(int)
|
|
(chipDrawable.getChipStartPadding()
|
|
+ chipDrawable.getTextStartPadding()
|
|
+ chipDrawable.calculateChipIconWidth());
|
|
if (insetBackgroundDrawable != null) {
|
|
Rect padding = new Rect();
|
|
insetBackgroundDrawable.getPadding(padding);
|
|
paddingStart += padding.left;
|
|
paddingEnd += padding.right;
|
|
}
|
|
|
|
setPaddingRelative(paddingStart, getPaddingTop(), paddingEnd, getPaddingBottom());
|
|
}
|
|
|
|
@Override
|
|
public void onRtlPropertiesChanged(int layoutDirection) {
|
|
super.onRtlPropertiesChanged(layoutDirection);
|
|
|
|
// Layout direction can be updated via a parent (or ancestor) View, causing this property change
|
|
// method to be called. Update text padding whenever a layout direction change is detected.
|
|
if (lastLayoutDirection != layoutDirection) {
|
|
lastLayoutDirection = layoutDirection;
|
|
updatePaddingInternal();
|
|
}
|
|
}
|
|
|
|
private void validateAttributes(@Nullable AttributeSet attributeSet) {
|
|
if (attributeSet == null) {
|
|
return;
|
|
}
|
|
if (attributeSet.getAttributeValue(NAMESPACE_ANDROID, "background") != null) {
|
|
Log.w(TAG, "Do not set the background; Chip manages its own background drawable.");
|
|
}
|
|
if (attributeSet.getAttributeValue(NAMESPACE_ANDROID, "drawableLeft") != null) {
|
|
throw new UnsupportedOperationException("Please set left drawable using R.attr#chipIcon.");
|
|
}
|
|
if (attributeSet.getAttributeValue(NAMESPACE_ANDROID, "drawableStart") != null) {
|
|
throw new UnsupportedOperationException("Please set start drawable using R.attr#chipIcon.");
|
|
}
|
|
if (attributeSet.getAttributeValue(NAMESPACE_ANDROID, "drawableEnd") != null) {
|
|
throw new UnsupportedOperationException("Please set end drawable using R.attr#closeIcon.");
|
|
}
|
|
if (attributeSet.getAttributeValue(NAMESPACE_ANDROID, "drawableRight") != null) {
|
|
throw new UnsupportedOperationException("Please set end drawable using R.attr#closeIcon.");
|
|
}
|
|
if (!attributeSet.getAttributeBooleanValue(NAMESPACE_ANDROID, "singleLine", true)
|
|
|| (attributeSet.getAttributeIntValue(NAMESPACE_ANDROID, "lines", 1) != 1)
|
|
|| (attributeSet.getAttributeIntValue(NAMESPACE_ANDROID, "minLines", 1) != 1)
|
|
|| (attributeSet.getAttributeIntValue(NAMESPACE_ANDROID, "maxLines", 1) != 1)) {
|
|
throw new UnsupportedOperationException("Chip does not support multi-line text");
|
|
}
|
|
|
|
if (attributeSet.getAttributeIntValue(
|
|
NAMESPACE_ANDROID, "gravity", (Gravity.CENTER_VERTICAL | Gravity.START))
|
|
!= (Gravity.CENTER_VERTICAL | Gravity.START)) {
|
|
Log.w(TAG, "Chip text must be vertically center and start aligned");
|
|
}
|
|
}
|
|
|
|
private void initOutlineProvider() {
|
|
setOutlineProvider(
|
|
new ViewOutlineProvider() {
|
|
@Override
|
|
public void getOutline(View view, @NonNull Outline outline) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.getOutline(outline);
|
|
} else {
|
|
outline.setAlpha(0.0f);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/** Returns the ChipDrawable backing this chip. */
|
|
public Drawable getChipDrawable() {
|
|
return chipDrawable;
|
|
}
|
|
|
|
/** Sets the ChipDrawable backing this chip. */
|
|
public void setChipDrawable(@NonNull ChipDrawable drawable) {
|
|
if (chipDrawable != drawable) {
|
|
unapplyChipDrawable(chipDrawable);
|
|
chipDrawable = drawable;
|
|
// Defers to TextView to draw the text and ChipDrawable to render the
|
|
// rest (e.g. chip / check / close icons).
|
|
chipDrawable.setShouldDrawText(false);
|
|
applyChipDrawable(chipDrawable);
|
|
ensureAccessibleTouchTarget(minTouchTargetSize);
|
|
}
|
|
}
|
|
|
|
private void updateBackgroundDrawable() {
|
|
updateFrameworkRippleBackground();
|
|
}
|
|
|
|
@Nullable
|
|
public Drawable getBackgroundDrawable() {
|
|
if (insetBackgroundDrawable == null) {
|
|
return chipDrawable;
|
|
}
|
|
return insetBackgroundDrawable;
|
|
}
|
|
|
|
private void updateFrameworkRippleBackground() {
|
|
//noinspection NewApi
|
|
ripple =
|
|
new RippleDrawable(
|
|
RippleUtils.sanitizeRippleDrawableColor(chipDrawable.getRippleColor()),
|
|
getBackgroundDrawable(),
|
|
null);
|
|
chipDrawable.setUseCompatRipple(false);
|
|
//noinspection NewApi
|
|
setBackground(ripple);
|
|
updatePaddingInternal();
|
|
}
|
|
|
|
private void unapplyChipDrawable(@Nullable ChipDrawable chipDrawable) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setDelegate(null);
|
|
}
|
|
}
|
|
|
|
private void applyChipDrawable(@NonNull ChipDrawable chipDrawable) {
|
|
chipDrawable.setDelegate(this);
|
|
}
|
|
|
|
@Override
|
|
protected int[] onCreateDrawableState(int extraSpace) {
|
|
final int[] state = super.onCreateDrawableState(extraSpace + 2);
|
|
if (isChecked()) {
|
|
mergeDrawableStates(state, SELECTED_STATE);
|
|
}
|
|
if (isCheckable()) {
|
|
mergeDrawableStates(state, CHECKABLE_STATE_SET);
|
|
}
|
|
return state;
|
|
}
|
|
|
|
@Override
|
|
public void setGravity(int gravity) {
|
|
if (gravity != (Gravity.CENTER_VERTICAL | Gravity.START)) {
|
|
Log.w(TAG, "Chip text must be vertically center and start aligned");
|
|
} else {
|
|
super.setGravity(gravity);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setBackgroundTintList(@Nullable ColorStateList tint) {
|
|
Log.w(TAG, "Do not set the background tint list; Chip manages its own background drawable.");
|
|
}
|
|
|
|
@Override
|
|
public void setBackgroundTintMode(@Nullable Mode tintMode) {
|
|
Log.w(TAG, "Do not set the background tint mode; Chip manages its own background drawable.");
|
|
}
|
|
|
|
@Override
|
|
public void setBackgroundColor(int color) {
|
|
Log.w(TAG, "Do not set the background color; Chip manages its own background drawable.");
|
|
}
|
|
|
|
@Override
|
|
public void setBackgroundResource(int resid) {
|
|
Log.w(TAG, "Do not set the background resource; Chip manages its own background drawable.");
|
|
}
|
|
|
|
@Override
|
|
public void setBackground(Drawable background) {
|
|
if (background != getBackgroundDrawable() && background != ripple) {
|
|
Log.w(TAG, "Do not set the background; Chip manages its own background drawable.");
|
|
} else {
|
|
super.setBackground(background);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setBackgroundDrawable(Drawable background) {
|
|
if (background != getBackgroundDrawable() && background != ripple) {
|
|
Log.w(TAG, "Do not set the background drawable; Chip manages its own background drawable.");
|
|
} else {
|
|
super.setBackgroundDrawable(background);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setCompoundDrawables(
|
|
@Nullable Drawable left,
|
|
@Nullable Drawable top,
|
|
@Nullable Drawable right,
|
|
@Nullable Drawable bottom) {
|
|
if (left != null) {
|
|
throw new UnsupportedOperationException("Please set start drawable using R.attr#chipIcon.");
|
|
}
|
|
if (right != null) {
|
|
throw new UnsupportedOperationException("Please set end drawable using R.attr#closeIcon.");
|
|
}
|
|
|
|
super.setCompoundDrawables(left, top, right, bottom);
|
|
}
|
|
|
|
@Override
|
|
public void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) {
|
|
if (left != 0) {
|
|
throw new UnsupportedOperationException("Please set start drawable using R.attr#chipIcon.");
|
|
}
|
|
if (right != 0) {
|
|
throw new UnsupportedOperationException("Please set end drawable using R.attr#closeIcon.");
|
|
}
|
|
|
|
super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
|
|
}
|
|
|
|
@Override
|
|
public void setCompoundDrawablesWithIntrinsicBounds(
|
|
@Nullable Drawable left,
|
|
@Nullable Drawable top,
|
|
@Nullable Drawable right,
|
|
@Nullable Drawable bottom) {
|
|
if (left != null) {
|
|
throw new UnsupportedOperationException("Please set left drawable using R.attr#chipIcon.");
|
|
}
|
|
if (right != null) {
|
|
throw new UnsupportedOperationException("Please set right drawable using R.attr#closeIcon.");
|
|
}
|
|
|
|
super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
|
|
}
|
|
|
|
@Override
|
|
public void setCompoundDrawablesRelative(
|
|
@Nullable Drawable start,
|
|
@Nullable Drawable top,
|
|
@Nullable Drawable end,
|
|
@Nullable Drawable bottom) {
|
|
if (start != null) {
|
|
throw new UnsupportedOperationException("Please set start drawable using R.attr#chipIcon.");
|
|
}
|
|
if (end != null) {
|
|
throw new UnsupportedOperationException("Please set end drawable using R.attr#closeIcon.");
|
|
}
|
|
|
|
super.setCompoundDrawablesRelative(start, top, end, bottom);
|
|
}
|
|
|
|
@Override
|
|
public void setCompoundDrawablesRelativeWithIntrinsicBounds(
|
|
int start, int top, int end, int bottom) {
|
|
if (start != 0) {
|
|
throw new UnsupportedOperationException("Please set start drawable using R.attr#chipIcon.");
|
|
}
|
|
if (end != 0) {
|
|
throw new UnsupportedOperationException("Please set end drawable using R.attr#closeIcon.");
|
|
}
|
|
|
|
super.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
|
|
}
|
|
|
|
@Override
|
|
public void setCompoundDrawablesRelativeWithIntrinsicBounds(
|
|
@Nullable Drawable start,
|
|
@Nullable Drawable top,
|
|
@Nullable Drawable end,
|
|
@Nullable Drawable bottom) {
|
|
if (start != null) {
|
|
throw new UnsupportedOperationException("Please set start drawable using R.attr#chipIcon.");
|
|
}
|
|
if (end != null) {
|
|
throw new UnsupportedOperationException("Please set end drawable using R.attr#closeIcon.");
|
|
}
|
|
super.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public TruncateAt getEllipsize() {
|
|
return chipDrawable != null ? chipDrawable.getEllipsize() : null;
|
|
}
|
|
|
|
@Override
|
|
public void setEllipsize(TruncateAt where) {
|
|
if (chipDrawable == null) {
|
|
return;
|
|
}
|
|
if (where == TruncateAt.MARQUEE) {
|
|
throw new UnsupportedOperationException("Text within a chip are not allowed to scroll.");
|
|
}
|
|
super.setEllipsize(where);
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setEllipsize(where);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setSingleLine(boolean singleLine) {
|
|
if (!singleLine) {
|
|
throw new UnsupportedOperationException("Chip does not support multi-line text");
|
|
}
|
|
super.setSingleLine(singleLine);
|
|
}
|
|
|
|
@Override
|
|
public void setLines(int lines) {
|
|
if (lines > 1) {
|
|
throw new UnsupportedOperationException("Chip does not support multi-line text");
|
|
}
|
|
super.setLines(lines);
|
|
}
|
|
|
|
@Override
|
|
public void setMinLines(int minLines) {
|
|
if (minLines > 1) {
|
|
throw new UnsupportedOperationException("Chip does not support multi-line text");
|
|
}
|
|
super.setMinLines(minLines);
|
|
}
|
|
|
|
@Override
|
|
public void setMaxLines(int maxLines) {
|
|
if (maxLines > 1) {
|
|
throw new UnsupportedOperationException("Chip does not support multi-line text");
|
|
}
|
|
super.setMaxLines(maxLines);
|
|
}
|
|
|
|
@Override
|
|
public void setMaxWidth(@Px int maxWidth) {
|
|
super.setMaxWidth(maxWidth);
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setMaxWidth(maxWidth);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onChipDrawableSizeChange() {
|
|
ensureAccessibleTouchTarget(minTouchTargetSize);
|
|
requestLayout();
|
|
invalidateOutline();
|
|
}
|
|
|
|
@Override
|
|
public void setChecked(boolean checked) {
|
|
if (chipDrawable == null) {
|
|
// Defer the setChecked() call until after initialization.
|
|
deferredCheckedValue = checked;
|
|
} else if (chipDrawable.isCheckable()) {
|
|
super.setChecked(checked);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setOnCheckedChangeListener(
|
|
@Nullable CompoundButton.OnCheckedChangeListener listener) {
|
|
// Do not call super here - the wrapped listener set in the constructor will call the listener.
|
|
onCheckedChangeListener = listener;
|
|
}
|
|
|
|
/** Register a callback to be invoked when the close icon is clicked. */
|
|
public void setOnCloseIconClickListener(OnClickListener listener) {
|
|
this.onCloseIconClickListener = listener;
|
|
updateAccessibilityDelegate();
|
|
}
|
|
|
|
/**
|
|
* Call this chip's close icon click listener, if it is defined. Performs all normal actions
|
|
* associated with clicking: reporting accessibility event, playing a sound, etc.
|
|
*
|
|
* @return True there was an assigned close icon click listener that was called, false otherwise
|
|
* is returned.
|
|
* @see #setOnCloseIconClickListener(OnClickListener)
|
|
*/
|
|
@CallSuper
|
|
public boolean performCloseIconClick() {
|
|
playSoundEffect(SoundEffectConstants.CLICK);
|
|
|
|
boolean result;
|
|
if (onCloseIconClickListener != null) {
|
|
onCloseIconClickListener.onClick(this);
|
|
result = true;
|
|
} else {
|
|
result = false;
|
|
}
|
|
|
|
if (touchHelperEnabled) {
|
|
touchHelper.sendEventForVirtualView(
|
|
CLOSE_ICON_VIRTUAL_ID, AccessibilityEvent.TYPE_VIEW_CLICKED);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@SuppressLint("ClickableViewAccessibility") // There's an accessibility delegate that will handle
|
|
// interactions with the trailing chip icon.
|
|
@Override
|
|
public boolean onTouchEvent(@NonNull MotionEvent event) {
|
|
boolean handled = false;
|
|
|
|
int action = event.getActionMasked();
|
|
boolean eventInCloseIcon = getCloseIconTouchBounds().contains(event.getX(), event.getY());
|
|
switch (action) {
|
|
case MotionEvent.ACTION_DOWN:
|
|
if (eventInCloseIcon) {
|
|
setCloseIconPressed(true);
|
|
handled = true;
|
|
}
|
|
break;
|
|
case MotionEvent.ACTION_MOVE:
|
|
if (closeIconPressed) {
|
|
if (!eventInCloseIcon) {
|
|
setCloseIconPressed(false);
|
|
}
|
|
handled = true;
|
|
}
|
|
break;
|
|
case MotionEvent.ACTION_UP:
|
|
if (closeIconPressed) {
|
|
performCloseIconClick();
|
|
handled = true;
|
|
}
|
|
// Fall-through.
|
|
case MotionEvent.ACTION_CANCEL:
|
|
setCloseIconPressed(false);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return handled || super.onTouchEvent(event);
|
|
}
|
|
|
|
@Override
|
|
public boolean onHoverEvent(@NonNull MotionEvent event) {
|
|
int action = event.getActionMasked();
|
|
switch (action) {
|
|
case MotionEvent.ACTION_HOVER_MOVE:
|
|
setCloseIconHovered(getCloseIconTouchBounds().contains(event.getX(), event.getY()));
|
|
break;
|
|
case MotionEvent.ACTION_HOVER_EXIT:
|
|
setCloseIconHovered(false);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return super.onHoverEvent(event);
|
|
}
|
|
|
|
@Override
|
|
protected boolean dispatchHoverEvent(@NonNull MotionEvent event) {
|
|
if (!touchHelperEnabled) {
|
|
return super.dispatchHoverEvent(event);
|
|
}
|
|
return touchHelper.dispatchHoverEvent(event)
|
|
|| super.dispatchHoverEvent(event);
|
|
}
|
|
|
|
@Override
|
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
|
if (!touchHelperEnabled) {
|
|
return super.dispatchKeyEvent(event);
|
|
}
|
|
boolean handled = touchHelper.dispatchKeyEvent(event);
|
|
// If the key event moves focus one beyond the end of the virtual view hierarchy in the
|
|
// traversal direction (i.e. beyond the last virtual view while moving forward or before the
|
|
// first virtual view while traversing backward), ExploreByTouchHelper will erroneously report
|
|
// that it consumed the key event even though it does not move focus to the next or previous
|
|
// real view. In order to account for this, call through to super to move focus to the correct
|
|
// real view.
|
|
if (handled
|
|
&& touchHelper.getKeyboardFocusedVirtualViewId() != ExploreByTouchHelper.INVALID_ID) {
|
|
return true;
|
|
}
|
|
return super.dispatchKeyEvent(event);
|
|
}
|
|
|
|
@Override
|
|
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
|
|
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
|
if (touchHelperEnabled) {
|
|
touchHelper.onFocusChanged(focused, direction, previouslyFocusedRect);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void getFocusedRect(@NonNull Rect r) {
|
|
if (touchHelperEnabled
|
|
&& (touchHelper.getKeyboardFocusedVirtualViewId() == CLOSE_ICON_VIRTUAL_ID
|
|
|| touchHelper.getAccessibilityFocusedVirtualViewId() == CLOSE_ICON_VIRTUAL_ID)) {
|
|
r.set(getCloseIconTouchBoundsInt());
|
|
} else {
|
|
super.getFocusedRect(r);
|
|
}
|
|
}
|
|
|
|
private void setCloseIconPressed(boolean pressed) {
|
|
if (closeIconPressed != pressed) {
|
|
closeIconPressed = pressed;
|
|
refreshDrawableState();
|
|
}
|
|
}
|
|
|
|
private void setCloseIconHovered(boolean hovered) {
|
|
if (closeIconHovered != hovered) {
|
|
closeIconHovered = hovered;
|
|
refreshDrawableState();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void drawableStateChanged() {
|
|
super.drawableStateChanged();
|
|
|
|
boolean changed = false;
|
|
|
|
if (chipDrawable != null && chipDrawable.isCloseIconStateful()) {
|
|
changed = chipDrawable.setCloseIconState(createCloseIconDrawableState());
|
|
}
|
|
|
|
if (changed) {
|
|
invalidate();
|
|
}
|
|
}
|
|
|
|
@NonNull
|
|
private int[] createCloseIconDrawableState() {
|
|
int count = 0;
|
|
if (isEnabled()) {
|
|
count++;
|
|
}
|
|
if (closeIconFocused) {
|
|
count++;
|
|
}
|
|
if (closeIconHovered) {
|
|
count++;
|
|
}
|
|
if (closeIconPressed) {
|
|
count++;
|
|
}
|
|
if (isChecked()) {
|
|
count++;
|
|
}
|
|
|
|
int[] stateSet = new int[count];
|
|
int i = 0;
|
|
|
|
if (isEnabled()) {
|
|
stateSet[i] = android.R.attr.state_enabled;
|
|
i++;
|
|
}
|
|
if (closeIconFocused) {
|
|
stateSet[i] = android.R.attr.state_focused;
|
|
i++;
|
|
}
|
|
if (closeIconHovered) {
|
|
stateSet[i] = android.R.attr.state_hovered;
|
|
i++;
|
|
}
|
|
if (closeIconPressed) {
|
|
stateSet[i] = android.R.attr.state_pressed;
|
|
i++;
|
|
}
|
|
if (isChecked()) {
|
|
stateSet[i] = android.R.attr.state_selected;
|
|
i++;
|
|
}
|
|
return stateSet;
|
|
}
|
|
|
|
private boolean hasCloseIcon() {
|
|
return chipDrawable != null && chipDrawable.getCloseIcon() != null;
|
|
}
|
|
|
|
@NonNull
|
|
private RectF getCloseIconTouchBounds() {
|
|
rectF.setEmpty();
|
|
|
|
if (hasCloseIcon() && onCloseIconClickListener != null) {
|
|
// noinspection ConstantConditions
|
|
chipDrawable.getCloseIconTouchBounds(rectF);
|
|
}
|
|
|
|
return rectF;
|
|
}
|
|
|
|
@NonNull
|
|
private Rect getCloseIconTouchBoundsInt() {
|
|
RectF bounds = getCloseIconTouchBounds();
|
|
rect.set((int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom);
|
|
return rect;
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
@TargetApi(VERSION_CODES.N)
|
|
public PointerIcon onResolvePointerIcon(@NonNull MotionEvent event, int pointerIndex) {
|
|
if (getCloseIconTouchBounds().contains(event.getX(), event.getY()) && isEnabled()) {
|
|
return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
|
|
}
|
|
return super.onResolvePointerIcon(event, pointerIndex);
|
|
}
|
|
|
|
/** @hide */
|
|
@RestrictTo(LIBRARY_GROUP)
|
|
@Override
|
|
public void setInternalOnCheckedChangeListener(
|
|
@Nullable MaterialCheckable.OnCheckedChangeListener<Chip> listener) {
|
|
onCheckedChangeListenerInternal = listener;
|
|
}
|
|
|
|
/** Provides a virtual view hierarchy for the close icon. */
|
|
private class ChipTouchHelper extends ExploreByTouchHelper {
|
|
|
|
ChipTouchHelper(Chip view) {
|
|
super(view);
|
|
}
|
|
|
|
@Override
|
|
protected int getVirtualViewAt(float x, float y) {
|
|
return (hasCloseIcon() && getCloseIconTouchBounds().contains(x, y))
|
|
? CLOSE_ICON_VIRTUAL_ID
|
|
: CHIP_BODY_VIRTUAL_ID;
|
|
}
|
|
|
|
@Override
|
|
protected void getVisibleVirtualViews(@NonNull List<Integer> virtualViewIds) {
|
|
virtualViewIds.add(CHIP_BODY_VIRTUAL_ID);
|
|
if (hasCloseIcon() && isCloseIconVisible() && onCloseIconClickListener != null) {
|
|
virtualViewIds.add(CLOSE_ICON_VIRTUAL_ID);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onVirtualViewKeyboardFocusChanged(int virtualViewId, boolean hasFocus) {
|
|
if (virtualViewId == CLOSE_ICON_VIRTUAL_ID) {
|
|
closeIconFocused = hasFocus;
|
|
}
|
|
if (chipDrawable.refreshCloseIconFocus(closeIconFocused)) {
|
|
refreshDrawableState();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onPopulateNodeForVirtualView(
|
|
int virtualViewId, @NonNull AccessibilityNodeInfoCompat node) {
|
|
if (virtualViewId == CLOSE_ICON_VIRTUAL_ID) {
|
|
CharSequence closeIconContentDescription = getCloseIconContentDescription();
|
|
if (closeIconContentDescription != null) {
|
|
node.setContentDescription(closeIconContentDescription);
|
|
} else {
|
|
CharSequence chipText = getText();
|
|
node.setContentDescription(
|
|
getContext()
|
|
.getString(
|
|
R.string.mtrl_chip_close_icon_content_description,
|
|
!TextUtils.isEmpty(chipText) ? chipText : "")
|
|
.trim());
|
|
}
|
|
node.setBoundsInParent(getCloseIconTouchBoundsInt());
|
|
node.addAction(AccessibilityActionCompat.ACTION_CLICK);
|
|
node.setEnabled(isEnabled());
|
|
// Set the class name to Button so that the close icon is treated as a button by TalkBack.
|
|
node.setClassName(Button.class.getName());
|
|
} else {
|
|
node.setContentDescription("");
|
|
node.setBoundsInParent(EMPTY_BOUNDS);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onPopulateNodeForHost(@NonNull AccessibilityNodeInfoCompat node) {
|
|
node.setCheckable(isCheckable());
|
|
node.setClickable(isClickable());
|
|
node.setClassName(getAccessibilityClassName());
|
|
CharSequence chipText = getText();
|
|
if (VERSION.SDK_INT >= VERSION_CODES.M) {
|
|
node.setText(chipText);
|
|
} else {
|
|
// Before M, TalkBack doesn't get the text from setText, so we have to set the content
|
|
// description instead.
|
|
node.setContentDescription(chipText);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected boolean onPerformActionForVirtualView(
|
|
int virtualViewId, int action, Bundle arguments) {
|
|
if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
|
|
if (virtualViewId == CHIP_BODY_VIRTUAL_ID) {
|
|
return performClick();
|
|
} else if (virtualViewId == CLOSE_ICON_VIRTUAL_ID) {
|
|
return performCloseIconClick();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Getters and setters for attributes.
|
|
|
|
/**
|
|
* Returns this chip's background color.
|
|
*
|
|
* @see #setChipBackgroundColor(ColorStateList)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipBackgroundColor
|
|
*/
|
|
@Nullable
|
|
public ColorStateList getChipBackgroundColor() {
|
|
return chipDrawable != null ? chipDrawable.getChipBackgroundColor() : null;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's background color using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's background color.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipBackgroundColor
|
|
*/
|
|
public void setChipBackgroundColorResource(@ColorRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipBackgroundColorResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's background color.
|
|
*
|
|
* @param chipBackgroundColor This chip's background color.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipBackgroundColor
|
|
*/
|
|
public void setChipBackgroundColor(@Nullable ColorStateList chipBackgroundColor) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipBackgroundColor(chipBackgroundColor);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's minimum height.
|
|
*
|
|
* @see #setChipMinHeight(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipMinHeight
|
|
*/
|
|
public float getChipMinHeight() {
|
|
return chipDrawable != null ? chipDrawable.getChipMinHeight() : 0;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's minimum height using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's minimum height.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipMinHeight
|
|
*/
|
|
public void setChipMinHeightResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipMinHeightResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's minimum height.
|
|
*
|
|
* @param minHeight This chip's minimum height.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipMinHeight
|
|
*/
|
|
public void setChipMinHeight(float minHeight) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipMinHeight(minHeight);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's corner radius.
|
|
*
|
|
* @see #setChipCornerRadius(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipCornerRadius
|
|
*/
|
|
public float getChipCornerRadius() {
|
|
return chipDrawable != null ? Math.max(0, chipDrawable.getChipCornerRadius()) : 0;
|
|
}
|
|
|
|
/**
|
|
* @deprecated call {@link ShapeAppearanceModel#withCornerSize(float)} or call {@link
|
|
* ShapeAppearanceModel#toBuilder()} on the {@link #getShapeAppearanceModel()}, modify the
|
|
* shape using the builder and then call {@link
|
|
* #setShapeAppearanceModel(ShapeAppearanceModel)}.
|
|
*/
|
|
@Deprecated
|
|
public void setChipCornerRadiusResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipCornerRadiusResource(id);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setShapeAppearanceModel(@NonNull ShapeAppearanceModel shapeAppearanceModel) {
|
|
chipDrawable.setShapeAppearanceModel(shapeAppearanceModel);
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public ShapeAppearanceModel getShapeAppearanceModel() {
|
|
return chipDrawable.getShapeAppearanceModel();
|
|
}
|
|
|
|
/**
|
|
* @deprecated call {@link ShapeAppearanceModel#withCornerSize(float)} or call {@link
|
|
* ShapeAppearanceModel#toBuilder()} on the {@link #getShapeAppearanceModel()}, modify the
|
|
* shape using the builder and then call {@link
|
|
* #setShapeAppearanceModel(ShapeAppearanceModel)}.
|
|
*/
|
|
@Deprecated
|
|
public void setChipCornerRadius(float chipCornerRadius) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipCornerRadius(chipCornerRadius);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's stroke color.
|
|
*
|
|
* @see #setChipStrokeColor(ColorStateList)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipStrokeColor
|
|
*/
|
|
@Nullable
|
|
public ColorStateList getChipStrokeColor() {
|
|
return chipDrawable != null ? chipDrawable.getChipStrokeColor() : null;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's stroke color using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's stroke color.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipStrokeColor
|
|
*/
|
|
public void setChipStrokeColorResource(@ColorRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipStrokeColorResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's stroke color.
|
|
*
|
|
* @param chipStrokeColor This chip's stroke color.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipStrokeColor
|
|
*/
|
|
public void setChipStrokeColor(@Nullable ColorStateList chipStrokeColor) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipStrokeColor(chipStrokeColor);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's stroke width.
|
|
*
|
|
* @see #setChipStrokeWidth(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipStrokeWidth
|
|
*/
|
|
public float getChipStrokeWidth() {
|
|
return chipDrawable != null ? chipDrawable.getChipStrokeWidth() : 0;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's stroke width using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's stroke width.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipStrokeWidth
|
|
*/
|
|
public void setChipStrokeWidthResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipStrokeWidthResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's stroke width.
|
|
*
|
|
* @param chipStrokeWidth This chip's stroke width.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipStrokeWidth
|
|
*/
|
|
public void setChipStrokeWidth(float chipStrokeWidth) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipStrokeWidth(chipStrokeWidth);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's ripple color.
|
|
*
|
|
* @see #setRippleColor(ColorStateList)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_rippleColor
|
|
*/
|
|
@Nullable
|
|
public ColorStateList getRippleColor() {
|
|
return chipDrawable != null ? chipDrawable.getRippleColor() : null;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's ripple color using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's ripple color.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_rippleColor
|
|
*/
|
|
public void setRippleColorResource(@ColorRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setRippleColorResource(id);
|
|
if (!chipDrawable.getUseCompatRipple()) {
|
|
updateFrameworkRippleBackground();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's ripple color.
|
|
*
|
|
* @param rippleColor This chip's ripple color.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_rippleColor
|
|
*/
|
|
public void setRippleColor(@Nullable ColorStateList rippleColor) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setRippleColor(rippleColor);
|
|
}
|
|
if (!chipDrawable.getUseCompatRipple()) {
|
|
updateFrameworkRippleBackground();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's text.
|
|
*
|
|
* @deprecated Use {@link Chip#getText()} instead.
|
|
*/
|
|
@Deprecated
|
|
public CharSequence getChipText() {
|
|
return getText();
|
|
}
|
|
|
|
@Override
|
|
public void setLayoutDirection(int layoutDirection) {
|
|
if (chipDrawable == null) {
|
|
return;
|
|
}
|
|
super.setLayoutDirection(layoutDirection);
|
|
}
|
|
|
|
@Override
|
|
public void setText(CharSequence text, BufferType type) {
|
|
if (chipDrawable == null) {
|
|
return;
|
|
}
|
|
if (text == null) {
|
|
text = "";
|
|
}
|
|
super.setText(chipDrawable.shouldDrawText() ? null : text, type);
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setText(text);
|
|
}
|
|
}
|
|
|
|
/** @deprecated Use {@link Chip#setText(int)} instead. */
|
|
@Deprecated
|
|
public void setChipTextResource(@StringRes int id) {
|
|
setText(getResources().getString(id));
|
|
}
|
|
|
|
/** @deprecated Use {@link Chip#setText(CharSequence)} instead. */
|
|
@Deprecated
|
|
public void setChipText(@Nullable CharSequence chipText) {
|
|
setText(chipText);
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's text appearance using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's text appearance.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_android_textAppearance
|
|
*/
|
|
public void setTextAppearanceResource(@StyleRes int id) {
|
|
this.setTextAppearance(getContext(), id);
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's text appearance.
|
|
*
|
|
* @param textAppearance This chip's text appearance.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_android_textAppearance
|
|
*/
|
|
public void setTextAppearance(@Nullable TextAppearance textAppearance) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setTextAppearance(textAppearance);
|
|
}
|
|
updateTextPaintDrawState();
|
|
}
|
|
|
|
@Override
|
|
public void setTextAppearance(Context context, int resId) {
|
|
super.setTextAppearance(context, resId);
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setTextAppearanceResource(resId);
|
|
}
|
|
updateTextPaintDrawState();
|
|
}
|
|
|
|
@Override
|
|
public void setTextAppearance(int resId) {
|
|
super.setTextAppearance(resId);
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setTextAppearanceResource(resId);
|
|
}
|
|
updateTextPaintDrawState();
|
|
}
|
|
|
|
@Override
|
|
public void setTextSize(int unit, float size) {
|
|
super.setTextSize(unit, size);
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setTextSize(
|
|
TypedValue.applyDimension(unit, size, getResources().getDisplayMetrics()));
|
|
}
|
|
updateTextPaintDrawState();
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public String getFontVariationSettings() {
|
|
if (chipDrawable != null) {
|
|
return chipDrawable.getFontVariationSettings();
|
|
}
|
|
return super.getFontVariationSettings();
|
|
}
|
|
|
|
@CanIgnoreReturnValue
|
|
@Override
|
|
public boolean setFontVariationSettings(@Nullable String fontVariationSettings) {
|
|
super.setFontVariationSettings(fontVariationSettings);
|
|
// ChipDrawable will be null if setFontVariationSettings is being called from the parent
|
|
// TextView's constructor. This override is in place to pass through subsequent calls
|
|
// to ChipDrawable and not to ensure xml attributes are properly set on ChipDrawable.
|
|
// ChipDrawable will handle reading xml attributes on its own and ensure font variation
|
|
// settings are applied itself.
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setFontVariationSettings(fontVariationSettings);
|
|
updateTextPaintDrawState();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void updateTextPaintDrawState() {
|
|
TextPaint textPaint = getPaint();
|
|
if (chipDrawable != null) {
|
|
textPaint.drawableState = chipDrawable.getState();
|
|
}
|
|
TextAppearance textAppearance = getTextAppearance();
|
|
if (textAppearance != null) {
|
|
textAppearance.updateDrawState(getContext(), textPaint, fontCallback);
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
private TextAppearance getTextAppearance() {
|
|
return chipDrawable != null ? chipDrawable.getTextAppearance() : null;
|
|
}
|
|
|
|
/**
|
|
* Returns whether this chip's icon is visible.
|
|
*
|
|
* @see #setChipIconVisible(boolean)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIconVisible
|
|
*/
|
|
public boolean isChipIconVisible() {
|
|
return chipDrawable != null && chipDrawable.isChipIconVisible();
|
|
}
|
|
|
|
/** @deprecated Use {@link Chip#isChipIconVisible()} instead. */
|
|
@Deprecated
|
|
public boolean isChipIconEnabled() {
|
|
return isChipIconVisible();
|
|
}
|
|
|
|
/**
|
|
* Sets the visibility of this chip's icon using a resource id.
|
|
*
|
|
* @param id The resource id for the visibility of this chip's icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIconVisible
|
|
*/
|
|
public void setChipIconVisible(@BoolRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipIconVisible(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets whether this chip's icon is visible.
|
|
*
|
|
* @param chipIconVisible The visibility of this chip's icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIconIsVisible
|
|
*/
|
|
public void setChipIconVisible(boolean chipIconVisible) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipIconVisible(chipIconVisible);
|
|
}
|
|
}
|
|
|
|
/** @deprecated Use {@link Chip#setChipIconVisible(int)} instead. */
|
|
@Deprecated
|
|
public void setChipIconEnabledResource(@BoolRes int id) {
|
|
setChipIconVisible(id);
|
|
}
|
|
|
|
/** @deprecated Use {@link Chip#setChipIconVisible(boolean)} instead. */
|
|
@Deprecated
|
|
public void setChipIconEnabled(boolean chipIconEnabled) {
|
|
setChipIconVisible(chipIconEnabled);
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's icon.
|
|
*
|
|
* @see #setChipIcon(Drawable)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIcon
|
|
*/
|
|
@Nullable
|
|
public Drawable getChipIcon() {
|
|
return chipDrawable != null ? chipDrawable.getChipIcon() : null;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's icon using a resource id.
|
|
*
|
|
* @param id The resource id for this chip's icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIcon
|
|
*/
|
|
public void setChipIconResource(@DrawableRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipIconResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's icon.
|
|
*
|
|
* @param chipIcon drawable of this chip's icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIcon
|
|
*/
|
|
public void setChipIcon(@Nullable Drawable chipIcon) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipIcon(chipIcon);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the {@link android.content.res.ColorStateList} used to tint the chip icon.
|
|
*
|
|
* @see #setChipIconTint(ColorStateList)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIconTint
|
|
*/
|
|
@Nullable
|
|
public ColorStateList getChipIconTint() {
|
|
return chipDrawable != null ? chipDrawable.getChipIconTint() : null;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip icon's color tint using a resource id.
|
|
*
|
|
* @param id The resource id for tinting the chip icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIconTint
|
|
*/
|
|
public void setChipIconTintResource(@ColorRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipIconTintResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip icon's color tint using the specified {@link
|
|
* android.content.res.ColorStateList}.
|
|
*
|
|
* @param chipIconTint The tint color of this chip's icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIconTint
|
|
*/
|
|
public void setChipIconTint(@Nullable ColorStateList chipIconTint) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipIconTint(chipIconTint);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's icon size.
|
|
* If a non-positive value is set, the icon drawable's width and height (up to 24dp) will be used
|
|
* instead.
|
|
*
|
|
* @see #setChipIconSize(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIconTint
|
|
*/
|
|
public float getChipIconSize() {
|
|
return chipDrawable != null ? chipDrawable.getChipIconSize() : 0;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip icon's size using a resource id.
|
|
* If the value is zero or negative, the icon drawable's width and height (up to 24dp) will be
|
|
* used instead.
|
|
*
|
|
* @param id The resource id of this chip's icon size.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIconSize
|
|
*/
|
|
public void setChipIconSizeResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipIconSizeResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip icon's size.
|
|
* If the value is zero or negative, the icon drawable's width and height (up to 24dp) will be
|
|
* used instead.
|
|
*
|
|
* @param chipIconSize This chip's icon size.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIconSize
|
|
*/
|
|
public void setChipIconSize(float chipIconSize) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipIconSize(chipIconSize);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns whether this chip's close icon is visible.
|
|
*
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipIconSize
|
|
* @see #setCloseIconVisible(boolean)
|
|
*/
|
|
public boolean isCloseIconVisible() {
|
|
return chipDrawable != null && chipDrawable.isCloseIconVisible();
|
|
}
|
|
|
|
/** @deprecated Use {@link Chip#isCloseIconVisible()} instead. */
|
|
@Deprecated
|
|
public boolean isCloseIconEnabled() {
|
|
return isCloseIconVisible();
|
|
}
|
|
|
|
/**
|
|
* Sets whether this chip close icon is visible using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's close icon visibility.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconVisible
|
|
*/
|
|
public void setCloseIconVisible(@BoolRes int id) {
|
|
setCloseIconVisible(getResources().getBoolean(id));
|
|
}
|
|
|
|
/**
|
|
* Sets whether this chip close icon is visible.
|
|
*
|
|
* @param closeIconVisible This chip's close icon visibility.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconVisible
|
|
* @see #isCloseIconVisible()
|
|
*/
|
|
public void setCloseIconVisible(boolean closeIconVisible) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCloseIconVisible(closeIconVisible);
|
|
}
|
|
updateAccessibilityDelegate();
|
|
}
|
|
|
|
/** @deprecated Use {@link Chip#setCloseIconVisible(int)} instead. */
|
|
@Deprecated
|
|
public void setCloseIconEnabledResource(@BoolRes int id) {
|
|
setCloseIconVisible(id);
|
|
}
|
|
|
|
/** @deprecated Use {@link Chip#setCloseIconVisible(boolean)} instead. */
|
|
@Deprecated
|
|
public void setCloseIconEnabled(boolean closeIconEnabled) {
|
|
setCloseIconVisible(closeIconEnabled);
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's close icon.
|
|
*
|
|
* @see #setCloseIcon(Drawable).
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIcon
|
|
*/
|
|
@Nullable
|
|
public Drawable getCloseIcon() {
|
|
return chipDrawable != null ? chipDrawable.getCloseIcon() : null;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's close icon using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's close icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIcon
|
|
*/
|
|
public void setCloseIconResource(@DrawableRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCloseIconResource(id);
|
|
}
|
|
updateAccessibilityDelegate();
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's close icon.
|
|
*
|
|
* @param closeIcon This chip's close icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIcon
|
|
*/
|
|
public void setCloseIcon(@Nullable Drawable closeIcon) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCloseIcon(closeIcon);
|
|
}
|
|
updateAccessibilityDelegate();
|
|
}
|
|
|
|
/**
|
|
* Returns the tint color for this chip's close icon.
|
|
*
|
|
* @see #setCloseIconTint(ColorStateList)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconTint
|
|
*/
|
|
@Nullable
|
|
public ColorStateList getCloseIconTint() {
|
|
return chipDrawable != null ? chipDrawable.getCloseIconTint() : null;
|
|
}
|
|
|
|
/**
|
|
* Sets the tint color for this chip's close icon using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's close icon tint.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconTint
|
|
*/
|
|
public void setCloseIconTintResource(@ColorRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCloseIconTintResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the tint color for this chip's close icon.
|
|
*
|
|
* @param closeIconTint This chip's close icon tint.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconTint
|
|
*/
|
|
public void setCloseIconTint(@Nullable ColorStateList closeIconTint) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCloseIconTint(closeIconTint);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's close icon size.
|
|
*
|
|
* @see #setCloseIconSize(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconSize
|
|
*/
|
|
public float getCloseIconSize() {
|
|
return chipDrawable != null ? chipDrawable.getCloseIconSize() : 0;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's close icon size using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's close icon size.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconSize
|
|
*/
|
|
public void setCloseIconSizeResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCloseIconSizeResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's close icon size.
|
|
*
|
|
* @param closeIconSize This chip's close icon size.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconSize
|
|
*/
|
|
public void setCloseIconSize(float closeIconSize) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCloseIconSize(closeIconSize);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the content description for this chip's close icon.
|
|
*
|
|
* @param closeIconContentDescription The content description for this chip's close icon.
|
|
*/
|
|
public void setCloseIconContentDescription(@Nullable CharSequence closeIconContentDescription) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCloseIconContentDescription(closeIconContentDescription);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's close icon content description.
|
|
*
|
|
* @see #setCloseIconContentDescription(CharSequence)
|
|
*/
|
|
@Nullable
|
|
public CharSequence getCloseIconContentDescription() {
|
|
return chipDrawable != null ? chipDrawable.getCloseIconContentDescription() : null;
|
|
}
|
|
|
|
/**
|
|
* Returns whether this chip is checkable.
|
|
*
|
|
* @see #setCheckable(boolean)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_android_checkable
|
|
*/
|
|
public boolean isCheckable() {
|
|
return chipDrawable != null && chipDrawable.isCheckable();
|
|
}
|
|
|
|
/**
|
|
* Sets whether this chip is checkable using a resource id.
|
|
*
|
|
* @param id The resource id of this chip is checkable.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_android_checkable
|
|
*/
|
|
public void setCheckableResource(@BoolRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCheckableResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets whether this chip is checkable.
|
|
*
|
|
* @param checkable Whether this chip is checkable.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_android_checkable
|
|
*/
|
|
public void setCheckable(boolean checkable) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCheckable(checkable);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns whether this chip's checked icon is visible.
|
|
*
|
|
* @see #setCheckedIconVisible(boolean)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_checkedIconVisible
|
|
*/
|
|
public boolean isCheckedIconVisible() {
|
|
return chipDrawable != null && chipDrawable.isCheckedIconVisible();
|
|
}
|
|
|
|
/** @deprecated Use {@link Chip#isCheckedIconVisible()} instead. */
|
|
@Deprecated
|
|
public boolean isCheckedIconEnabled() {
|
|
return isCheckedIconVisible();
|
|
}
|
|
|
|
/**
|
|
* Sets whether this chip's checked icon is visible using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's check icon visibility.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_checkedIconVisible
|
|
*/
|
|
public void setCheckedIconVisible(@BoolRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCheckedIconVisible(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets whether this chip's checked icon is visible.
|
|
*
|
|
* @param checkedIconVisible This chip's checked icon visibility.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_checkedIconVisible
|
|
*/
|
|
public void setCheckedIconVisible(boolean checkedIconVisible) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCheckedIconVisible(checkedIconVisible);
|
|
}
|
|
}
|
|
|
|
/** @deprecated Use {@link Chip#setCheckedIconVisible(int)} instead. */
|
|
@Deprecated
|
|
public void setCheckedIconEnabledResource(@BoolRes int id) {
|
|
setCheckedIconVisible(id);
|
|
}
|
|
|
|
/** @deprecated Use {@link Chip#setCheckedIconVisible(boolean)} instead. */
|
|
@Deprecated
|
|
public void setCheckedIconEnabled(boolean checkedIconEnabled) {
|
|
setCheckedIconVisible(checkedIconEnabled);
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's checked icon.
|
|
*
|
|
* @see #setCheckedIcon(Drawable)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_checkedIcon
|
|
*/
|
|
@Nullable
|
|
public Drawable getCheckedIcon() {
|
|
return chipDrawable != null ? chipDrawable.getCheckedIcon() : null;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's checked icon using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's checked icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_checkedIcon
|
|
*/
|
|
public void setCheckedIconResource(@DrawableRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCheckedIconResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's checked icon.
|
|
*
|
|
* @param checkedIcon This chip's checked icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_checkedIcon
|
|
*/
|
|
public void setCheckedIcon(@Nullable Drawable checkedIcon) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCheckedIcon(checkedIcon);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the {@link android.content.res.ColorStateList} used to tint the checked icon.
|
|
*
|
|
* @see #setCheckedIconTint(ColorStateList)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_checkedIconTint
|
|
*/
|
|
@Nullable
|
|
public ColorStateList getCheckedIconTint() {
|
|
return chipDrawable != null ? chipDrawable.getCheckedIconTint() : null;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's checked icon's color tint using a resource id.
|
|
*
|
|
* @param id The resource id for tinting the checked icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_checkedIconTint
|
|
*/
|
|
public void setCheckedIconTintResource(@ColorRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCheckedIconTintResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's checked icon's color tint using the specified {@link
|
|
* android.content.res.ColorStateList}.
|
|
*
|
|
* @param checkedIconTint The tint color of this chip's checked icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_checkedIconTint
|
|
*/
|
|
public void setCheckedIconTint(@Nullable ColorStateList checkedIconTint) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCheckedIconTint(checkedIconTint);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's show motion spec.
|
|
*
|
|
* @see #setShowMotionSpec(MotionSpec)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_showMotionSpec
|
|
*/
|
|
@Nullable
|
|
public MotionSpec getShowMotionSpec() {
|
|
return chipDrawable != null ? chipDrawable.getShowMotionSpec() : null;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's show motion spec using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's show motion spec.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_showMotionSpec
|
|
*/
|
|
public void setShowMotionSpecResource(@AnimatorRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setShowMotionSpecResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's show motion spec.
|
|
*
|
|
* @param showMotionSpec This chip's show motion spec.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_showMotionSpec
|
|
*/
|
|
public void setShowMotionSpec(@Nullable MotionSpec showMotionSpec) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setShowMotionSpec(showMotionSpec);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's hide motion spec.
|
|
*
|
|
* @see #setHideMotionSpec(MotionSpec)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_hideMotionSpec
|
|
*/
|
|
@Nullable
|
|
public MotionSpec getHideMotionSpec() {
|
|
return chipDrawable != null ? chipDrawable.getHideMotionSpec() : null;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's hide motion spec using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's hide motion spec.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_hideMotionSpec
|
|
*/
|
|
public void setHideMotionSpecResource(@AnimatorRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setHideMotionSpecResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's hide motion spec.
|
|
*
|
|
* @param hideMotionSpec This chip's hide motion spec.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_hideMotionSpec
|
|
*/
|
|
public void setHideMotionSpec(@Nullable MotionSpec hideMotionSpec) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setHideMotionSpec(hideMotionSpec);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's start padding.
|
|
*
|
|
* @see #setChipStartPadding(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipStartPadding
|
|
*/
|
|
public float getChipStartPadding() {
|
|
return chipDrawable != null ? chipDrawable.getChipStartPadding() : 0;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's start padding using a resource id.
|
|
*
|
|
* @param id The resource id of this chip's start padding.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipStartPadding
|
|
*/
|
|
public void setChipStartPaddingResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipStartPaddingResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's start padding.
|
|
*
|
|
* @param chipStartPadding This chip's start padding.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipStartPadding
|
|
*/
|
|
public void setChipStartPadding(float chipStartPadding) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipStartPadding(chipStartPadding);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the start padding for this chip's icon.
|
|
*
|
|
* @see #setIconStartPadding(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_iconStartPadding
|
|
*/
|
|
public float getIconStartPadding() {
|
|
return chipDrawable != null ? chipDrawable.getIconStartPadding() : 0;
|
|
}
|
|
|
|
/**
|
|
* Sets the start padding for this chip's icon using a resource id.
|
|
*
|
|
* @param id The resource id for the start padding of this chip's icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_iconStartPadding
|
|
*/
|
|
public void setIconStartPaddingResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setIconStartPaddingResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's icon start padding.
|
|
*
|
|
* @param iconStartPadding The start padding of this chip's icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_iconStartPadding
|
|
*/
|
|
public void setIconStartPadding(float iconStartPadding) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setIconStartPadding(iconStartPadding);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the end padding for this chip's icon.
|
|
*
|
|
* @see #setIconEndPadding(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_iconEndPadding
|
|
*/
|
|
public float getIconEndPadding() {
|
|
return chipDrawable != null ? chipDrawable.getIconEndPadding() : 0;
|
|
}
|
|
|
|
/**
|
|
* Sets the end padding for this chip's icon using a resource id.
|
|
*
|
|
* @param id The resource id for the end padding of this chip's icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_iconEndPadding
|
|
*/
|
|
public void setIconEndPaddingResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setIconEndPaddingResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the end padding for this chip's icon.
|
|
*
|
|
* @param iconEndPadding The end padding of this chip's icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_iconEndPadding
|
|
*/
|
|
public void setIconEndPadding(float iconEndPadding) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setIconEndPadding(iconEndPadding);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the start padding for this chip's text.
|
|
*
|
|
* @see #setTextStartPadding(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_textStartPadding
|
|
*/
|
|
public float getTextStartPadding() {
|
|
return chipDrawable != null ? chipDrawable.getTextStartPadding() : 0;
|
|
}
|
|
|
|
/**
|
|
* Sets the start padding for this chip's text using a resource id.
|
|
*
|
|
* @param id The resource id for the start padding of this chip's text.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_textStartPadding
|
|
*/
|
|
public void setTextStartPaddingResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setTextStartPaddingResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the start padding for this chip's text.
|
|
*
|
|
* @param textStartPadding The start padding of this chip's text.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_textStartPadding
|
|
*/
|
|
public void setTextStartPadding(float textStartPadding) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setTextStartPadding(textStartPadding);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the end padding for this chip's text.
|
|
*
|
|
* @see #setTextEndPadding(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_textEndPadding
|
|
*/
|
|
public float getTextEndPadding() {
|
|
return chipDrawable != null ? chipDrawable.getTextEndPadding() : 0;
|
|
}
|
|
|
|
/**
|
|
* Sets the end padding for this chip's text using a resource id.
|
|
*
|
|
* @param id The resource id for the end padding of this chip's text.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_textEndPadding
|
|
*/
|
|
public void setTextEndPaddingResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setTextEndPaddingResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the end padding for this chip's text.
|
|
*
|
|
* @param textEndPadding The end padding of this chip's text.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_textStartPadding
|
|
*/
|
|
public void setTextEndPadding(float textEndPadding) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setTextEndPadding(textEndPadding);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the start padding for this chip's close icon.
|
|
*
|
|
* @see #setCloseIconStartPadding(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconStartPadding
|
|
*/
|
|
public float getCloseIconStartPadding() {
|
|
return chipDrawable != null ? chipDrawable.getCloseIconStartPadding() : 0;
|
|
}
|
|
|
|
/**
|
|
* Sets the start padding for this chip's close icon using a resource id.
|
|
*
|
|
* @param id The resource id for the start padding of this chip's close icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconStartPadding
|
|
*/
|
|
public void setCloseIconStartPaddingResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCloseIconStartPaddingResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the start padding for this chip's close icon.
|
|
*
|
|
* @param closeIconStartPadding The start padding of this chip's close icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconStartPadding
|
|
*/
|
|
public void setCloseIconStartPadding(float closeIconStartPadding) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCloseIconStartPadding(closeIconStartPadding);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the end padding for this chip's close icon.
|
|
*
|
|
* @see #setCloseIconEndPadding(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconEndPadding
|
|
*/
|
|
public float getCloseIconEndPadding() {
|
|
return chipDrawable != null ? chipDrawable.getCloseIconEndPadding() : 0;
|
|
}
|
|
|
|
/**
|
|
* Sets the end padding for this chip's close icon using a resource id.
|
|
*
|
|
* @param id The resource id for the end padding of this chip's close icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconEndPadding
|
|
*/
|
|
public void setCloseIconEndPaddingResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCloseIconEndPaddingResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the end padding for this chip's close icon.
|
|
*
|
|
* @param closeIconEndPadding The end padding of this chip's close icon.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_closeIconEndPadding
|
|
*/
|
|
public void setCloseIconEndPadding(float closeIconEndPadding) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setCloseIconEndPadding(closeIconEndPadding);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns this chip's end padding.
|
|
*
|
|
* @see #setChipEndPadding(float)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipEndPadding
|
|
*/
|
|
public float getChipEndPadding() {
|
|
return chipDrawable != null ? chipDrawable.getChipEndPadding() : 0;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's end padding using a resource id.
|
|
*
|
|
* @param id The resource id for this chip's end padding.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipEndPadding
|
|
*/
|
|
public void setChipEndPaddingResource(@DimenRes int id) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipEndPaddingResource(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's end padding.
|
|
*
|
|
* @param chipEndPadding This chip's end padding.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_chipEndPadding
|
|
*/
|
|
public void setChipEndPadding(float chipEndPadding) {
|
|
if (chipDrawable != null) {
|
|
chipDrawable.setChipEndPadding(chipEndPadding);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns whether this chip will expand its bounds (if needed) to meet the minimum touch target
|
|
* size.
|
|
*
|
|
* @see #setEnsureMinTouchTargetSize(boolean)
|
|
* @attr ref com.google.android.material.R.styleable#Chip_ensureMinTouchTargetSize
|
|
*/
|
|
public boolean shouldEnsureMinTouchTargetSize() {
|
|
return ensureMinTouchTargetSize;
|
|
}
|
|
|
|
/**
|
|
* Sets whether this chip should expand its bounds (if needed) to meet the minimum touch target
|
|
* size.
|
|
*
|
|
* @param flag Whether this chip should meet the min touch target size.
|
|
* @attr ref com.google.android.material.R.styleable#Chip_ensureMinTouchTargetSize
|
|
*/
|
|
public void setEnsureMinTouchTargetSize(boolean flag) {
|
|
ensureMinTouchTargetSize = flag;
|
|
ensureAccessibleTouchTarget(minTouchTargetSize);
|
|
}
|
|
|
|
/**
|
|
* Extends the touch target of this chip using a {@link InsetDrawable} if chip's intrinsic width /
|
|
* height is smaller than the {@code minTargetPx}.
|
|
*
|
|
* @param minTargetPx minimum touch target size in pixel
|
|
* @return whether the background was changed
|
|
*/
|
|
public boolean ensureAccessibleTouchTarget(@Dimension int minTargetPx) {
|
|
minTouchTargetSize = minTargetPx;
|
|
if (!shouldEnsureMinTouchTargetSize()) {
|
|
if (insetBackgroundDrawable != null) {
|
|
removeBackgroundInset();
|
|
} else {
|
|
updateBackgroundDrawable();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int deltaHeight = Math.max(0, minTargetPx - chipDrawable.getIntrinsicHeight());
|
|
int deltaWidth = Math.max(0, minTargetPx - chipDrawable.getIntrinsicWidth());
|
|
|
|
if (deltaWidth <= 0 && deltaHeight <= 0) {
|
|
if (insetBackgroundDrawable != null) {
|
|
removeBackgroundInset();
|
|
} else {
|
|
updateBackgroundDrawable();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int deltaX = deltaWidth > 0 ? deltaWidth / 2 : 0;
|
|
int deltaY = deltaHeight > 0 ? deltaHeight / 2 : 0;
|
|
|
|
if (insetBackgroundDrawable != null) {
|
|
Rect padding = new Rect();
|
|
insetBackgroundDrawable.getPadding(padding);
|
|
if (padding.top == deltaY
|
|
&& padding.bottom == deltaY
|
|
&& padding.left == deltaX
|
|
&& padding.right == deltaX) {
|
|
updateBackgroundDrawable();
|
|
return true;
|
|
}
|
|
}
|
|
if (getMinHeight() != minTargetPx) {
|
|
setMinHeight(minTargetPx);
|
|
}
|
|
if (getMinWidth() != minTargetPx) {
|
|
setMinWidth(minTargetPx);
|
|
}
|
|
insetChipBackgroundDrawable(deltaX, deltaY, deltaX, deltaY);
|
|
updateBackgroundDrawable();
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Sets this chip's accessibility class name.
|
|
*
|
|
* @param className This chip's accessibility class name.
|
|
*/
|
|
public void setAccessibilityClassName(@Nullable CharSequence className) {
|
|
accessibilityClassName = className;
|
|
}
|
|
|
|
@Override
|
|
@NonNull
|
|
public CharSequence getAccessibilityClassName() {
|
|
if (!TextUtils.isEmpty(accessibilityClassName)) {
|
|
return accessibilityClassName;
|
|
} else if (isCheckable()) {
|
|
ViewParent parent = getParent();
|
|
if (parent instanceof ChipGroup && ((ChipGroup) parent).isSingleSelection()) {
|
|
return RADIO_BUTTON_ACCESSIBILITY_CLASS_NAME;
|
|
} else {
|
|
return BUTTON_ACCESSIBILITY_CLASS_NAME;
|
|
}
|
|
} else if (isClickable()) {
|
|
return BUTTON_ACCESSIBILITY_CLASS_NAME;
|
|
} else {
|
|
return GENERIC_VIEW_ACCESSIBILITY_CLASS_NAME;
|
|
}
|
|
}
|
|
|
|
private void removeBackgroundInset() {
|
|
if (insetBackgroundDrawable != null) {
|
|
insetBackgroundDrawable = null;
|
|
setMinWidth(0);
|
|
setMinHeight((int) getChipMinHeight());
|
|
updateBackgroundDrawable();
|
|
}
|
|
}
|
|
|
|
private void insetChipBackgroundDrawable(
|
|
int insetLeft, int insetTop, int insetRight, int insetBottom) {
|
|
insetBackgroundDrawable =
|
|
new InsetDrawable(chipDrawable, insetLeft, insetTop, insetRight, insetBottom);
|
|
}
|
|
}
|