Add a header/footer in a listview in xml - android

I know how to add a header or a footer in JAVA, but I was wondering if I could add it straight in the XML.
I wouldn't want to simulate this, but really add it as footer or header!

No, I don't think that it is possible. Based on ListView source code there are only overScrollHeader/overScrollFooter are available from XML attributes. But these attributes accept only drawables.
If you don't want to use tricks with layouts above/below ListView. You can extend ListView and implement your own footer and header support in customized View. It is not so hard because of footer and header are already implemented. You only have to add XML attributes parsing in your customized View's constructor.

I was just trying to achieve the same thing (to keep my code cleaner and use XML for markup & source code for logic), but the only solution I found is to define the header view with XML somewhere in your layout and then detach it and put into ListView as header.
For example, having this XML:
<ListView android:id="#+id/myListView">
</ListView>
<LinearLayout android:id="#+id/myHeader">
....
</LinearLayout>
You can do this in your code:
ListView myListView = (ListView) findViewById(R.id.myListView);
LinearLayout myHeader = (LinearLayout) findViewById(R.id.myHeader);
// Let's remove the myHeader view from it's current child...
((ViewGroup) myHeader.getParent()).removeView(myHeader);
// ... and put it inside ListView.
myListView.addFooterView(myHeader);
Basically, what we do here is just detach the inflated LinearLayout from its parent and set it as ListView header child.
This is not an ideal solution, but it is still easier than creating/inflating header manually. Also this utilizes the power of XML inflation & view reusing if you're using this inside some "holder" pattern.
Hope this helps somebody.

This is how it worked for me, in my Adapter class which extends the BaseAdapter. I am targeting API 23:
#Override
public View getView(int position, View view, ViewGroup parent) {
if (position == 0) {
if (view == null) {
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
view = layoutInflater.inflate(R.layout.test_results_header, parent, false);
}
} else {
if (view == null) {
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
view = layoutInflater.inflate(R.layout.test_result_item, parent, false);
}
}
Pretty simple, I inflate a header XML for position 0 and the content XML for the rest. If you know the position where you want a header or any other XML, in your logic you would need to check the position, and inflate the respective XML for that position.

I created an xml resource same as my adapter rows xml (so the title is fit) and added it to the listview after addind the adapter:
listView.setAdapter(myRowsAdapter);
listView.addHeaderView(View.inflate(getContext(), R.layout.title_row, null));

Related

Dynamically add a button to a view from a listview Adapter GetView method

As a little eperiment, I'm trying to do the following.
I have an AXML describing a vertical linear layout which contains a listview (only filling 200dp of the vertical linear layout ). The AXML is inflated when the activity starts with SetContentView. Then the listview is correctly populated with values using its Adapter.
In the GetView method of the listview Adapter, I am trying to also dynamically create a button and add it to the linear layout, but for some reason the button is not added.
If I try to add the button in the constructor method of the Adapter instead, it is correctly added.
Can you tell me what could be possibly going wrong?
Let me add some code:
class TracksAdapter : BaseAdapter<string> {
Activity context;
List<Dictionary<string,string>> trackList;
// constructor
public TracksAdapter (Activity context, List<Dictionary<string,string>> trackList) {
this.context = context;
this.trackList = trackList;
// Just as a little test, if I create the button from here it will be correctly added to linear layout:
var ll = context.FindViewById<LinearLayout>(Resource.Id.linLayForResultsActivity);
Button b1 = new Button(context);
b1.Text = "Btn";
ll.AddView(b1);
}
public override View GetView(int position, View oldView, ViewGroup parent) {
// if I create the button from here it will not be added to the layout
var ll = context.FindViewById<LinearLayout>(Resource.Id.linLayForResultsActivity);
Button b1 = new Button(context);
b1.Text = "Btn";
ll.AddView(b1);
// this other code is working
View view = context.LayoutInflater.Inflate(Resource.Layout.ResultItem, null);
var artistLabel = view.FindViewById<TextView>(Resource.Id.resultArtistNameTextView);
artistLabel.Text = trackList[position]["trackArtistName"];
return view;
}
}
Update: adding some more context information because I know this can be a bit weird to understand without it:
In GetView, I don't need to return the new button I am trying to create there. GetView only need to return a listview view item, but, along its execution, GetView also has to create and add a button to the linear layout containing the listview.
The real code is much more complex than that. I have simplified it in the question. In the real code, the listview items are made of text and a button. The GetView also attaches event handlers to the buttons. Then what I need is, when a user clicks a button in any of the listview items, another button is added below the listview. So I need the code for adding another button to be in GetView, and the button needs to be added outside of the listview, ie. to the linear layout containing the listview.
Use the LayoutInflator to create a view based on your layout template, and then inject it into the view where you need it.
LayoutInflater vi = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = vi.inflate(R.layout.your_layout, null);
// fill in any details dynamically here
TextView textView = (TextView) v.findViewById(R.id.a_text_view);
textView.setText("your text");
// insert into main view
ViewGroup insertPoint = (ViewGroup) findViewById(R.id.insert_point);
insertPoint.addView(v, 0, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
I looked in you code, you are returning view, while you add the button to ll, you should return ll
what you return in getView() is what you see in the list item layout, since you're adding the button to ll and returning view, the button won't appear.
you can add the button to view as you implementation
Also check this:
Try using boolean addViewInLayout (View child, int index, ViewGroup.LayoutParams params)
http://developer.android.com/reference/android/view/ViewGroup.html#addViewInLayout(android.view.View, int, android.view.ViewGroup.LayoutParams)
It's working... Without making any changes now it's working as it should... ! Ugh!
I really don't know what I was doing wrong here... probably it was because of some sort of caching of older version of the installed APK.. ? I know this sort of stuff can happen, and that's why I've always been uninstalling the app before deplyoing the new version to the device... but still...!

List items overlaps each other

i like to implement a layout for a listview like this:
Any idea how i can implement this?
Thanks
You can do it in a couple of ways, but I think the most convenient way is to create two 9-patch background images so that you can define which sides should scale in what way. (Check here for information about 9-patch)
Make sure that the background image has a transparent part, where you want the one list item to overlap with the other, and set the layout_marginTop of the second item negative on an amount that gives you the desired effect.
This Approach must Help,Using two Different View and Displaying One at one Time based on Position
To implement listView elements as the screenshot, you need to have a CustomListViewAdapter (extends ArrayAdapter ) and in your CustomListViewAdapter class you need to specify in the method getView() the background to use in each element as below:
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.rowlayout, parent, false);
if ((position % 2) == 0) {
rowView.setBackgroundResource(R.drawable.trapeze_down);
} else {
rowView.setBackgroundResource(R.drawable.trapeze_up);
}
rowView.refreshDrawableState();
return rowView;
}
Note:
* rowLayout represent the layout of an element in the listView
* trapeze_down and trapeze_up are two png images representing the trapeze form you want to have in background
* when you create your list view, don't forget to specify :
android:divider="#null"
android:dividerHeight="0dp"
*And finally you just set the adapter to your listView

