Prevent AutoCompleteTextView from showing the result in its own box - android

I am using an AutoCompleteTextView to show a list of items the user can select. When the users selects an item, this selected item fills a ListView just below the AutoCompleteTextView. So far so good.
The issue: after the selection of the item out of the AutoCompleteTextView, the AutoCompleteTextView body itself (this "text-box") gets filled up with some text, which is the SimpleCursorAdapter resource (the actual text showing up is: android.widget.SimpleCursorAdapter#4107d010).
What I wish to have: I want the AutoCompleteTextView to refresh and show no text in its own body so the user can immediately type in more text and select further items out of the drop-down list.
Could you please give me a hint how I could achieve that?
Added information:
Thank you Kyle. What I did was to extend SimpleCursorAdapter to SimpleCursorAdapterNoText. I then overridden convertToString() just like you said. I didn't change BindView because I read the documentation twice but I still don't understand what I should change in BindView. Any way - This didn't save the problem - I still get the same string in the AutoComplete. Here is my code:
#SuppressWarnings("deprecation")
private void populateListView()
{
// Get all of the notes from the database and create the item list
Cursor tournamentXCursor = mDbHelper.retrieveTrounamentX(mRowId);
startManagingCursor(tournamentXCursor);
// Create an array to specify the fields we want to display in the list (only name)
String[] from = new String[] {StournamentConstants.TblX.TBL_COLUMN_X_NAME};
// and an array of the fields we want to bind those fields to (in this case just name)
int[] to = new int[]{R.id.competitor_row};
// Now create an array adapter and set it to display using our row
SimpleCursorAdapterNoText tournamentX = new SimpleCursorAdapterNoText(this, R.layout.competitor_row, tournamentXCursor, from, to);
tournamentX.convertToString(tournamentXCursor);
setListAdapter(tournamentX);
}
Anyone has a clue what I am doing wrong?
EDITED:
This is my inherited SimpleCursorAdapter class
public class SimpleCursorAdapterNoText extends SimpleCursorAdapter
{
public SimpleCursorAdapterNoText(Context context, int layout, Cursor c,
String[] from, int[] to)
{
super(context, layout, c, from, to);
// TODO Auto-generated constructor stub
}
#Override
public CharSequence convertToString(Cursor cursor)
{
//Empty string so AutoComplete shows no text
return "";
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// TODO Auto-generated method stub
super.bindView(view, context, cursor);
}
}
I changed my calling code and eliminated
tournamentX.convertToString(tournamentXCursor);
I was convinced it is essential that I not only override it in my subclass but that I also use it in my calling code so the text inside the AutoComplete will be eliminated.
I am sag to say the this still didn't help - I keep on getting android.database.sqlite.SQLiteCursor#41377578 in the AutoCompleteBox just after I select one item off the AutoComplete selection list.
Thanks D.

If you simply want to clear the text when a user clicks on an item in the dropdown list, define the AutoComplete as a member variable and override it's setOnItemClickListener. Like this:
mAutoComplete.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mAutoComplete.setText("");
}
});

if you are using a simplecursoradapter to fill the textView, you will need to subclass it and override the following method. You will probably also have to override bindview.
#Override
public CharSequence convertToString (Cursor cursor){
return "";
}
You need to put the above inside your SimpleCursorAdapterNoText class, not call it from the top level code.
class extends SimpeCursorAdpaterNotText{
// ... whatever other code you have here
#Override
public CharSequence convertToString (Cursor cursor){
return "";
}
}

Related

Change Specific TextView Color in Listview

