Coder Social home page Coder Social logo

natario1 / autocomplete Goto Github PK

View Code? Open in Web Editor NEW
355.0 12.0 70.0 7.85 MB

Simple yet powerful autocomplete behavior for EditTexts, to avoid working with MultiAutoCompleteTextView APIs.

License: Apache License 2.0

Java 96.25% Kotlin 3.75%
autocomplete autocompletetextview android edittext popup android-ui

autocomplete's Introduction

Build Status Release Issues

Need support, consulting, or have any other business-related question? Feel free to get in touch.

Like the project, make profit from it, or simply want to thank back? Please consider sponsoring me!

Autocomplete

Simple yet powerful autocomplete behavior for EditTexts, to avoid working with MultiAutoCompleteTextView APIs.

implementation("com.otaliastudios:autocomplete:1.1.0")

To see it in action, take a look at the sample app in the sample module.

Usage

Autocomplete let's you add autocomplete behavior to any EditText of your choice. The workflow is as follows:

  • User types stuff into the edit text
  • AutocompletePolicy detects if typed text should trigger the autocomplete popup
  • If yes, the popup is shown
  • AutocompletePolicy extracts the query string from text. For instance, if text is Look at this @john, you might want to look for john users in your database
  • The query string is passed to AutocompletePresenter, that shows a list of items for that query
  • When some item is clicked, AutocompleteCallback is notified and tells whether the popup should be dismissed or not.

These are the base components of the library. You will build an Autocomplete instance passing each component you need, and that's it.

Autocomplete.on(editText)
  .with(autocompletePolicy)
  .with(autocompleteCallback)
  .with(autocompletePresenter)
  .with(popupBackground)
  .with(popupElevation)
  .build();

AutocompletePolicy

This is an interface that controls when to show/hide the popup. For simple cases (single autocompletion, with just one result, similar to AutocompleteTextView) you can leave this unspecified. The library will fallback to Autocomplete.SimplePolicy:

public class SimplePolicy implements AutocompletePolicy {
    @Override
    public boolean shouldShowPopup(Spannable text, int cursorPos) {
        return text.length() > 0;
    }

    @Override
    public boolean shouldDismissPopup(Spannable text, int cursorPos) {
        return text.length() == 0;
    }

    @Override
    public CharSequence getQuery(Spannable text) {
        return text;
    }

    @Override
    public void onDismiss(Spannable text) {}
}

For more complex situations, you can go implementing the methods:

  • shouldShowPopup(Spannable, int): called to understand whether the popup should be shown. For instance, you might want to trigger the popup only when the hashtag character '#' is typed.
  • shouldDismissPopup(Spannable, int): whether the popup should be hidden. The typical implementation would simply be to return !shouldShowPopup(), but that is up to you.
  • getQuery(Spannable): called to understand which part of the text should be passed to presenters. For instance, user might have typed @john but you want to query for john of course.
  • onDismiss(Spannable): this is the moment you should clear any span you have added to the text.

For the typical case of #hashtags, @usernames or whatever is triggered by a certain character, the library provides the CharPolicy class. It works as multi-autocomplete as well (e.g. for texts like you should see this @john @pete).

Autocomplete.on(editText)
  .with(new CharPolicy('#'))
  .with(autocompletePresenter)
  .build();

AutocompletePresenter

The presenter controls the display of items and their filtering when a query is selected. 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:

  • instantiateAdapter(): you should provide an adapter for the recycler here.
  • instantiateLayoutManager(): same for the layout manager. Defaults to vertical LinearLayoutManager. Complex managers might lead to UI inconsistencies.
  • getPopupDimensions(): return dimensions for the popup (width, height, maxWidth, maxHeight).
  • onViewShown(): you can perform further initialization on the recycler. The list now is about to be requested.
  • onQuery(CharSequence): we have a query from the edit text, as returned by AutocompletePolicy. This is the time to display a list of results corresponding to this filter.
  • onViewHidden(): release resources here if needed.

When a list item is clicked, please ensure you are calling dispatchClick(item) to dispatch the click event to the AutocompleteCallback, if present.

AutocompleteCallback

public interface AutocompleteCallback<T> {
    boolean onPopupItemClicked(Editable editable, T item);
    void onPopupVisibilityChanged(boolean shown);
}

