I've got a ListView in my application that's rendered in a ListFragment's onActivityCreated()using setListAdapter(). Passed in to this setListAdapter()are my implementation of ArrayAdapter. At some times this adapter can be empty, and that's fine, but at those moments I would like to show a message in the list telling that there are no items, instead of just an empty view. However I don't really know how to achieve this, as for I have researched most people to show lists in a ListActivityand by doing that you can setEmptyView() but this doesn't seem doable when using a ListFragment. Another way of doing this was to change view in the ListFragment if the ArrayAdapter has no item's in it, then change view to another showing the message, but this seems to me a bit hacky.
Whats really the proper way of doing what I want to achieve?
Tried to setEmptyView() to my ListView but that didn't work either, see code on how views are inflated in my ListFragment:
public class MyFragment extends ListFragment {
#SuppressLint("InflateParams")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ListView listView = (ListView) inflater.inflate(R.layout.my_list, null);
listView.setEmptyView(inflater.inflate(R.layout.list_items_missing, null));
return listView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
MyItemArrayAdapter adapter = new MyItemArrayAdapter(getActivity());
// Populate adapter with items...
setListAdapter(adapter);
}
}
Shouldn't this result in the empty view beeing shown if no items exists in my adapter?
1) Try putting backgroundImage for ListView inside xml. If no item, show backgroundImage, if there is item, put background color.
2) You can also do what as #kgandroid suggested and here, setEmptyView() which you set custom view.
Example:
Another:
You can customize your adapter to show the layout R.layout.list_items_missing when (item == null) instead of inflating the normal custom list item layout that you implement.
Something like this:
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder; //asuming you have this in your custom adapter
if (convertView == null) {
holder = new ViewHolder();
if(MyItemArrayList.get(position)!=null)
{
convertView = this.inflater.inflate(R.layout.layout_list_item,
parent, false);
else
{
convertView = this.inflater.inflate(R.layout.list_items_missing,
parent, false);
}
//the rest of the adapter logic
}
Related
Inside the dialogFragment I have viewPager with two pages. Every page contains a custom adapter. One adapter with list of spinners, other adapter with list of EditTexts. ViewPager adds adapters fine.
public class PageFragment extends Fragment {
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.pagefragment_newprod, null);
LinearLayout ll=(LinearLayout) view.findViewById(R.id.tvLL);
ListView listView=new ListView(getActivity());
ll.addView(listView);
if (pageNumber==0){
dropDownAdapter=new DropDownAdapter(getActivity(), fillListAdapter);
listView.setAdapter(dropDownAdapter);
} else if (pageNumber==1){
boxAdapter = new BoxAdapter(getActivity(), filledFields);
listView.setAdapter(boxAdapter);
}
return view;
}
}
But it works to slow! Current Adapter (I mean at the curren page) create views every milisecond! Look at this:
public class BoxAdapter extends BaseAdapter{
...
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (view == null) {
view = lInflater.inflate(R.layout.addproduct_item, parent, false);
}
Log.d(LOG_TAG, "====As I said every milisecond...======");
EditText editText = (EditText) view.findViewById(R.id.addProductEditText);
editText.setText(p.value);
return view;
}
}
Even when I focused the EditText this Log.d write messages every milisecond!
Besides that, adapter at the next page works too. I have other Log.d at the other adapter getView and it works when I used different page's adapter!
Please help me to understand what is wrong...(
The question has already been solved in the comments. The solution for the OP was apparently to remove complex fragments and their adapter. However, I also had complex fragments in a tab layout with a ViewPager, and the following solution fixed the slow paging problem:
viewPager.setOffscreenPageLimit(2);
The 2 will keep two pages away from the current page in memory. This was enough for me because I had three tabs. Be careful about keeping too many pages in memory, though. See the documentation.
I have a listview that is populated via an adapter. I need one of the items (which are just bits of text) in the listview to have a different background compared to the others (to mark it as the currently selected one).
I have all of the background logic, I just need a way to say listview.setBackgroundById(int position)
or something like that.
How do I do this?
This needs to be as simple as possible, 'cause all of the other things done in the Activity are currently working perfectly. :)
As asked, this is my Adapter that I'm using:
public class SampleAdapter extends ArrayAdapter<SampleItem> {
private String title;
public SampleAdapter(Context context) {
super(context, 0);
}
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.row_station, null);
}
TextView title = (TextView)convertView.findViewById(R.id.station_name);
font.setFont(title, 2, getActivity());
title.setText(getItem(position).title);
RelativeLayout info = (RelativeLayout)convertView.findViewById(R.id.info_relative_button);
info.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
MainActivity.setCurrentTab(41);
MainActivity.setBackDisabled(true);
Log.e("current tab:",String.valueOf(MainActivity.getCurrentTab()));
Fragment fragment = new StationInfo();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
UserManager.getInstance().setStationId(getItem(position).id);
}
});
return convertView;
}
}
The SampleItem has 2 String fields, title and id, it's very simple.
You need to use a custom list adapter and have it return views with your desired background. Create a class extending ListAdapter or any of the existing SimpleAdapter etc and override getView to inflate a suitable view for your element, and add any logic you need to set the background of that view.
There is no way to tell the listview itself to decorate some of its elements by id or position.
Update: I just noticed you added the list adapter code.
Since you are already implementing getView, to change the background of your element simply call convertView.setBackgroundColor, or have two different views inflated depending on the situation.
(BTW it's really bad practice to call static methods on your activity like in your onClickListener.)
In ListView adapter:
#Override
public View getView(int position, View view, ViewGroup viewGroup) {
if(view==null)
....
//for example every even list item to be grey, every odd to be white
if(((position+1)%2)==0)
view.setBackgroundColor(mContext.getResources().getColor(R.color.grey));
else view.setBackgroundColor(mContext.getResources().getColor(android.R.color.white));
Hope you get an idea...
I need to change color on selected item in list view, i know how to do that in click method, but the thing is that I want to set it then i load new activity. In that activity I'm creating listview and then I want to change one item background color from that list.
I have tried
this.slideMenuList = (ListView) findViewById(R.id.listSlideMenu);
ArrayAdapter<String> adapter2 =
new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, this.menuListResut);
this.slideMenuList.setAdapter(adapter2);
this.slideMenuList.getChildAt(0).setBackgroundColor(R.color.red);
but I get NullPointer
You need a custom adapter; you're probably getting a NPE because the views aren't rendered until they're needed, and you can't do that reliably as-is. Write your own adapter class and set the background color after the view has been inflated, like so:
public class MyAdapter extends BaseAdapter {
#Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
convertView = mInflater.inflate(your layout); // Pseudo-code!
if (i == 0) {
convertView.setBackgroundColor(R.color.red);
}
}
}
I have a weird situation with a custom ArrayAdapter.
When I try to update the adpater with new data, instead of the data being updated, the new data are inserted to the beginning of the listview and the old data are remaining and visible once you scroll the listview.
UPDATE
It seems that the problem is caused by the ArrayList from the fragment bundle.
If I don't set the listview in the onCreateView from the fragment bundle, my update code works fine, but now I'm puzzled why this:
ArrayList<Collection> cityStoresList = fragmentBundle.getParcelableArrayList("stores");
mStoresList.addAll(cityStoresList);
is causing the items to always remain on the list?
END OF UPDATE
Here are parts of the code: (Collection is a custom object model class)
ArrayList<Collection> mStoresList = new ArrayList<Collection>();
/** List Adapter */
private StoresListAdapter mListAdapter;
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
boolean attach = false;
if (container == null) {
attach = true;
}
Bundle fragmentBundle = getArguments();
ArrayList<Collection> cityStoresList = fragmentBundle.getParcelableArrayList("stores");
mStoresList.addAll(cityStoresList);
//inflater code not added here, but is present
mListAdapter = new StoresListAdapter(getActivity(), mStoresList);
mListView.setAdapter(mListAdapter);
return layout;
}
My custom adapter is as follows:
public class StoresListAdapter extends ArrayAdapter<Collection> {
public StoresListAdapter(Context c, ArrayList<Collection> array) {
super(c, 0, array);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// View from recycle
View row = convertView;
// Handle inflation
if (row == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.row_store, null);
}
// Get the Store
Collection store = getItem(position);
//rest of code follows
return row;
}
}
Now when I want to update my adapter I use the following:
public void updateAdapter(ArrayList<Collection> storesList, final int listIndex) {
mStoresList.clear();
mStoresList.addAll(storesList);
mListAdapter.notifyDataSetChanged();
}
And this creates the issue I mentioned. The new items appear fine, but the previous ones are still visible and added after the new ones.
It's like adding the new items in the ArrayList as the first items, instead of just replacing the old ones.
Any ideas, suggestions?
Ok, finally found the problem.
Because the whole thing is within a fragment, the oncreateView is actually called when I'm attaching the array, so what happens is that my updateAdapter method is called, the items are added and displayed, before the view is actually visible.
Then the oncreateView method is fired and the original bundle items are being added to the Arraylist....
I'm trying to give the users of my app the option to change how they want their results displayed.
I've created a different layout item for each view and extended from BaseAdapter like so:
public View getView(int index, View recycledCompatibleView, ViewGroup parent)
{
// Just in case the view can be reused
View toReturn = recycledCompatibleView;
if(toReturn == null)
{
LayoutInflater inflator = LayoutInflater.from(parent.getContext());
toReturn = inflator.inflate(layoutId, null);
}
...
}
public void setResultsListStyle(int layoutId)
{
this.layoutId = layoutId;
}
Calling notifyDataSetChanged() is (observable through debug) refreshing the view because the new view is being inflated and returned from getView() method.
However the view on screen is not changing...
Is there something I'm missing ?
The problem here is that ListView may cache already inflated Views that are of old "format". You need to somehow reset this View "cache". For this you can use next trick:
mListView.setAdapter(mListView.getAdapter());
Instead of calling notifyDataSetChanged().