I want to create a ListView with a header view that can be expanded and retractet just as in a ExpandableListView (but just the header view, all other views just be normal list items).
I'm using an ExpandableListView with a BaseExpandableListAdapter and treat all the other items in the list as groups that have no children.
This is cumbersome and error-prone and has unwanted sideeffects.
I also tried using a normal ListView and a view for the header where I setVisivility(View.VISIBLE) to the expanded part of the view when the header view is clicked, but this doesn't seem to have any effect:
private View getHeaderView() {
final View v = layoutInflater.inflate(R.layout.headertest, null);
View v1 = v.findViewById(R.id.view1);
final View v2 = v.findViewById(R.id.view2);
v1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d("head", "click");
v2.setVisibility(View.VISIBLE);
notifyDataSetChanged();
}
});
return v;
}
When v1 is clicked, the visibility of v2 is not changed, although the clickListener is called. I also tried .invalidate() on all kinds of views, to no avail.
Any ideas on how to solve this one or the other way?
You can do it with the expandable list view. First disable the indicators (open/close icons) on your ListView:
mExpList.setIndicator(null);
Next, your header (first group) will have to be a special type of group which has an image (an indicator) in its layout. Basically you want to have 2 types of group views:
#Override
public int getGroupTypeCount() {
return 2;
}
#Override
public int getGroupType(int groupPosition) {
if (groupPosition == headerPosition) {
return 1;
} else {
return 0;
}
}
You will also need to Override onGroupExpanded and onGroupCollapsed to change the image of your header (if a header was clicked of course).
Lastly you'll need to override the ListView's OnGroupClickListener:
mExpList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
if (groupPosition == header) {
// Click was not handled
return false;
} else {
// Do some normal stuff with items
// Click was handled group won't be (or tried to be) expanded
return true;
}
}
});
Also a good idea would be to override adapters getChildCount to return 0 when it's not a header.
Hope this helps. Good luck!
Related
I have a configuration activity for an AppWidget. I want to let the user choose an existing string for the widget, or create one of their own by selecting the first option and editing the text within the list.
How do I change the element type of just the first list item to a different type of view that will allow users to insert custom text?
The ListAdapter interface has two methods getViewTypeCount() and getItemViewType(). So in your case, they might be implemented like this:
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int position) {
// first position has view type == 0; all others have view type == 1
return position == 0 ? 0 : 1;
}
What this does is make sure that the correct views are recycled for the correct positions. Once you have these methods, then you can do:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (position == 0) {
// create a custom edit view and return it
} else {
// create a selection view and return it
}
}
I'm looking for an API like isExpanded() or isCollapsed() that tells me if a group is expanded or collapsed.
You can use isGroupExpanded .
expListViewObj.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
if(parent.isGroupExpanded(groupPosition))
{
// Do your Staff
}
else{
// Expanded ,Do your Staff
}
return false;
}
});
For more details you can visit Here
http://developer.android.com/reference/android/widget/ExpandableListView.html#setOnGroupClickListener(android.widget.ExpandableListView.OnGroupClickListener)
As #George D wrote there is ExpandableListView .isGroupExpanded(int groupPosition) method. Well you could add the code to get expanded group position or -1
public int getExpandedGroupPosition() {
for (int i = 0; i < listView.getExpandableListAdapter().getGroupCount(); i++) {
if ( listView.isGroupExpanded(i) ) {
return i;
}
}
return -1;
}
If u use BaseExpandableListAdapter class you have getGroupView() override method.
public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
// Here is your expand list view parent id
// b specify that parent expand or not.
.............
if(b){
imdDownArrow.setVisibility(View.GONE);
imdUpArrow.setVisibility(View.VISIBLE);
}else{
imdDownArrow.setVisibility(View.VISIBLE);
imdUpArrow.setVisibility(View.GONE);
}
...............
return view;
}
so using this simple code you can show arrow up or down
There is a parameter in getGroupView() on your ExpandableListAdapter, a boolean that represents wheter the group is expanded or not.
From (http://developer.android.com/reference/android/widget/ExpandableListAdapter.html#getGroupView(int, boolean, android.view.View, android.view.ViewGroup)
Gets a View that displays the given group. This View is only for the group--the Views for the group's children will be fetched using getChildView(int, int, boolean, View, ViewGroup)).
Parameters
groupPosition the position of the group for which the View is returned
isExpanded whether the group is expanded or collapsed
convertView the old view to reuse, if possible. You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view. It is not guaranteed that the convertView will have been previously created by getGroupView(int, boolean, View, ViewGroup).
parent the parent that this view will eventually be attached to
I have ExpandableListview inside NavigationDrawer. When group is expanded I collapse the previous expanded group, but when group is collapsed expanded group loses the focus (position of ExpandableListview goes down). Here's the code:
#Override
public boolean onGroupClick(ExpandableListView expandableListView, View view, int i, long l) {
if (mListView.isGroupExpanded(i)) {
mListView.collapseGroupWithAnimation(i);
} else {
mListView.expandGroupWithAnimation(i);
if(i!=lastExpandedGroupPosition )
mListView.collapseGroupWithAnimation(lastExpandedGroupPosition);
lastExpandedGroupPosition = i;
}
return true;
}
Use the function setSelectedGroup(groupPosition) with the expandablelistview object while expanding the list. This would set the focus for the group , who's view you had clicked!
Happy coding :)
Pretty much I have a listview, where if you press one button, the other is meant to change to a dark grey image. The code works fine on an individual level, but for some reason the action is replicated every 4th list item. Here is the getItemView code! (By the way I have indeed tried making the imagebuttons local!)
ImageButton thumbsUpButton;
ImageButton thumbsDownButton;
#Override
public View getItemView(FactListParseObject factRow, View v,
ViewGroup parent) {
if (v == null) {
v = View.inflate(getContext(), R.layout.fact_list_row, null);
}
super.getItemView(factRow, v, parent);
setTexts(v, factRow);
thumbsUpButton = (ImageButton) v.findViewById(R.id.thumbsup);
thumbsDownButton = (ImageButton) v.findViewById(R.id.thumbsdown);
if (thumbsDownButton != null&& thumbsUpButton!=null) {
thumbsUpButton.setTag(false);
thumbsDownButton.setTag(false);
thumbsUpButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if((boolean)thumbsUpButton.getTag()==true){
thumbsUpButton
.setImageResource(R.drawable.thumbsup);
thumbsUpButton.setTag(false);
}
if ((boolean)thumbsDownButton.getTag() == false) {
// thumbsdown not currently disabled
thumbsDownButton
.setImageResource(R.drawable.thumbsdowndisabled);
thumbsDownButton.setTag(true);
} else {
// thumbsdown is disabled
thumbsDownButton.setImageResource(R.drawable.thumbsdown);
thumbsDownButton.setTag(false);
}
}
});
thumbsDownButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.d("called","howmany");
if((boolean)thumbsDownButton.getTag()==true){
thumbsDownButton
.setImageResource(R.drawable.thumbsdown);
thumbsDownButton.setTag(false);
}
if ((boolean)thumbsUpButton.getTag() == false) {
// thumbsdown not currently disabled
thumbsUpButton
.setImageResource(R.drawable.thumbsupdisabled);
thumbsUpButton.setTag(true);
} else {
// thumbsdown is disabled
thumbsUpButton.setImageResource(R.drawable.thumbsup);
thumbsUpButton.setTag(false);
}
}
});
}
return v;
}
Because the ListView recycles the view, therefore the fourth is the recycled one ...
So you have to "reset" the state (in your case the color of the button) for every item in your list (or in other words for each cell in your listview) ...
btw. the methods name is getView and not getItemView()
Here you can find an abstract base adapter class, that helps you to handle better the "lifecycle" of a listview cell:
https://github.com/sockeqwe/appkit/blob/master/adapter/src/main/java/com/hannesdorfmann/appkit/adapter/SimpleAdapter.java
The idea is that there are two key methods:
newView() Here you inflate the View from layout and setup the ViewHolder pattern.
bindView() Here you bind the view cell (may be a recycled or a new created one from newView() ) to your data object that should "fill" the cell with the desired data. So here is where you should set the color of the button ...
I am new to android, and I want to implement a ListView like the image below. It seems expandableListView may meet my request, but what I want is only Item 4 has children and can be expanded, 'Item 1' is just an option user can click, and can't be expanded. I read the document of Expandable List View, and it's not clear enough how to implement this. Can anyone gave some suggestion on implementing this? Thank you so much
but what I want is only Item 4 has children and can be expanded
If Item doesn't have children, it won't be exanded. You can image that like:
public class Item {
private String title;
private List<Option> children; // if size = 0 won't be expanded
}
It's native behaviour of ExpandableListView so if any Item doesn't have children, implicitly won't be expanded but you need to set OnClickListener for both groups (Items) and children (Options):
public boolean onChildClick(ExpandableListView parent, View row,
int groupPosition, int childPosition, long id) {
// callback method after click for Options
return false;
}
public boolean onGroupClick(ExpandableListView parent, View row,
int groupPosition, long id) {
/** if you are using BaseAdapter subclass implementation **/
adapter.getGroup(groupPosition)).getChildren() == null) {
// item doesn't have children
}
else {
// has children
}
Generally if you want to get more control over your ListView i pretty recommend you to implement own subclass of ListAdapter in your case you can use BaseExpandableListAdapter.
And an appearance of List is only issue about proper styled layouts for example removing group indicator with
android:groupIndicator="#null"
Update:
Issue mentioned by #Roberto Lombardini:
A little problem with this solution is that the little grey triangle
indicating the state of the groupview (expanded or not) will appear
even if group has no children. Am i wrong?
If you want to have gray triangle only for Items with children, you need to fix it in your custom adapter in getGroupView() method:
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
// inflating View etc.
Item item = items.get(groupPosition);
if (item != null) {
// if Item has children
if (item.getChildren() != null && !item.getChildren().isEmpty()) {
// set children indicator to VISIBLE
imageView.setVisibility(ImageView.VISIBLE);
}
// if Item doesn't have children
else {
// set children indicator to GONE
imageView.setVisibility(ImageView.GONE);
}
}
}
Try to implement some custom Adapter, I think could be the better way to do what you need
lv.setOnGroupClickListener(new OnGroupClickListener() {
public boolean onGroupClick(ExpandableListView parent, View v, int position, long id) {
switch (position) {
case 0: return true;
case 2: return true; // returning true wont expand
default:
return false;// if you return false then only that position will be expanded
}
}
}
);
just return false on the which parent position you want to expand and in which you dont want to expand you can return true.