AutocompleteCallback controls what happens when either the popup visibility changes, or when an item is selected. Typically at this point you might want to insert a String related to that item into the EditText.

This should be done by acting on the Editable interface that you should already know, using methods like editable.insert() or editable.replace().

Contributing

You are welcome to contribute with issues, PRs or suggestions.

autocomplete's People

Contributors

natario1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

autocomplete's Issues

update maven library version

I see that there were several changes in 2020 to the project but the maven repository still have the version 1.1.0 from 2018.

please update the binaries.
thanks

Background Image like in Screenshot

Can you please let me know how can I achieve this background of the "tag" from this screenshot:
image

In the sample code there is no background.
And with setSpan(new BackgroundColorSpan(..)) I get only a background color, but not the look and feel like in your sample screenshot.

Cannot use with RecyclerView

This is my RecyclerView Adapter code.

import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.EditText;

import com.otaliastudios.autocomplete.Autocomplete;
import com.otaliastudios.autocomplete.AutocompleteCallback;
import com.otaliastudios.autocomplete.AutocompletePresenter;

import java.util.ArrayList;

/**
 * Created by INTEL on 14-02-2018.
 */

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

    private static final String TAG = RecyclerViewAdapter.class.getSimpleName();
    private float elevation = 6f;
    private Drawable backgroundDrawable = new ColorDrawable(Color.WHITE);
    private AutocompletePresenter<String> presenter;
    private AutocompleteCallback<String> callback;

    RecyclerViewAdapter(Context context) {
        presenter = new SuggestionsPresenter(context);
        callback = new AutocompleteCallback<String>() {
            @Override
            public boolean onPopupItemClicked(Editable editable, String item) {
                editable.clear();
                editable.append(item);
                Log.v(TAG, "onPopupItemClicked");
                return true;
            }

            public void onPopupVisibilityChanged(boolean shown) {
                Log.v(TAG, "shown : "+shown);
            }
        };
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        holder.textView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View view, boolean b) {
                if(b){
                    Autocomplete.<String>on(holder.textView)
                            .with(elevation)
                            .with(backgroundDrawable)
                            .with(presenter)
                            .with(callback)
                            .build();
                }
            }
        });
    }

    @Override
    public int getItemCount() {
        return 30;
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        EditText textView;

        public ViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.editText);
        }
    }
}

When I run this, I am getting following screen shot.

When I type O I am getting following screen shot.
Image 1

When I type On I am getting following screen shot.
Image 2

When I choose TWENTY ONE I am getting following screen shot. If I choose TWENTY ONE again and again, again and again this popup is showing.
device-2018-02-16-102033

Don't know how to resolve this. Can you fix this ASAP please?

ScrollBars doesn't show

I @Overrided the getView() from RecyclerViewPresenter and I set the scrollbar vertically and fade enabled, but nothing shows up. How can I do to make the recyclerView to show scrollbars??

[Solved][Suggestion]Random crash when writing or clearing text too fast from edit text [Network Request]

I am calling Google maps places API with this library. right now writing text or clearing it too fast crashes the app. So I took some RXJava help to delay the output query and only get the latest query item from all inputs.

  • Library version: 1.1.0
  • Reproducible in official demo app: no (No network request present in demo)
  • Device / Android version: Any

Steps to reproduce the behavior:

  1. Call network request to fill up the recyclerview's arraylist.
  2. write text or clear it too fast from edit text
  3. See error

Expected behavior

As stated above, queries can be delayed and this can be configurable by user. I don't know if you want to edit your library for this or not. but if you can simply add a snippet in your ReadMe it would help new users a lot.

Logs

attaching file

Code Snippet to solve this

PublishSubject<String> queries = PublishSubject.create(); // PublishSubject provides functionality to add items to it dynamically
// BehaviorSubject will only provide last item
BehaviorSubject.fromPublisher(queries.toFlowable(BackpressureStrategy.LATEST))
        .sample(1000, TimeUnit.MILLISECONDS) // every 1000 Millisecond sample method will provide the last emmited item
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                getCompositeDisposable().add(d);
            }

            @Override
            public void onNext(String query) {
                // Call network request
            }

            @Override
            public void onError(Throwable e) {
                AppLog.loge(false, "EventFilterActivity.java", "onError", e);
            }

            @Override
            public void onComplete() {

            }
        });