i Have Two Database
first one Contain All The Items, and the ListView Display it
and the second db contain the the Favorite item , [selected from the first database]
what i want is that when the listview display all the items
check if the item is already exist in Favoritelist then make that textview background RED for this item
i have this code that work fine
public static void ChangeMyFavoritesBG(){
for (int i = 0; i < Items.size(); i++) {
if(db.verification(Items.get(i).toString())){
try {
TextView favtextview = (TextView) listview.getChildAt(i-listview.getFirstVisiblePosition()).findViewById(R.id.item_name);
favtextview.setBackgroundResource(R.drawable.redcolor);
}catch (NullPointerException e) {
}}}}
db.verification check if item exist in favorites database
if true . then it should change the background of this item to red
this code work fine but only if i put it in button click
i need to make the code work automatically
but if i made it start automatically when the activity is loaded i get NullPointer Error
i guess because the function ChangeMyFavoritesBG(); work before the listview display items
any idea guys? and sorry for my bad english
Do this control inside the getView(int position, View convertView, ViewGroup parent) method of the Adapter used by the listView.
If your favorite is not currently visible in the ListView then getChildAt() will return null.
You are looping over all items in the list view and my guess is that it holds more items than can fit on the screen. When your favorite item is one of them then this fragment of your code
listview.getChildAt(i-listview.getFirstVisiblePosition())
will return null. And that will cause the NullPointerException when you call findViewById(R.id.item_name) on it.
Just add a check for null on the result of getChildAt(). If it is null then do nothing, if it is non-null then call the second part. This will protect against the exception when your favorite item is not on the screen, and will allow it to be colored red when your favorite is visible on the screen.
update
My apologies, I read to quickly and misunderstood your problem to be about the NullPointerException but you say that your code works fine when you call it from a button click handler but not when you call it automatically at start-up.
You are right, the ListView does not yet have any items loaded when you are still in onCreate(). You can add a delay before running you code. The following works for me:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
// initialize the ListView with data for the list items. (I'm using a string array in this
// example. You are loading it from a database table, but that is the same in principle.)
ListAdapter adapter = new ArrayAdapter<String>(this, R.layout.item_list, R.id.item_name, Items);
ListView listview = (ListView) findViewById(R.id.listview);
listview.setAdapter(adapter);
// ask the system to wait before setting the background color of the favorite item so that
// the ListView has time to load the items.
final int DELAY_IN_MILLISECONDS = 100;
listview.postDelayed(new Runnable() {
#Override
public void run() {
ChangeMyFavoritesBG();
}
}, DELAY_IN_MILLISECONDS);
}
As you can see in the above example, after initializing the ListView, you ask the system to wait 100 milliseconds before calling ChangeMyFavoritesBG(). Hopefully that is enough time to load the items from the database into the ListView. If it is not enough time then you can, of course, use a longer delay.
The alternative
The above should work, but to be honest I would not write it this way. The above code is very brittle because it depends on the timing of how long it takes to load the items. I recommend that you put your background coloring into a customized adapter.
Because you want the items displayed in a customized way -- you want them to have a red background when it is the favorite one -- you should use a customized adapter. Override the bindView() function to make the background red when it is the favorite one or give it a normal background when it is not the favorite.
I don't know how you currently get the items from the database into your ListView, but inheriting from SimpleCursorAdaptor would work pretty well.
public class FavoritesItemAdapter extends SimpleCursorAdapter {
public FavoritesItemAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
super.bindView(view, context, cursor);
// read the name from the database
int nameColumnIndex = cursor.getColumnIndexOrThrow("name");
String name = cursor.getString(nameColumnIndex);
// write the name to the TextView
TextView nameText = (TextView) view.findViewById(R.id.item_name);
nameText.setText(name);
// set the background to normal or to red, depending on if it is the favorite one or not
boolean isFavorite = db_verification(name);
if (isFavorite) {
nameText.setBackgroundResource(R.drawable.redcolor);
} else {
nameText.setBackgroundResource(android.R.color.transparent);
}
}
public boolean db_verification(String name) {
// this is a stub. You must use your own code here
return name.equals("the favorite one");
}
}
You can then throw away ChangeMyFavoritesBG() and initialize your ListView with the adapter in onCreate() like this.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
Cursor cursor = readItemsFromDatabase();
String[] from = new String[] { "name_column" }; // mapping from database column name ...
int[] to = new int[] { R.id.item_name }; // ... to View ID in the item's layout.
FavoritesItemAdapter adapter = new FavoritesItemAdapter(this, R.layout.item_list, cursor, from, to, 0);
ListView listview = (ListView) findViewById(R.id.listview);
listview.setAdapter(adapter);
}
Good luck!

Convert a selection in Android Autocomplete to a String