How can I inflate a View subclass from XML?

I am currently populating an Adapter on startup with views inflated from XML using
private void addView(Context context) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.deal_tile, this, null);
mViews.add(view);
}
However, I've found that storing the views in a list inside the AdapterView creates problems with controls within those views, so I want to change over to use the recycling functions in Adapter#getView(int position, View recycle, ViewGroup container).
For this reason I want to use a custom view class so I can do a sanity check (if(recycle!=null && recycle instanceof CustomView)) before I repopulate it in the adapter. However, I can't find out how you inflate a custom view class from XML. I can find out how you add an inflated view to a custom view, I can find out how you insert a custom view into an XML layout, etc, and obviously I am quite happily inflating these things directly using LayoutInflater, but I can't find an equivalent for generating the custom view itself. I want to reuse the XML I already have; consequently I don't want to program in the elements (and how they look) directly.
I used this to create my own slide gallery, i think it would help.
LinearLayout internalWrapper = new LinearLayout(getContext());
internalWrapper.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
internalWrapper.setOrientation(LinearLayout.HORIZONTAL);
addView(internalWrapper);
this.mItems = items;
LinearLayout generalLayout = new LinearLayout(this.getContext());
generalLayout = (LinearLayout) View.inflate(this.getContext(), R.layout.galleryrow, null);
// inside linear layout
LinearLayout generalLinear = (LinearLayout) generalLayout.findViewById(R.id.rowgenerallin);
// set height & width to the LINEAR
generalLinear.setLayoutParams(new LayoutParams(reference_width, reference_height));
ImageView ivl = (ImageView) generalLayout.findViewById(R.id.arrow_left);
ImageView ivr = (ImageView) generalLayout.findViewById(R.id.arrow_right);
internalWrapper.addView(generalLayout);
In my case, R.layout.gallery_row contains the two images I want to manage, nested by a LinearLayous (rowgenerllin), the internal wrapper is an empty LinearLayout declared in the main layout of your activity.
Double check the LayoutParams code or you will get a big NULL :)
Cheers!

