I have this code inside a ListFragment:
TextView tv = (TextView) this.getListView().getChildAt(0);
tv.setBackgroundColor(getResources().getColor(R.color.White));
tv.setTextColor(getResources().getColor(R.color.OtherColor));
I wanted write this code onActivityCreated, but tv is null.
If I write this code inside onListItemClick, it works perfectly.
Is it imposible what I want?
code:
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String[] values = new String[] { getResources().getString(R.string.menu_partida),
getResources().getString(R.string.menu_acciones),
getResources().getString(R.string.menu_resultado) };
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), R.layout.list_item_menu, values);
setListAdapter(adapter);
}
Views are only draw after all of the "creation" callbacks have executed, there is no callback for this event. However you can post() a Runnable to the UI Handler and achieve the same thing:
getListView().post(new Runnable() {
public void run() {
TextView tv = (TextView) this.getListView().getChildAt(0);
tv.setBackgroundColor(getResources().getColor(R.color.White));
tv.setTextColor(getResources().getColor(R.color.OtherColor));
}
}
But really, this change won't do what you expect since the row layouts are recycled in a ListView. (You will see eradict behavior while scrolling.) You should create a custom Adapter to change the layout for the row at position 0 only. You might get away with the Runnable since you only have three rows, but the best solution is to extend Adapter.
Related
I want to change the background of a TextView, which is inserted in a ListView. The ListView contains a series of TextView, and the value of each one is retrieved from a simple List. Now I show you my snippet:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.town_selection);
list = (ListView) findViewById(R.id.list);
adapter = new ArrayAdapter<>(this, R.layout.string_item, App.towns);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
adapter.notifyDataSetChanged();
list.invalidate();
// list.getCount() returns zero!!
// and so, list.getChildAt(...) returns null!!
}
App.towns is the list of String I was talking, and its length is greater than 0. When the app is running it seems ok, because the ListView is showing the items, but at the end of the onCreate I need to change the background color of some items, but the ListView seems not ready as I commented.
notifyDataSetChanged() and invalidate() doesn't help.
I'm not claiming that my answer is the best, but I have some idea and I'd like to share it.
If your string list of towns, as I understood, is unchangable let's do the following:
...
final Context context = this;
String [] towns = new String [] { "town_1", "town_2", "town_3" };
ListView list;
ArrayAdapter<String> adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.town_selection);
list = (ListView) findViewById(R.id.list);
adapter = new ArrayAdapter<String>(this, R.layout.string_item, R.id.string_item_text, towns)
//R.id.string_item_text - id your TextView in item of your list
{
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
TextView txtView = (TextView) v.findViewById(R.id.string_item_text);
String sText = txtView.getText().toString();
if (sText.equals("town_1")) {
txtView.setBackgroundColor(Color.parseColor("#93C47D")); //#93C47D - just example
} else if (sText.equals("town_2")){
txtView.setBackgroundColor(Color.parseColor("#6FA8DC")); //#6FA8DC - just example
} else if (sText.equals("town_3")){
txtView.setBackgroundColor(Color.parseColor("#F6B26B"));//#F6B26B - just example
}
return v;
}
};
list.setAdapter(adapter);
...
It helped me in one of Android projects. If it will help you it'll be good.
In any way, leave your feedback.
You will need to write a custom adapter for your list view and change the color when creating each item in the list view.
This SO question - Custom Adapter for List View has great answers which should help you with how to create this custom adapter. You will not be able to do it with the ArrayAdapter as-is.
The best solution is to use a custom adapter instead of ArrayAdapter , then in the getView() method of custom adapter you can change the color of the textview
If, for some reason, you need to change your background is TextViev, the information about it should be somewhere to store and change the background is using methods in your custom adapter. Create your own custom adapter.
I want to open a dialog for user to choose from multiple items but I get an error when setAdapter() was going to execute...
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Dialog cd = new Dialog(Main1.this);
String[] mobileArray = {"Android","IPhone","WindowsMobile","Blackberry","WebOS","Ubuntu","Windows7","Max OS X"};
ArrayAdapter adapter = new ArrayAdapter<String>(cd.getContext(), R.layout.lvlayout, mobileArray);
ListView listView = (ListView) findViewById(R.id.listviewID);
listView.setAdapter(adapter);
cd.setContentView(R.layout.dialogLayout);
cd.setTitle("MEOW");
cd.show();
}
});
ListView is in Dialog layout. whats Wrong here?
Simply there are two mistakes in your code, you are calling this line without prefixing it with cd. so that you have to do it like this,
ListView listView = (ListView) cd.findViewById(R.id.listviewID);
Another mistake you are doing is calling findViewById before calling setContentView(), This may also raise NPE.
So I suggest you to move this up and re-arrange like this
cd.setContentView(R.layout.dialogLayout);
ListView listView = (ListView) cd.findViewById(R.id.listviewID);
The problem is that your variable listView null is when you call setAdapter() on it. So the call to findViewById() returns null. Maybe you just used a wrong ID.
Just initialize your listview outside of onClick listener.
Initializing it in onCreate() is more preferable.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
// initialize
ListView listView = (ListView) findViewById(R.id.listviewID);
}
You have some basic mistakes here.
The major mistake is calling the cd.setContentView(R.layout.dialogLayout); at the end of your code. You need to call before you want to find something in that content layout.
And the other mistake is trying to find the list. You need to get a view to find the list in that view. This might be something like this.
ListView listView = (ListView) cd.getView().findViewById(R.id.listviewID);
However, I do prefer the following solution for your problem. This might be an easier way for what you're trying to achieve.
Here's a nice example of implementing a custom dialogue. You can have a look here.
https://github.com/afollestad/material-dialogs
So, now as you're getting NullPointerException, findViewById is not returning any reference of your ListView I guess. So here by using the library mentioned above you can achieve this quite easily.
// Initialize your dialogue
MaterialDialog dialog = new MaterialDialog.Builder(getActivity())
.title("MEOW")
.customView(R.layout.dialogLayout, true)
.positiveText(R.string.ok)
.negativeText(R.string.cancel)
.onNegative(new MaterialDialog.SingleButtonCallback() {
#Override
public void onClick(#NonNull MaterialDialog dialog, #NonNull DialogAction which) {
dialog.dismiss();
}
})
.show();
// Now get the view of that dialogue.
View view = dialog.getCustomView();
// Initialize the array adapter
String[] mobileArray = {"Android","IPhone","WindowsMobile","Blackberry","WebOS","Ubuntu","Windows7","Max OS X"};
ArrayAdapter adapter = new ArrayAdapter<String>(cd.getContext(), R.layout.lvlayout, mobileArray);
// Get the list view and set the adapter
ListView listView = (ListView) view.findViewById(R.id.listviewID);
listView.setAdapter(adapter);
I don't want to override onCreateView because there is no need. With a ListFragment all I am doing is taking an array of data, putting it in an ArrayAdapter and calling setListAdapter(arrayGoesHere) and then I have my populated ListFragment.
I am calling findViewById inside onActivityCreated() as it is the recommended place to find and store references to your views. And as you know, this is called after onCreateView() in the Android framework.
I can't do viewReturnedFromOnCreateView.findViewById because I'm not using onCreateView.
getActivity().findViewById doesnt work, because I'm actually not sure why.
getListView().findViewById doesnt work (because the element im trying to access is not a child of getListView()).
Edit 1: getView() didn't work either, I forgot to mention I am using the support library, android.support.v4.app.ListFragment. not sure if that matters
This is my code:
public class SomeFragment extends ListFragment {
private int someButtonId;
private Button someButton;
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String[] someList = getResources().getStringArray(R.array.someData);
ArrayAdapter<String> someAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_activated_1, someList);
setListAdapter(someAdapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
context = getActivity().getApplicationContext();
someButtonId = context.getResources().getIdentifier("someButton", "id", context.getPackageName());
someButton = (Button) getActivity().findViewById(someButtonId);
Log.i("hello", someButton.toString()); //Null pointer exception
}
}
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!
I have got a custom list view adapter and an image button in the adapter class. When i click on the image button, the listener should reload the list view. I need to reload the list view within getview() of adapter class. So I need to know other options than using notifyDataSetChanged() in my listActivity class.
Thanks
You want to refresh a cell inside the listview or do you want to refresh the whole listview, if a single row is loaded inside getView() ?
Check this out:
Android ListView Refresh Single Row
Create a static handler inside the activity which calls a method which reloads the listview and send a message to this handler from the adapter whenever required.
handler = new Handler() {
public void handleMessage(Message paramAnonymousMessage) {
switch (paramAnonymousMessage.what) {
case 1:
populateList();
break;
}
}
};
public void populateBill() {
MyBasketAdapter adapter = new MyBasketAdapter(this, basketList);
listView = (ListView) findViewById(android.R.id.list);
listView.setAdapter(adapter);
}
Inside the adapter class. for example,
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Message msg = Message.obtain();
msg.what = 1;
MyActivity.handler.sendMessage(msg);
}
});
That is very Simple just write a method in your adapter class and call it get view when you deleting or adding anything in your list which you are binding to your adapter.and use notifyDataSetChanged after change in list
public void updateResults(ArrayList<CustomList> results) {
// assign the new result list to your existing list it will work
notifyDataSetChanged();
}