I have just implemented an autocompletion for a textfield using an online webservice, based on this answer on Stackoverflow:
ArrayAdapter is updated late from Webservice in AutoCompleteTextAdapter
Using an ArrayAdapter<User> implements Filterable, I have managed that the autocompletion suggests me entries as intended.
User is a Java Bean that contains information which is presented in the suggestion (age, name, ...).
When I select a suggestion, the Autocomplete field is filled with the 'wrong' data - using the toString()method, instead of the 'name' property of the bean.
My Question is: Can I override (in the Adapter) a method which will allow me to specify how to convert the bean so that the correct property is returned for the AutoCompleteTextView?
(Ideally, User.toString() should not be changed)
Thx!
There is no need subclassing AutoCompleteTextViewand override the convertSelectionToStringmethod. The same thing is achievable by overriding the convertResultToStringmethod in your custom Filter in (your already subclassed) ArrayAdapter.
I had the same problem: custom objects in my ArrayAdapter whose toString() implementation wasn't something I could control. I implemented the method like this:
// In custom Filter implementation
#Override
public CharSequence convertResultToString(Object result) {
if(result instanceof MyCustomClass) {
return ((MyCustomClass) result).getAttribute("name");
}
return super.convertResultToString(result);
}
The search results depend on what the data's toString() returns. In your case you need to return name field in the toString() implementation.
I have found another way:
The method convertSelectionToString(Object selectedItem) in AutoCompleteTextView can be overridden by subclasses to allow for custom conversions. This way, no adjustment to the toString() method is required.
This - it seems to me - has the advantage that the Filter can return not just a list of Strings but a list of custom objects, which can be used by getView(int position, View convertView, ViewGroup parent) of the adapter to construct "richer" suggestions.
The obvious disadvantage is that it requires subclassing AutoCompleteTextView for every Filterresult type whose toString() method shall not be modified.
#Override
protected CharSequence convertSelectionToString(Object selectedItem) {
if(selectedItem instanceof User){
User u = (User) selectedItem;
return u.getUsername();
} else {
return super.convertSelectionToString(selectedItem);
}
}
Any comments on this?
If you subclass your own adapter from SimpleCursorAdapter, you can set a CursorToStringConverter on the Adapter in the constructor.
private class AutoCompleteAdapter extends SimpleCursorAdapter {
public AutoCompleteAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
/* Other setup code here */
setCursorToStringConverter(new CursorToStringConverter() {
#Override
public CharSequence convertToString(Cursor item) {
return item.getString(item.getColumnIndex(DESIRED_COLUMN_NAME));
}
});
}
}

Android: Display HTML formatted text in a ListView when loaded from database

I have an SQLite database of items where some of them contain basic HTML such as b and sub tags. I've bound the table to a ListView using a SimpleCursorAdapter. Is there a way to make the ListView format the HTML tags so it displays properly?
It seems like the way forward is to get the Cursor to deliver SpannedStrings but I can't work out how to do that.
Thanks Ian, this is my final adapter code:
private class HtmlCursorAdapter extends SimpleCursorAdapter {
public HtmlCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
}
#Override
public void setViewText (TextView view, String text) {
view.setText(Html.fromHtml(text),BufferType.SPANNABLE);
}
}
If your data contains only simple HTML tags, they can actually be handled by a TextView by using Html.fromHtml(yourString). That static method returns a Spanned, which can be displayed by a TextView with far less overhead than a WebView.
You could use the CursorWrapper class.
CursorWrapper cw = new CursorWrapper(myCursor) {
public String getString(int columnIndex) {
String withHTML = super.getString(columnIndex);
return Html.fromHtml(withHTML).toString();
}
};

checkbox in List being checked unexpectedly

