How to dynamically add suggestions to autocompletetextview with preserving character status along with images
ok try this:
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
AutoCompleteTextView actv = new AutoCompleteTextView(this);
actv.setThreshold(1);
String[] from = {"name"};
int[] to = {android.R.id.text1};
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_dropdown_item_1line, null, from, to) {
// required for Spanned data
@Override
public void bindView(View view, Context context, Cursor cursor) {
MyCursor c = (MyCursor) cursor;
TextView tv = (TextView) view;
tv.setText(c.getSpanned());
}
// required for Spanned data
@Override
public CharSequence convertToString(Cursor cursor) {
MyCursor c = (MyCursor) cursor;
return c.getSpanned();
}
};
FilterQueryProvider provider = new FilterQueryProvider() {
@Override
public Cursor runQuery(CharSequence constraint) {
if (constraint == null) {
return null;
}
MyCursor c = new MyCursor();
// fake web service responses
List<String> names = callFakeWebService(constraint);
int i = 0;
for (String name: names) {
SpannableStringBuilder ssb = new SpannableStringBuilder(name);
int start = name.indexOf(" ");
ForegroundColorSpan what = new ForegroundColorSpan(0xffff0000);
ssb.setSpan(what, start + 1, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
c.newRow().add(i++).add(name);
c.addSpanned(ssb);
}
return c;
}
// fake web service request
private List<String> callFakeWebService(CharSequence constraint) {
Log.d(TAG, "callFakeWebService for: " + constraint);
String[] namesArr = {
"Mark Smith",
"Monica Thompson",
"John White",
"Jane Brown"
};
String stringConstraint = constraint.toString().toLowerCase();
List<String> names = new ArrayList<String>();
for (int i = 0; i < namesArr.length; i++) {
String name = namesArr[i];
if (name.toLowerCase().startsWith(stringConstraint)) {
names.add(name);
}
}
return names;
}
};
adapter.setFilterQueryProvider(provider);
actv.setAdapter(adapter);
ll.addView(actv);
TextView tv = new TextView(this);
tv.setTextSize(32);
tv.setTextColor(0xffff0000);
tv.setText("type one of:\n mark,\n monica,\n john\n jane");
ll.addView(tv);
setContentView(ll);
where custom Cursor could look like this (it is minimalistic version supporting only one Spanned in a row):
static class MyCursor extends MatrixCursor {
private static final String[] NAMES = {BaseColumns._ID, "name"};
private ArrayList<Spanned> mSpannedList;
public MyCursor() {
super(NAMES);
mSpannedList = new ArrayList<Spanned>();
}
public void addSpanned(Spanned s) {
mSpannedList.add(s);
}
public Spanned getSpanned() {
return mSpannedList.get(mPos);
}
}
EDIT with no Spanned text:
AutoCompleteTextView actv = new AutoCompleteTextView(this);
actv.setThreshold(1);
final String[] from = {BaseColumns._ID, "name", "artist", "title"};
int[] to = {R.id.list_image, R.id.textView1, R.id.textView2, R.id.textView3};
final SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.list_row, null, from, to);
adapter.setStringConversionColumn(1);
ViewBinder viewBinder = new ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if (columnIndex == 0) {
ImageView iv = (ImageView) view;
Bitmap bitmap = cursor.getExtras().getParcelable("image");
if (bitmap != null) {
iv.setImageBitmap(bitmap);
}
return true;
}
return false;
}
};
adapter.setViewBinder(viewBinder);
FilterQueryProvider provider = new FilterQueryProvider() {
ExecutorService mPool = Executors.newCachedThreadPool();
Uri URI = Uri.parse("adapter://autocomplete");
public Cursor runQuery(CharSequence constraint) {
if (constraint == null) {
return null;
}
try {
return callWebService(constraint, from);
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
// here you make the web request
private Cursor callWebService(CharSequence constraint, String[] columnNames) throws JSONException {
Log.d("TAG", "callWebService for: " + constraint);
MatrixCursor cursor = new MyMatrixCursor(columnNames);
// TODO do real network request
// call web service here and keep the result in "jsonStr"
String jsonStr = "{\"ResultArray\":[{\"data\":{ \"sno\":\"sno1\", \"date\":\"2011-08-21 14:27:09\", \"user\":\"1\", \"link\":\"http://scm-l3.technorati.com/11/11/17/56749/google-docs-revision.jpg?t=20111117074048\", \"name\":\"Aa\" }},{\"data\":{ \"sno\":\"sno2\", \"date\":\"2011-08-21 14:28:09\", \"user\":\"2\", \"link\":\"http://kcclaveria.com/wp-content/uploads/2013/02/google-panda-penguin.jpg\", \"name\":\"Bb\" }}]}";
JSONObject json = new JSONObject(jsonStr);
JSONArray resultArray = json.getJSONArray("ResultArray");
int length = resultArray.length();
for (int i = 0; i < length; i++) {
JSONObject data = resultArray.getJSONObject(i).getJSONObject("data");
cursor.newRow().add(i)
.add(data.getString("name"))
.add(data.getString("user"))
.add(data.getString("sno"));
String link = data.getString("link");
// get cached Bundle based on "link" (use HashMap<String, Bundle>)
// or if new link initiate async request for getting the bitmap
// TODO implement HashMap caching
// new async request
Bundle extras = new Bundle();
try {
mPool.submit(new ImageRequest(link, extras));
} catch (MalformedURLException e) {
e.printStackTrace();
}
cursor.respond(extras);
}
cursor.setNotificationUri(getContentResolver(), URI);
return cursor;
}
class ImageRequest implements Runnable {
private URL mUrl;
private Bundle mExtra;
public ImageRequest(String link, Bundle extra) throws MalformedURLException {
mUrl = new URL(link);
mExtra = extra;
}
@Override
public void run() {
// TODO do real network request
// simulate network delay
Log.d(TAG, "getting " + mUrl);
try {
Thread.sleep(2000 + (long) (4000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
}
Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
mExtra.putParcelable("image", b);
getContentResolver().notifyChange(URI, null);
Log.d(TAG, "run got a bitmap " + b.getWidth() + "x" + b.getHeight());
}
}
};
adapter.setFilterQueryProvider(provider);
actv.setAdapter(adapter);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
setContentView(actv, params);
and the custom MatrixCursor:
class MyMatrixCursor extends MatrixCursor {
List<Bundle> mBundles = new ArrayList<Bundle>();
public MyMatrixCursor(String[] columnNames) {
super(columnNames);
}
@Override
public Bundle respond(Bundle extras) {
mBundles.add(extras);
return extras;
}
@Override
public Bundle getExtras() {
return mBundles.get(mPos);
}
}
Dynamically updating an AutoCompleteTextView adapter
This is how I update my AutoCompleteTextView:
String[] data = terms.toArray(new String[terms.size()]); // terms is a List<String>
ArrayAdapter<?> adapter = new ArrayAdapter<Object>(activity, android.R.layout.simple_dropdown_item_1line, data);
keywordField.setAdapter(adapter); // keywordField is a AutoCompleteTextView
if(terms.size() < 40) keywordField.setThreshold(1);
else keywordField.setThreshold(2);
Now of course, this is static and doesn't deal with an over-the-air suggestions but, I can also suggest you to notify adapter for the changes after you assign it to the AutoCompleteTextView:
adapter.notifyDataSetChanged();
Hope this helps.
-serkan
Android - AutoCompleteTextView wildcard suggestion
Okay here's how I made it work. Major props to pskink for the lead.
It's very similar to the code I have above, with some changes to make the runQuery
method work.
The same logic/thought pattern is used, only that I changed the runQuery
method. Read the comments for a walkthrough.
//create ACTV Here
AutoCompleteTextView search = (AutoCompleteTextView) findViewById(R.id.actvCatalogueSearch);
search.setThreshold(1);
//I don't know what these are for, honestly.
String[] from = { "name" };
int[] to = { android.R.id.text1 };
//create a simple cursorAdapter
SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_dropdown_item_1line, null, from, to, 0);
//again, I don't know what this is for
cursorAdapter.setStringConversionColumn(1);
//create the filter query provider
FilterQueryProvider provider = new FilterQueryProvider(){
@Override
public Cursor runQuery(CharSequence constraint) {
// TODO Auto-generated method stub
//I need to do this because my list items are in all caps
String constrain = (String) constraint;
constrain = constrain.toUpperCase();
if (constraint == null) {
return null;
}
//I'll be honest again, no clue what these lines do.
String[] columnNames = { Columns._ID, "name" };
MatrixCursor c = new MatrixCursor(columnNames);
try {
//here's what I do, I go though my Array (pdflist)
//when a list item contains the user input, I add that to the Matrix Cursor
//this matrix cursor will be returned and the contents will be displayed
for (int i = 0; i < pdflist.length; i++) {
if(pdflist[i].contains(constrain)){
c.newRow().add(i).add(pdflist[i]);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return c;
}
};
//use the filter query provider on the cursor adapter
cursorAdapter.setFilterQueryProvider(provider);
//finally, use the adapter on your ACTV
search.setAdapter(cursorAdapter);
It's a bit of a work but it gets the job done. Honestly, I'm a bit surprised that there's no "straightforward/intuitive" way of doing this. Something to the tune of just enabling/disabling something in your AutoCompleteTextView then it's done.
I guess we'll have to stick with this solution until further notice.
how to show suggestions of autocomplete Text Box contains with??
You need to extend the ArrayAdapter
that implements Filterable
.
Check this SO question and the answer: Filtering AutoCompleteTextView to show partial match
So your solution would be (the combination of question and answer):
public class CodesArrayAdapter extends ArrayAdapter implements Filterable{
List<String> allCodes;
List<String> originalCodes;
StringFilter filter;
public CodesArrayAdapter(Context context, int resource, List<String> keys) {
super(context, resource, keys);
allCodes=keys;
originalCodes=keys;
}
public int getCount() {
return allCodes.size();
}
public Object getItem(int position) {
return allCodes.get(position);
}
public long getItemId(int position) {
return position;
}
private class StringFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
String filterString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
final List<String> list = originalCodes;
int count = list.size();
final ArrayList<String> nlist = new ArrayList<String>(count);
String filterableString ;
for (int i = 0; i < count; i++) {
filterableString = list.get(i);
if (filterableString.toLowerCase().contains(filterString)) {
nlist.add(filterableString);
}
}
results.values = nlist;
results.count = nlist.size();
return results;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
allCodes = (ArrayList<String>) results.values;
notifyDataSetChanged();
}
}
@Override
public Filter getFilter()
{
return new StringFilter();
}
}
AutoCompleteTextView Text Filtering
So, I fixed the problem myself doing this. So, I use a normal BaseAdapter
and extend Filterable
So, for those that may need how to use RealmDB
with AutoCompleteTextView
there you go
public class LgasAutoCompleteAdapter extends BaseAdapter implements Filterable {
private static final String TAG = "LgasAutoComp";
private Context mContext;
private List<Lga> mResult = new ArrayList<>();
private LayoutInflater inflater;
public LgasAutoCompleteAdapter(Context mContext) {
this.mContext = mContext;
}
@Override
public int getCount() {
return mResult.size();
}
@Override
public Object getItem(int position) {
return mResult.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
if (inflater == null)
inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (view == null)
view = inflater.inflate(R.layout.item_baker_autocomplete, parent, false);
Lga lga = mResult.get(position);
TextView customerNameLabel = (TextView) view.findViewById(R.id.bakerName);
TextView bakerAddress = (TextView) view.findViewById(R.id.bakerAddress);
if (lga != null) {
if (customerNameLabel != null) {
// Log.i(MY_DEBUG_TAG, "getView Customer Name:"+customer.getName());
customerNameLabel.setText(lga.getName());
bakerAddress.setVisibility(View.GONE);
}
}
return view;
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
return null;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults filterResults) {
if (constraint != null) {
//String query = constraint.toString().toLowerCase();
mResult = filterStates(constraint.toString());
Log.e(TAG, ""+mResult.size());
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
}
@NonNull
private List<Lga> filterStates(String query) {
Realm mRealm = RealmUtils.getRealmInstance(mContext);
return mRealm.where(Lga.class)
.contains("name", query)
.or()
.beginsWith("name", query)
.findAll();
}
}
Related Topics
How to Use Putextra() and Getextra() For String Data
How to Start My App When the Phone Starts on Android
How to Handle Button Clicks Using the Xml Onclick Within Fragments
Android - Implementing Startforeground For a Service
Scrollview Vertical and Horizontal in Android
How to Increase Heap Size of an Android Application
How to Display Count of Notifications in App Launcher Icon
Difference Between Compilesdkversion and Targetsdkversion
What Does Android:Layout_Weight Mean
How to Convert a Drawable to a Bitmap
Is There an Addheaderview Equivalent For Recyclerview
Linear Layout and Weight in Android
How to Display a Toast from a Background Thread on Android
Converting a View to Bitmap Without Displaying It in Android
Getting an Issue While Checking the Dynamically Generated Checkbox Through List View