From dd3681f5ee1f87e271ff0c31eec60ae1b89cfd4f Mon Sep 17 00:00:00 2001 From: Mattia Iavarone Date: Thu, 19 Apr 2018 18:55:18 +0200 Subject: [PATCH] Don't create popup if detached from window. Bump version (#16) --- README.md | 9 +++++- autocomplete/build.gradle | 2 +- .../autocomplete/Autocomplete.java | 32 +++++++++---------- .../autocomplete/AutocompletePopup.java | 7 ++-- sample/build.gradle | 6 ++-- 5 files changed, 32 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 2f986c0..339a9f1 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Simple yet powerful autocomplete behavior for `EditText`s, to avoid working with `MultiAutoCompleteTextView` APIs. ```groovy -implementation 'com.otaliastudios:autocomplete:1.0.3' +implementation 'com.otaliastudios:autocomplete:1.1.0' ``` To see it in action, take a look at the sample app in the `sample` module. @@ -107,6 +107,13 @@ The presenter controls the display of items and their filtering when a query is It is recommended to extend `RecyclerViewPresenter`, which shows a `RecyclerView` list. For more complex needs, look at the base `AutocompletePresenter` class and its comments. +**Note**: starting from **1.1.0**, if the view returned by `AutocompletePresenter` has 0 height, this is read as a +no-data signal and the popup will be dismissed. Not doing so would cause drawing artifacts, by +leaving the popup in a weird state. + +If you are performing asynchronous loading, make sure to give some height to your view, +for example by returning a 'loading' item from your adapter, or adding vertical padding. + #### RecyclerViewPresenter This automatically inflates a `RecyclerView` into the popup. Some relevant callbacks to be overriden: diff --git a/autocomplete/build.gradle b/autocomplete/build.gradle index 7a4f9b0..8fdf264 100644 --- a/autocomplete/build.gradle +++ b/autocomplete/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' // Required by bintray -version = '1.0.3' +version = '1.1.0' group = 'com.otaliastudios' android { diff --git a/autocomplete/src/main/java/com/otaliastudios/autocomplete/Autocomplete.java b/autocomplete/src/main/java/com/otaliastudios/autocomplete/Autocomplete.java index c39df76..11f9c93 100644 --- a/autocomplete/src/main/java/com/otaliastudios/autocomplete/Autocomplete.java +++ b/autocomplete/src/main/java/com/otaliastudios/autocomplete/Autocomplete.java @@ -6,6 +6,7 @@ import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; +import android.support.annotation.NonNull; import android.text.Editable; import android.text.Selection; import android.text.SpanWatcher; @@ -173,24 +174,31 @@ private Autocomplete(Builder builder) { // Set up popup popup = new AutocompletePopup(source.getContext()); - popup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); popup.setAnchorView(source); popup.setGravity(Gravity.START); popup.setModal(false); popup.setBackgroundDrawable(builder.backgroundDrawable); popup.setElevation(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, builder.elevationDp, source.getContext().getResources().getDisplayMetrics())); + // popup dimensions AutocompletePresenter.PopupDimensions dim = this.presenter.getPopupDimensions(); popup.setWidth(dim.width); popup.setHeight(dim.height); popup.setMaxWidth(dim.maxWidth); popup.setMaxHeight(dim.maxHeight); + // Fire visibility events popup.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { + lastQuery = "null"; if (callback != null) callback.onPopupVisibilityChanged(false); + boolean saved = block; + block = true; + policy.onDismiss(source.getText()); + block = saved; + presenter.hideView(); } }); @@ -202,14 +210,14 @@ public void onDismiss() { presenter.registerClickProvider(new AutocompletePresenter.ClickProvider() { @Override public void click(T item) { - AutocompleteCallback c = Autocomplete.this.callback; - EditText e = Autocomplete.this.source; - if (c == null) return; - boolean b = block; + AutocompleteCallback callback = Autocomplete.this.callback; + EditText edit = Autocomplete.this.source; + if (callback == null) return; + boolean saved = block; block = true; - boolean dismiss = c.onPopupItemClicked(e.getText(), item); + boolean dismiss = callback.onPopupItemClicked(edit.getText(), item); if (dismiss) dismissPopup(); - block = b; + block = saved; } }); @@ -244,7 +252,7 @@ public void setSoftInputMode(int mode) { * * @param query query text. */ - public void showPopup(CharSequence query) { + public void showPopup(@NonNull CharSequence query) { if (isPopupShowing() && lastQuery.equals(query.toString())) return; lastQuery = query.toString(); @@ -267,16 +275,8 @@ public void showPopup(CharSequence query) { * To control when this is called, provide a good implementation of {@link AutocompletePolicy}. */ public void dismissPopup() { - lastQuery = "null"; if (isPopupShowing()) { - log("dismissPopup: called, and popup is showing"); popup.dismiss(); - boolean b = block; - block = true; - policy.onDismiss(source.getText()); - block = b; - presenter.hideView(); - // Not calling onPopupVisibilityChanged. That is done with a OnDismissListener. } } diff --git a/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePopup.java b/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePopup.java index f12afd7..3e6c7a4 100644 --- a/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePopup.java +++ b/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePopup.java @@ -174,7 +174,7 @@ void setAnimationStyle(@StyleRes int animationStyle) { * Returns the view that will be used to anchor this popup. * @return The popup's anchor view */ - @Nullable View getAnchorView() { + View getAnchorView() { return mAnchorView; } @@ -183,7 +183,7 @@ void setAnimationStyle(@StyleRes int animationStyle) { * the anchor view when shown. * @param anchor The view to use as an anchor. */ - void setAnchorView(@Nullable View anchor) { + void setAnchorView(@NonNull View anchor) { mAnchorView = anchor; } @@ -294,8 +294,9 @@ void setOnDismissListener(PopupWindow.OnDismissListener listener) { * will recalculate the popup's size and position. */ void show() { - int height = buildDropDown(); + if (!ViewCompat.isAttachedToWindow(getAnchorView())) return; + int height = buildDropDown(); final boolean noInputMethod = isInputMethodNotNeeded(); int mDropDownWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; PopupWindowCompat.setWindowLayoutType(mPopup, mDropDownWindowLayoutType); diff --git a/sample/build.gradle b/sample/build.gradle index 2e92b96..cf441ea 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -23,7 +23,7 @@ android { } dependencies { - compile "com.android.support:appcompat-v7:$supportLibVersion" - compile "com.android.support:design:$supportLibVersion" - compile project(':autocomplete') + implementation "com.android.support:appcompat-v7:$supportLibVersion" + implementation "com.android.support:design:$supportLibVersion" + implementation project(':autocomplete') }