I have list of checkboxes in list binded by Custom simpleCursorAdapter.
In my custom simpleCursorAdapter, I've overridden newView and bindView with my modifications.
I've managed somehow to do multichoice.
The wierd thing is, after I delete any item from my list, the first item's checkbox is being checked all of a sudden. How does that happen? How can I solve it?
My SimpleCursorAdapter class:
public class MyListCursorAdapter extends SimpleCursorAdapter
{
private Context context;
private int layout;
public MyCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to)
{
super(context, layout, c, from, to);
this.context = context;
this.layout = layout;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent)
{
Cursor c = getCursor();
final LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(layout, parent, false);
CheckBox chkBoxBtn = (CheckBox) v.findViewById (R.id.deleteTwittChkBox);
if (chkBoxBtn != null)
{
chkBoxBtn.setChecked(false);
}
return v;
}
#Override
public void bindView(View v, Context context, Cursor c)
{
--binding view to my textsview in my items
//now it's the importat part:
CheckBox chkBoxBtn = (CheckBox) v.findViewById(R.id.deleteTwittChkBox);
if (chkBoxBtn != null)
{
chkBoxBtn.setId(Integer.valueOf(c.getString(c
.getColumnIndex(MyUsers.User._ID))));
chkBoxBtn.setOnClickListener(new OnItemClickListener(chkBoxBtn, v));
chkBoxBtn.setChecked(false);
}
}
//i couldnt find another way of doing this, but this is how i set listeners to my checkboxses
static ArrayList<String> checkedItemsList = new ArrayList<String>();
private class OnItemClickListener implements OnClickListener
{
private int mPosition;
private CheckBox chkBox;
OnItemClickListener(CheckBox mChkBox, View v)
{
chkBox = mChkBox;
chkBox.setChecked(false);
}
#Override
public void onClick(View v)
{
if (chkBox.isChecked())
{
checkedItemsList.add(String.valueOf(chkBox.getId()));
}
else
{
checkedItemsList.remove(String.valueOf(chkBox.getId()));
}
}
}
}
Here is the code part from the ListActivity class which describes the button that deletes the checked box items:
OnClickListener btListener = new OnClickListener()
{
public void onClick(View view)
{
// long[] items = listView.getCheckItemIds();
int x = 0;
Uri myUri = Uri
.parse("content://com.idan.datastorageprovider/users");
String where = "_id" + "=?";
//here i am tatking all checkboxes which ive added from the adapter class
ArrayList<String> checkedItemsList = MySimpleCursorAdapter.checkedItemsList;
for (String itemID : checkedItemsList)
{
getContentResolver()
.delete(myUri, where, new String[] { itemID});
checkedItemsList.remove(itemID);
}
}
};
I doubt that SimpleCursorAdapter is the right class to extend here.
Is the "checked" state connected to the data XML in any way? No? So you need your own custom adapter!
Basically all adapters have to implement a way to generate a view from a given element (more precisely an element position!). This will be called at any time where the list wants to display an element. Now, the trick it uses is to re-use formerly created list view elements that cannot be seen on screen any more! Thus: when you scroll your list down and an element disappears at the top, EXACTLY this view object will be re-used for the next appearing item.
So, when this method is called with a given "old" view that should be re-used, all contained elements will have to be set according the elements data. If a checkbox is part of this game, you will have to have a storage for the checked state! It is not sufficient to have a checkbox as there will be less checkbox objects as there are list elements!
SimpleCursorAdapters are there to - yeah - represent SIMPLE things. An XML describing data (images and text, as the documentation states). Because of this simplicity all you have to do here is provide a method to create NEW element view objects - you are not intercepting the re-use process AT ALL! It basically only knows how to put the data into an existing view object - but it is lacking the knowledge of how to handle checked/unchecked boxes!
Your solution: write your own BaseAdapter extension and do what has to be done: implement "getView" (and some other methods like getItem, getItemId and getCount). It's not hard at all!
This API Demo uses a BaseAdapter and the mExpanded state here is basically identical to your checkbox states!
Good luck!
You might need to call notifyDataSetChanged when you modify the data.
The problem is probably that you're calling setChecked from within the onItemClickListener. One hacky way around this is to do the following before and after you call setChecked from within your listener:
chkBox.setClickable(false);
chkBox.setChecked(false);
checkBox.setClickable(true);
This will prevent your onItemClickListener from getting called when you manually call setChecked.

AutoCompleteTextView displays 'android.database.sqlite.SQLiteCursor#'... after making selection