// put this in RecyclerViewPresenter#onQuery        
queries.onNext(queryString);

Close popup

when the value is empty or null, I hope the popup will disappear.

In your sample when isEmpty inside public void onBindViewHolder. I want to close the popup. How to do it? please help me. many thanks :)

Help creating custom AutocompletePolicy

Hello

I am trying to create a custom policy where the popup appears after a keyword is typed in the EditText

Here's my current solution, but it isn't working 😕. Could you please check and tell me what's wrong with it? 🙏

public class KeywordPolicy implements AutocompletePolicy {
    @Override
    public boolean shouldShowPopup(Spannable text, int cursorPos) {
        return text.toString().startsWith("key");
    }

    @Override
    public boolean shouldDismissPopup(Spannable text, int cursorPos) {
        return text.toString().length() <= 0;
    }

    @Override
    public CharSequence getQuery(Spannable text) {
        return text.toString();
    }

    @Override
    public void onDismiss(Spannable text) {
    }
}

How can I use the cursor as anchor istead of the view?

When the EditText is too big, the popup is not shown properly, as you can see here:

2888403606721068496

Is there any way that I can use the cursor as the anchor? And one more doubt, can I choose if the popup will be shown above or below the anchor in some situations?

cannot resolve dispatchClick

I cannot call the dispatchClick() function from the onBindViewHolder of my adapter class. What else can I use to paste the selected item to the edittext?

Hi! - sponsoring Autocomplete development

Hi! 👋

I am Mattia, the main developer and maintainer here, and I have enabled the GitHub Sponsor button on this repository which will let you support the library development by sponsoring my open source work through GitHub itself.

In the last years, I have spent countless unpaid hours on this and other projects, designing and developing tools that solve real problems, for everyone to use. I am very happy to know that companies of all sizes benefit from my work everyday.

GitHub is now offering you the opportunity to thank back with a sponsorship. For individuals, it could be a small amount. For companies that are powered by my tools, it could be a fairly small percentage of their revenue. In any case, your support will be greatly appreciated (and for bigger amounts, you get things like private support hours, or something else if you prefer).

https://github.com/sponsors/natario1

I will experiment leaving this as a pinned issue - for a while at least - since it's where people are most likely to see it. Sorry if this bothers you, and thank you all for your help.

Is it possible to add Autocomplete entries on the go?

I'm working on an app where users have to put people names on it. I want to let them put one of the suggested by autocompletion, but let them put names that aren't suggested. And, in this case, add this new name to the suggestion list.

Is that possible? I didn't manage myself to do it.

Thanks in advance!

Edit: It's in fact possible, putting an ArrayList inside RecyclerViewPresenter.

Show Suggestions Above EditText?

Iike WhatsApp I have edit text located at bottom of screen in bottom sheet.
when suggestions appears it shows behind keyboard below edit text.
I use Adjust Resize as Input method.
Can we control this or fix it and any suggestions i appreciate.
I use 1.1.0 by the way

RTL support

hey @natario1
first of all thanks for this awesome library
but now i find small issue
that library doesn't support rtl
so
is there anyway to fix it
thanks for all

How to show popup always above the EditText

I have an editText in the middle of the screen. I want to show the popup always above the editText. How to achieve it?
I have tried setting the height of the popup as larger than the bottom remaining space.This always does the trick.I want the height to wrap content and always remain above the editText.

Thanks.
Akash Rao

Sample app crashes on orientation change

FYI, the sample app crash when starting to type at the "Look for a single user" field and rotating the device while the popup is visible.