It is possible to implement a ListView without XML files?

I'm trying to implement a ListView on my app, but i'm trying to understand and learn how to achieve it without using XML files, all with java code.
I'm stuck on the inflater part, the mInflater.inflate(); function needs a resource xml file, so, i didn't understand how to continue without using XML files
I have a ArrayList of strings, and I simply need a ListView that shows a list with these strings of the Arraylist, and a delete Button on the right of the String. If the user press the Button, the item of the List get's deleted.
Each item of the ListView has two things, a TextView with the String of the ArrayList and a Button to delete it.
If someone can give me code examples i will be grateful.
Thanks
I totally agree with CommonsWare. But the part that you are stuck is the part that you have to create a row "template" for the ListView rows. The inflater is used so as to make a single View out of a complete layout.xml file. So the basic idea is that you create an xml that represents each row and then inflate it through that piece of code.
In your situation, you need to do that through code. Perhaps add a LinearLayout as a parent with orientation=vertical add some width or height properties and then add 2 TextViews so as to be a title and a subtitle with some additional properties. Then you should add them to the LinearLayout and you there you go.
Your LinearLayout is a pile of Views that are dynamically created and have the same effect as inflating all the above code through an xml file.
But I reaaaaally don't see the point in creating such a fuss over a much faster, easier, straight forwarded, better implemented and not to mention best practice...
EDIT: Somewhere inside your adapter you have: mInflater.inflate(); with the resource that you mention. As I previously said the resource determines how the "template" for each row would be. So a normal xml file that will determine a list row would be something like this:
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content" android:orientation="vertical" >
<TextView ... /> <! --some properties you want to set -->
<TextView ... /> <! --some properties you want to set -->
</LinearLayout>
This xml produces a 2 line list row for a ListView. With the layout inflater the above xml file returns a View object that contains all the bundle.
So if you want to create it from code, then the snippet would be:
LinearLayout layout = new LinearLayout(context);
//layout set some properties
TextView title = new TextView(context);
//title set some properties
TextView subtitle = new TextView(context);
//subtitle set some properties
layout.add(title);
layout.add(subtitle);
Now instead of inflating the xml to get the contents into a single View object, you have the layout variable in the code snippet that contains all the logic that was previously inflated through the xml.
If you have created a custom ListView adapter before then you should be familiar with creating a custom list row and how it works.
EDIT: sample code for the adapter of the ListView
this is the standart procedure of getView() method of the adapter by inflating a single layout:
#Override
public View getView(int position, View view, ViewGroup viewgroup) {
ViewHolder holder; //our view holder of the row
if (view == null) {
view = context.getLayoutInflater().inflate(R.layout.static_layout, null);
holder = new ViewHolder();
//set the views of the holder
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
//rest of implementation of the View
return view;
}
dynamic implementation:
#Override
public View getView(int position, View view, ViewGroup viewgroup) {
ViewHolder holder; //our view holder of the row
if (view == null) {
LinearLayout layout = new LinearLayout(context);
//layout set some properties
TextView title = new TextView(context);
//title set some properties
TextView subtitle = new TextView(context);
//subtitle set some properties
layout.add(title);
layout.add(subtitle);
//CREATING THE LAYOUT THROUGH CODE
view = layout; //INSTEAD OF INFLATING A LAYOUT FOR THE ROW I JUST BINDED IT TO THE RECENTLY CREATED LAYOUT
holder = new ViewHolder();
//bind the views of the holder to the views of the layout
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
//rest of implementation of the View
return view;
}

How to do my own custom list?

How to do my own custom list? I mean, that each element of list will be looking like I want.
Create a custom list item row layout
You have to create a custom list row item in the layout folder, just like you define the usual activity layouts. There you place your icons, TextViews etc and place them properly.
Override the specific adapter you need
You then need to override the specific adapter you need in order to associate the data from your curso / object list with your layout xml element. This is usually done by overriding the getViewor bindView method of the adapter of your choice (ResourceCursorAdapter, ArrayAdapter,..).
#Override
public View getView(int position, View convertView, ViewGroup parent){
if(convertView == null){
convertView = mInflater.inflate(R.layout.row_item, parent, false);
}
TextView someTextViewOnMyRowLayout = (TextView)findViewById(...);
someTextViewOnMyRowLayout.setText(...);
return convertView;
}
You can create an xml file which acts as an element that looks like you want..
and assign that to the list using inflators and adapters..
Try this..
http://www.softwarepassion.com/android-series-custom-listview-items-and-adapters/ ,
http://www.androidpeople.com/android-custom-listview-tutorial-example/

Categories

Resources