I am using the following code to set the adapter (SimpleCursorAdapter) for an AutoCompleteTextView
mComment = (AutoCompleteTextView) findViewById(R.id.comment);
Cursor cComments = myAdapter.getDistinctComments();
scaComments = new SimpleCursorAdapter(this,R.layout.auto_complete_item,cComments,new String[] {DBAdapter.KEY_LOG_COMMENT},new int[]{R.id.text1});
mComment.setAdapter(scaComments);
auto_complete_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
and thi is the xml for the actual control
<AutoCompleteTextView
android:id="#+id/comment"
android:hint="#string/COMMENT"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="18dp"/>
The dropdown appears to work correctly, and shows a list of items. When I make a selection from the list I get a sqlite object ('android.database.sqlite.SQLiteCursor#'... ) in the textview.
Anyone know what would cause this, or how to resolve this?
thanks
Ok I am able to hook into the OnItemClick event, but the TextView.setText() portion of the AutoCompleteTextView widget is updated after this point. The OnItemSelected() event never gets fired, and the onNothingSelected() event gets fired when the dropdown items are first displayed.
mComment.setOnItemClickListener( new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
SimpleCursorAdapter sca = (SimpleCursorAdapter) arg0.getAdapter();
String str = getSpinnerSelectedValue(sca,arg2,"comment");
TextView txt = (TextView) arg1;
txt.setText(str);
Toast.makeText(ctx, "onItemClick", Toast.LENGTH_SHORT).show();
}
});
mComment.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
Toast.makeText(ctx, "onItemSelected", Toast.LENGTH_SHORT).show();
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
Toast.makeText(ctx, "onNothingSelected", Toast.LENGTH_SHORT).show();
}
});
Anyone alse have any ideas on how to override the updating of the TextView?
thanks
patrick
I don't think you should have to update the text for the AutoCompleteTextView. It should do it automatically. It does this by calling the [CursorAdapter.convertToString(...)][1] method. if you read the description of the method it points this out. So if you were writing your own CursorAdapter you would override that method to return whatever text you would want to show up in the list of suggestions. This guy does a good job of explaining how to do it:
Line 86 - http://thinkandroid.wordpress.com/2010/02/08/writing-your-own-autocompletetextview/
However, since you are using a SimpleCursorAdapter, you can't override this method. Instead you need implement/create a [SimpleCursorAdapter.CursorToStringConverter][2] and pass it into [SimpleCursorAdapter.setCursorToStringConverter(...)][3]:
SimpleCursorAdapter adapter = new SimpleCursorAdapter(context, layout, cursor, from, to);
CursorToStringConverter converter = new CursorToStringConverter() {
#Override
public CharSequence convertToString(Cursor cursor) {
int desiredColumn = 1;
return cursor.getString(desiredColumn);
}
};
adapter.setCursorToStringConverter(converter);
Or if you don't want to create a CursorToStringConverter then use the [SimpleCursorAdapter. setStringConversionColumn(...)][4] method. But I think you still have to explicitly set the CursorToStringConverter to null:
int desiredColumn = 1;
adapter.setCursorToStringConverter(null);
adapter.setStringConversionColumn(desiredColumn);
Sorry, but the spam blocker won't let me post the links to the Android Documentation that describes the links I posted above. But a quick google search will point you to the correct doc pages.
[Late answer, just for the record. EDITed to remove my suggestion that subclassing is necessary.]
To use SimpleCursorAdapter with an AutoCompleteTextView, you need to set two handlers on the adapter: The CursorToStringConverter, and the FilterQueryProvider. Pseudocode follows:
adapter.setCursorToStringConverter(new CursorToStringConverter() {
public String convertToString(android.database.Cursor cursor) {
// Assume that "someColumn" contains the strings that we want to
// use to identify rows in the result set.
final int columnIndex = cursor.getColumnIndexOrThrow("someColumn");
final String str = cursor.getString(columnIndex);
return str;
}
});
adapter.setFilterQueryProvider(new FilterQueryProvider() {
public Cursor runQuery(CharSequence constraint) {
// runSomeQuery will look for all rows in the database
// that match the given constraint.
Cursor cursor = runSomeQuery(constraint);
return cursor;
}
});
When I make a selection from the list
I get a sqlite object
('android.database.sqlite.SQLiteCursor#'...
) in the textview.
You do not say what this "textview" is or how it relates to the Spinner.
I am going to take an educated guess and assume that you are simply assigning the selected item out of the Spinner into the TextView.
The selected item from a Spinner using a SimpleCursorAdapter is a Cursor, pointing at the row the user selected. The toString() implementation of Cursor will give you something akin to android.database.sqlite.SQLiteCursor# depending on where the Cursor came from.
More likely, you are going to want to call getString() on that Cursor, to retrieve some column value, and assign it to the TextView in question.
To solve the problem I just extended SimpleCursorAdapter and implemented the method convertToString(). Then I created an instance and set it as the adapter.
In order to allow filtering in AutoCompleteTextView when using CursorAdapters I also used setFilterQueryProvider(). See this question.
My extended class inside the Activity looks as:
private static class AutoCompleteCursorAdapter extends SimpleCursorAdapter {
public AutoCompleteCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
}
#Override
public CharSequence convertToString(Cursor cursor) {
// This is the method that does the trick (return the String you need)
return cursor.getString(cursor.getColumnIndex("name"));
}
}

Categories

Resources