12-21 13:59:33.173 31972-31972/com.otaliastudios.sample E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.otaliastudios.sample, PID: 31972
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.otaliastudios.sample/com.otaliastudios.sample.MainActivity}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4699)
at android.app.ActivityThread.-wrap18(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1595)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:765)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
at android.widget.PopupWindow.invokePopup(PopupWindow.java:1433)
at android.widget.PopupWindow.showAsDropDown(PopupWindow.java:1284)
at android.support.v4.widget.PopupWindowCompat$PopupWindowCompatApi19Impl.showAsDropDown(PopupWindowCompat.java:114)
at android.support.v4.widget.PopupWindowCompat.showAsDropDown(PopupWindowCompat.java:218)
at com.otaliastudios.autocomplete.AutocompletePopup.show(AutocompletePopup.java:376)
at com.otaliastudios.autocomplete.Autocomplete.showPopup(Autocomplete.java:232)
at com.otaliastudios.autocomplete.Autocomplete.onTextChanged(Autocomplete.java:337)
at android.widget.TextView.sendOnTextChanged(TextView.java:9364)
at android.widget.TextView.setText(TextView.java:5397)
at android.widget.TextView.setText(TextView.java:5250)
at android.widget.EditText.setText(EditText.java:113)
at android.widget.TextView.setText(TextView.java:5207)
at android.widget.TextView.onRestoreInstanceState(TextView.java:5082)
at android.view.View.dispatchRestoreInstanceState(View.java:17706)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3751)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3751)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3751)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3751)
at android.view.View.restoreHierarchyState(View.java:17684)
at com.android.internal.policy.PhoneWindow.restoreHierarchyState(PhoneWindow.java:2131)
at android.app.Activity.onRestoreInstanceState(Activity.java:1102)
at android.app.Activity.performRestoreInstanceState(Activity.java:1057)
at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1260)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2751)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856) 
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4699) 
at android.app.ActivityThread.-wrap18(Unknown Source:0) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1595) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:164) 
at android.app.ActivityThread.main(ActivityThread.java:6494) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 

Change width of the dropdown dialog

I added an email field on the drop-down. When the email is too long, it goes to the 2nd line with is not totally visible. Is it possible to make the drop-down dialog width wrap-content so that it can show it in one line only and increase the width as required?

Need a sample app

I've having trouble trying to use the library, even with the current documentation. A sample app
with examples similar to the ones shown on the animation would be nice

Bintray Shutting Down May 2021 -- Host artifacts elsewhere?

Hi @natario1!

Recently JFrog (which owns Bintray/JCenter) announced that they're sunsetting Bintray/JCenter - the last day to access these repositories will be May 2021. https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/

I know a lot of tooling goes into artifact upload to a repository, so I wanted to throw a signal flare up now so nobody is caught by surprise on May 1.

It looks like this tool simplifies the process of moving to MavenCentral: https://github.com/martinbonnin/vespene

How to implement chip view in EditText

How do I?

Hi, there!
Thanks for this amazing lib!
Screen Shot 2022-11-30 at 13 15 22

I notice that in the gif images, there are some chip views in the EditText. Any clue to achieve that?

Version used

Library version.

new logo/icon

Hi, I am a graphic designer, I want to help others in graphic design.

After I reviewed your project, you have no logo on this project. Therefore I want to contribute to this project by creating a new logo / icon. what do you think?

For # Hashtag, it is not working.

When i try with other CharPolicy like '@' or '<' it was working.
when i try with '#', initial popup showing, then not returning any char. :(

i found something wrong with public CharSequence getQuery(@nonnull Spannable text) {}

Didn't find class "android.support.v4.view.ViewCompat"

Describe the bug

Please add a clear description of what the bug is, and fill the list below.

  • Library version: 1.1.0
  • Reproducible in official demo app: no
  • Device / Android version: Pixel, API 30

To Reproduce

Steps to reproduce the behavior, possibly in the demo app:
CLick on edittext and tap any character on keyboard

Expected behavior

show popup

Actual

Crash

Didn't find class "android.support.v4.view.ViewCompat"

Async example

Hi, I'm having trouble to get it working with async load of autocompletions.

I think it would be nice if you could provide an example of an async Presenter with a progress / failure management. This join the request from #12

Bug when call popupWindow.showAsDropDown() on API 24.

Hello,

On your AutocompletePopup class, on line 376, when you call popupWindow.showAsDropDown() funcion,
the is a bug on Api 24, you should replace the current line to :

``
// API 24 PopupWindow bug fix

    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
        int[] a = new int[2];
       getAnchorView().getLocationInWindow(a);
        popupWindow.showAtLocation(context.getWindow().getDecorView(), Gravity.NO_GRAVITY, a[0], a[1] + anchorView.getHeight());

    } else {
        popupWindow.showAsDropDown(getAnchorView());
    }

``

Best regards
José Martins

Move to maven or other repository

Problem to be addressed

jCenter() will be shut down

Describe the solution you'd like

Would be really good if you can move the library to maven or another repository and we get rid of jCenter()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.