|
29 | 29 | import android.graphics.drawable.ColorDrawable;
|
30 | 30 | import android.graphics.drawable.Drawable;
|
31 | 31 | import android.graphics.drawable.RippleDrawable;
|
| 32 | +import android.os.Parcel; |
| 33 | +import android.os.Parcelable; |
32 | 34 | import androidx.appcompat.widget.AppCompatAutoCompleteTextView;
|
33 | 35 | import androidx.appcompat.widget.ListPopupWindow;
|
| 36 | +import android.text.Editable; |
34 | 37 | import android.text.InputType;
|
| 38 | +import android.text.TextUtils; |
| 39 | +import android.text.TextWatcher; |
35 | 40 | import android.util.AttributeSet;
|
36 | 41 | import android.view.View;
|
37 | 42 | import android.view.View.MeasureSpec;
|
@@ -83,6 +88,8 @@ public class MaterialAutoCompleteTextView extends AppCompatAutoCompleteTextView
|
83 | 88 | private int simpleItemSelectedColor;
|
84 | 89 | @Nullable private ColorStateList simpleItemSelectedRippleColor;
|
85 | 90 |
|
| 91 | + @Nullable private CharSequence selectedItem; |
| 92 | + |
86 | 93 | public MaterialAutoCompleteTextView(@NonNull Context context) {
|
87 | 94 | this(context, null);
|
88 | 95 | }
|
@@ -181,6 +188,23 @@ public void onItemClick(AdapterView<?> parent, View selectedView, int position,
|
181 | 188 | }
|
182 | 189 |
|
183 | 190 | attributes.recycle();
|
| 191 | + |
| 192 | + // TODO: Remove this workaround once the framework bug (b/202873898) is fixed. |
| 193 | + addTextChangedListener( |
| 194 | + new TextWatcher() { |
| 195 | + @Override |
| 196 | + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} |
| 197 | + |
| 198 | + @Override |
| 199 | + public void onTextChanged(CharSequence s, int start, int before, int count) {} |
| 200 | + |
| 201 | + @Override |
| 202 | + public void afterTextChanged(Editable s) { |
| 203 | + if (!TextUtils.equals(selectedItem, s)) { |
| 204 | + selectedItem = null; |
| 205 | + } |
| 206 | + } |
| 207 | + }); |
184 | 208 | }
|
185 | 209 |
|
186 | 210 | @Override
|
@@ -437,6 +461,55 @@ public CharSequence getHint() {
|
437 | 461 | return super.getHint();
|
438 | 462 | }
|
439 | 463 |
|
| 464 | + @Override |
| 465 | + public boolean getFreezesText() { |
| 466 | + // Always return false to handle the input text restoration by ourselves. This is required |
| 467 | + // to avoid the auto-completion from being updated when the view is recreated. |
| 468 | + return false; |
| 469 | + } |
| 470 | + |
| 471 | + @Override |
| 472 | + protected void replaceText(CharSequence text) { |
| 473 | + selectedItem = text; |
| 474 | + super.replaceText(text); |
| 475 | + } |
| 476 | + |
| 477 | + @Override |
| 478 | + public void setText(CharSequence text, boolean filter) { |
| 479 | + if (!filter) { |
| 480 | + // When filter is false, the text is updated by the selection from the auto-complete list. |
| 481 | + selectedItem = text; |
| 482 | + } |
| 483 | + super.setText(text, filter); |
| 484 | + } |
| 485 | + |
| 486 | + @Override |
| 487 | + @NonNull |
| 488 | + public Parcelable onSaveInstanceState() { |
| 489 | + Parcelable parcelable = super.onSaveInstanceState(); |
| 490 | + if (TextUtils.isEmpty(getText()) || !super.getFreezesText()) { |
| 491 | + return parcelable; |
| 492 | + } |
| 493 | + |
| 494 | + SavedState savedState = new SavedState(parcelable); |
| 495 | + // Remember if the current text is from the auto-complete selection. |
| 496 | + savedState.shouldRefreshAutoCompletion = (selectedItem == null); |
| 497 | + savedState.inputText = getText(); |
| 498 | + return savedState; |
| 499 | + } |
| 500 | + |
| 501 | + @Override |
| 502 | + public void onRestoreInstanceState(Parcelable state) { |
| 503 | + if (!(state instanceof SavedState)) { |
| 504 | + super.onRestoreInstanceState(state); |
| 505 | + return; |
| 506 | + } |
| 507 | + |
| 508 | + SavedState savedState = (SavedState) state; |
| 509 | + setText(savedState.inputText, savedState.shouldRefreshAutoCompletion); |
| 510 | + super.onRestoreInstanceState(savedState.getSuperState()); |
| 511 | + } |
| 512 | + |
440 | 513 | @Override
|
441 | 514 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
442 | 515 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
@@ -622,4 +695,40 @@ private boolean hasSelectedRippleColor() {
|
622 | 695 | return simpleItemSelectedRippleColor != null;
|
623 | 696 | }
|
624 | 697 | }
|
| 698 | + |
| 699 | + private static final class SavedState extends BaseSavedState { |
| 700 | + |
| 701 | + private boolean shouldRefreshAutoCompletion; |
| 702 | + private CharSequence inputText; |
| 703 | + |
| 704 | + public SavedState(Parcelable superState) { |
| 705 | + super(superState); |
| 706 | + } |
| 707 | + |
| 708 | + public SavedState(Parcel source) { |
| 709 | + super(source); |
| 710 | + shouldRefreshAutoCompletion = source.readInt() != 0; |
| 711 | + inputText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); |
| 712 | + } |
| 713 | + |
| 714 | + @Override |
| 715 | + public void writeToParcel(Parcel out, int flags) { |
| 716 | + super.writeToParcel(out, flags); |
| 717 | + out.writeInt(shouldRefreshAutoCompletion ? 1 : 0); |
| 718 | + TextUtils.writeToParcel(inputText, out, flags); |
| 719 | + } |
| 720 | + |
| 721 | + public static final Creator<SavedState> CREATOR = |
| 722 | + new Creator<SavedState>() { |
| 723 | + @Override |
| 724 | + public SavedState createFromParcel(Parcel source) { |
| 725 | + return new SavedState(source); |
| 726 | + } |
| 727 | + |
| 728 | + @Override |
| 729 | + public SavedState[] newArray(int size) { |
| 730 | + return new SavedState[size]; |
| 731 | + } |
| 732 | + }; |
| 733 | + } |
625 | 734 | }
|
0 commit comments