Skip to content

[TextInputLayout] Exposed the style of the ExposedDropDownMenu #1566

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.RippleDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import androidx.core.view.ViewCompat;
Expand All @@ -57,7 +56,6 @@
import com.google.android.material.color.MaterialColors;
import com.google.android.material.internal.TextWatcherAdapter;
import com.google.android.material.shape.MaterialShapeDrawable;
import com.google.android.material.shape.ShapeAppearanceModel;
import com.google.android.material.textfield.TextInputLayout.AccessibilityDelegate;
import com.google.android.material.textfield.TextInputLayout.BoxBackgroundMode;
import com.google.android.material.textfield.TextInputLayout.OnEditTextAttachedListener;
Expand Down Expand Up @@ -144,7 +142,6 @@ public void onEditTextAttached(@NonNull TextInputLayout textInputLayout) {
AutoCompleteTextView autoCompleteTextView =
castAutoCompleteTextViewOrThrow(textInputLayout.getEditText());

setPopupBackground(autoCompleteTextView);
addRippleEffect(autoCompleteTextView);
setUpDropdownShowHideBehavior(autoCompleteTextView);
autoCompleteTextView.setThreshold(0);
Expand Down Expand Up @@ -184,8 +181,6 @@ public void onEndIconChanged(@NonNull TextInputLayout textInputLayout, int previ
private boolean dropdownPopupDirty = false;
private boolean isEndIconChecked = false;
private long dropdownPopupActivatedAt = Long.MAX_VALUE;
private StateListDrawable filledPopupBackground;
private MaterialShapeDrawable outlinedPopupBackground;
@Nullable private AccessibilityManager accessibilityManager;
private ValueAnimator fadeOutAnim;
private ValueAnimator fadeInAnim;
Expand All @@ -196,45 +191,15 @@ public void onEndIconChanged(@NonNull TextInputLayout textInputLayout, int previ

@Override
void initialize() {
float popupCornerRadius =
context
.getResources()
.getDimensionPixelOffset(R.dimen.mtrl_shape_corner_size_small_component);
float exposedDropdownPopupElevation =
context
.getResources()
.getDimensionPixelOffset(R.dimen.mtrl_exposed_dropdown_menu_popup_elevation);
int exposedDropdownPopupVerticalPadding =
context
.getResources()
.getDimensionPixelOffset(R.dimen.mtrl_exposed_dropdown_menu_popup_vertical_padding);
// Background for the popups of the outlined variation and for the filled variation when it is
// being displayed above the layout.
MaterialShapeDrawable roundedCornersPopupBackground =
getPopUpMaterialShapeDrawable(
popupCornerRadius,
popupCornerRadius,
exposedDropdownPopupElevation,
exposedDropdownPopupVerticalPadding);
// Background for the popup of the filled variation when it is being displayed below the layout.
MaterialShapeDrawable roundedBottomCornersPopupBackground =
getPopUpMaterialShapeDrawable(
0,
popupCornerRadius,
exposedDropdownPopupElevation,
exposedDropdownPopupVerticalPadding);

outlinedPopupBackground = roundedCornersPopupBackground;
filledPopupBackground = new StateListDrawable();
filledPopupBackground.addState(
new int[] {android.R.attr.state_above_anchor}, roundedCornersPopupBackground);
filledPopupBackground.addState(new int[] {}, roundedBottomCornersPopupBackground);

// For lollipop+, the arrow icon changes orientation based on dropdown popup, otherwise it
// always points down.
int drawableResId =
IS_LOLLIPOP ? R.drawable.mtrl_dropdown_arrow : R.drawable.mtrl_ic_arrow_drop_down;
textInputLayout.setEndIconDrawable(AppCompatResources.getDrawable(context, drawableResId));

if (textInputLayout.getEndIconDrawable() == null) {
// For lollipop+, the arrow icon changes orientation based on dropdown popup, otherwise it
// always points down.
int drawableResId =
IS_LOLLIPOP ? R.drawable.mtrl_dropdown_arrow : R.drawable.mtrl_ic_arrow_drop_down;
textInputLayout.setEndIconDrawable(AppCompatResources.getDrawable(context, drawableResId));
}

textInputLayout.setEndIconContentDescription(
textInputLayout.getResources().getText(R.string.exposed_dropdown_menu_content_description));
textInputLayout.setEndIconOnClickListener(
Expand Down Expand Up @@ -287,16 +252,11 @@ private void showHideDropdown(@Nullable AutoCompleteTextView editText) {
}
}

private void setPopupBackground(@NonNull AutoCompleteTextView editText) {
/*private void setPopupBackground(@NonNull AutoCompleteTextView editText) {
if (IS_LOLLIPOP) {
int boxBackgroundMode = textInputLayout.getBoxBackgroundMode();
if (boxBackgroundMode == TextInputLayout.BOX_BACKGROUND_OUTLINE) {
editText.setDropDownBackgroundDrawable(outlinedPopupBackground);
} else if (boxBackgroundMode == TextInputLayout.BOX_BACKGROUND_FILLED) {
editText.setDropDownBackgroundDrawable(filledPopupBackground);
}
editText.setDropDownBackgroundDrawable(popupBackground);
}
}
}*/

/* Add ripple effect to non editable layouts. */
private void addRippleEffect(@NonNull AutoCompleteTextView editText) {
Expand Down Expand Up @@ -410,21 +370,6 @@ public void onDismiss() {
}
}

private MaterialShapeDrawable getPopUpMaterialShapeDrawable(
float topCornerRadius, float bottomCornerRadius, float elevation, int verticalPadding) {
ShapeAppearanceModel shapeAppearanceModel =
ShapeAppearanceModel.builder()
.setTopLeftCornerSize(topCornerRadius)
.setTopRightCornerSize(topCornerRadius)
.setBottomLeftCornerSize(bottomCornerRadius)
.setBottomRightCornerSize(bottomCornerRadius)
.build();
MaterialShapeDrawable popupDrawable =
MaterialShapeDrawable.createWithElevationOverlay(context, elevation);
popupDrawable.setShapeAppearanceModel(shapeAppearanceModel);
popupDrawable.setPadding(0, verticalPadding, 0, verticalPadding);
return popupDrawable;
}

private boolean isDropdownPopupActive() {
long activeFor = System.currentTimeMillis() - dropdownPopupActivatedAt;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build.VERSION;
import androidx.annotation.StyleRes;
import androidx.appcompat.widget.AppCompatAutoCompleteTextView;
import androidx.appcompat.widget.ListPopupWindow;
import android.text.InputType;
Expand All @@ -41,6 +43,8 @@
import androidx.annotation.Nullable;
import com.google.android.material.internal.ManufacturerUtils;
import com.google.android.material.internal.ThemeEnforcement;
import com.google.android.material.shape.MaterialShapeDrawable;
import com.google.android.material.shape.ShapeAppearanceModel;

/**
* A special sub-class of {@link android.widget.AutoCompleteTextView} that is auto-inflated so that
Expand All @@ -60,6 +64,19 @@ public class MaterialAutoCompleteTextView extends AppCompatAutoCompleteTextView
@NonNull private final ListPopupWindow modalListPopup;
@Nullable private final AccessibilityManager accessibilityManager;
@NonNull private final Rect tempRect = new Rect();
private StateListDrawable popupBackground;
private int popupStartPadding;
private int popupTopPadding;
private int popupBottomPadding;
private int popupEndPadding;
private float popupElevation;
@StyleRes int popupShapeAppearanceResId;
@StyleRes int popupShapeAppearanceOverlayResId;
boolean enforceFlatTopCorners;

private static final int[] POPUP_ATTRS = {
android.R.attr.popupElevation
};

public MaterialAutoCompleteTextView(@NonNull Context context) {
this(context, null);
Expand Down Expand Up @@ -95,6 +112,15 @@ public MaterialAutoCompleteTextView(
}
}

TypedArray a =
context.obtainStyledAttributes(
attributeSet, POPUP_ATTRS, defStyleAttr, 0);
if (a.hasValue(0)) {
popupElevation = a.getDimension(0, 0);
}
a.recycle();
loadPopupAttributes(attributes);

accessibilityManager =
(AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);

Expand Down Expand Up @@ -127,9 +153,70 @@ public void onItemClick(AdapterView<?> parent, View selectedView, int position,
}
});

createPopupBackground();
setPopupBackground();
attributes.recycle();
}

private void loadPopupAttributes(@NonNull TypedArray a){

popupShapeAppearanceResId = a.getResourceId(R.styleable.MaterialAutoCompleteTextView_popupBackgroundShapeAppearance, 0);
popupShapeAppearanceOverlayResId =
a.getResourceId(R.styleable.MaterialAutoCompleteTextView_popupBackgroundShapeAppearanceOverlay, 0);

popupStartPadding = a.getDimensionPixelSize(R.styleable.MaterialAutoCompleteTextView_popupStartPadding, 0);
popupTopPadding = a.getDimensionPixelSize(R.styleable.MaterialAutoCompleteTextView_popupTopPadding, 0);
popupBottomPadding = a.getDimensionPixelSize(R.styleable.MaterialAutoCompleteTextView_popupBottomPadding, 0);
popupEndPadding = a.getDimensionPixelSize(R.styleable.MaterialAutoCompleteTextView_popupEndPadding, 0);

enforceFlatTopCorners = a.getBoolean(R.styleable.MaterialAutoCompleteTextView_enforceFlatTopCorners,false);
}

private void createPopupBackground() {

ShapeAppearanceModel popupShapeAppearanceModel = ShapeAppearanceModel.builder(
getContext(), popupShapeAppearanceResId, popupShapeAppearanceOverlayResId)
.build();

// Background for the popups of the outlined variation and for the filled variation when it is
// being displayed above the layout.
MaterialShapeDrawable defaultRoundedCornersPopupBackground =
createDefaultPopupMaterialShapeDrawable(popupShapeAppearanceModel);

MaterialShapeDrawable flatTopCornersPopupBackground = null;
popupBackground = new StateListDrawable();
if (enforceFlatTopCorners) {
ShapeAppearanceModel flatTopCornersShapeAppearanceModel =
ShapeAppearanceModel.builder(
getContext(), popupShapeAppearanceResId, popupShapeAppearanceOverlayResId)
.setTopLeftCornerSize(0)
.setTopRightCornerSize(0)
.build();

flatTopCornersPopupBackground =
createDefaultPopupMaterialShapeDrawable(flatTopCornersShapeAppearanceModel);

popupBackground.addState(
new int[] {android.R.attr.state_above_anchor}, defaultRoundedCornersPopupBackground);
popupBackground.addState(new int[] {}, flatTopCornersPopupBackground);
} else {
popupBackground.addState(new int[]{}, defaultRoundedCornersPopupBackground);
}
}

private MaterialShapeDrawable createDefaultPopupMaterialShapeDrawable(
ShapeAppearanceModel shapeAppearanceModel) {
MaterialShapeDrawable popupDrawable =
MaterialShapeDrawable.createWithElevationOverlay(getContext(), popupElevation);
popupDrawable.setShapeAppearanceModel(shapeAppearanceModel);
popupDrawable.setPadding(popupStartPadding, popupTopPadding, popupEndPadding, popupBottomPadding);
return popupDrawable;
}

private void setPopupBackground(){
setDropDownBackgroundDrawable(popupBackground);
}

@Override
public void showDropDown() {
if (accessibilityManager != null && accessibilityManager.isTouchExplorationEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@
<public name="passwordToggleTintMode" type="attr"/>

<public name="textInputLayoutFocusedRectEnabled" type="attr"/>
<public name="popupBackgroundShapeAppearance" type="attr" />
<public name="popupBackgroundShapeAppearanceOverlay" type="attr"/>
<public name="enforceFlatTopCorners" type="attr"/>
<public name="popupTopPadding" type="attr"/>
<public name="popupBottomPadding" type="attr"/>
<public name="popupStartPadding" type="attr"/>
<public name="popupEndPadding" type="attr"/>

<public name="Widget.Design.TextInputLayout" type="style"/>
<public name="Widget.MaterialComponents.TextInputLayout.FilledBox" type="style"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2019 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.
-->
<resources xmlns:tools="http://schemas.android.com/tools">

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,21 @@

<declare-styleable name="MaterialAutoCompleteTextView" parent="AppCompatAutoCompleteTextView">
<attr name="android:inputType"/>
<!-- Shape appearance style reference for DropDownMenu in MaterialAutoCompleteTextView. -->
<attr name="popupBackgroundShapeAppearance" format="reference" />
<!-- Shape appearance overlay style reference for DropDownMenu in MaterialAutoCompleteTextView.
To be used to augment attributes declared in the popupBackgroundShapeAppearance. -->
<attr name="popupBackgroundShapeAppearanceOverlay" format="reference"/>
<!-- Whether the flat top corners should be used in DropDownMenu -->
<attr name="enforceFlatTopCorners" format="boolean"/>
<!-- Top padding for DropDownMenu in MaterialAutoCompleteTextView. -->
<attr name="popupTopPadding" format="dimension"/>
<!-- Bottom padding for DropDownMenu in MaterialAutoCompleteTextView. -->
<attr name="popupBottomPadding" format="dimension"/>
<!-- Start padding for DropDownMenu in MaterialAutoCompleteTextView. -->
<attr name="popupStartPadding" format="dimension"/>
<!-- End padding for DropDownMenu in MaterialAutoCompleteTextView. -->
<attr name="popupEndPadding" format="dimension"/>
</declare-styleable>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,19 @@
<item name="android:textAppearance">?attr/textAppearanceSubtitle1</item>
<item name="android:dropDownVerticalOffset">@dimen/mtrl_exposed_dropdown_menu_popup_vertical_offset</item>
<item name="android:popupElevation" tools:ignore="NewApi">@dimen/mtrl_exposed_dropdown_menu_popup_elevation</item>
<item name="enforceFlatTopCorners">false</item>
<item name="popupBackgroundShapeAppearance">?attr/shapeAppearanceMediumComponent</item>
<item name="popupStartPadding">0dp</item>
<item name="popupTopPadding">@dimen/mtrl_exposed_dropdown_menu_popup_vertical_padding</item>
<item name="popupEndPadding">0dp</item>
<item name="popupBottomPadding">@dimen/mtrl_exposed_dropdown_menu_popup_vertical_padding</item>
</style>

<!-- Styles for the AutocompleteTextView to be used if an ExposedDropdownMenu style is being used. -->
<style name="Widget.MaterialComponents.AutoCompleteTextView.FilledBox" parent="Base.Widget.MaterialComponents.AutoCompleteTextView">
<item name="android:paddingTop">28dp</item>
<item name="android:paddingBottom">12dp</item>
<item name="enforceFlatTopCorners">true</item>
</style>

<style name="Widget.MaterialComponents.AutoCompleteTextView.FilledBox.Dense">
Expand Down Expand Up @@ -316,4 +323,23 @@
<item name="cornerSizeBottomRight">@dimen/mtrl_textinput_box_corner_radius_small</item>
</style>

<!--
<style name="Widget.MaterialComponents.ExposedDropdownMenu" parent="android:Widget"/>

<style name="Base.Widget.MaterialComponents.ExposedDropdownMenu.TextInputLayout" parent="Widget.MaterialComponents.ExposedDropdownMenu">
<item name="endIconDrawable">@drawable/mtrl_ic_arrow_drop_down</item>
<item name="popupVerticalPadding">@dimen/mtrl_exposed_dropdown_menu_popup_vertical_padding</item>
<item name="popupElevation">@dimen/mtrl_exposed_dropdown_menu_popup_elevation</item>
<item name="enforceFlatTopCorners">false</item>
<item name="shapeAppearance">?attr/shapeAppearanceMediumComponent</item>
</style>

<style name="Widget.MaterialComponents.ExposedDropdownMenu.TextInputLayout" parent="Base.Widget.MaterialComponents.ExposedDropdownMenu.TextInputLayout"/>

<style name="Widget.MaterialComponents.ExposedDropdownMenu.TextInputLayout.FilledBox">
<item name="enforceFlatTopCorners">true</item>
</style>

<style name="Widget.MaterialComponents.ExposedDropdownMenu.TextInputLayout.OutlinedBox"/>
-->
</resources>