The listview I used has custom xml and adapter. I want to get the checked items from this listview from anywhere. My xml is here:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<CheckBox
android:id="#+id/cb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="15dp"
android:paddingBottom="30dp"
android:focusable="false"
android:focusableInTouchMode="false" />
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="bold"
android:paddingTop="15dp"
android:paddingRight="15dp"
android:paddingLeft="50dp"
android:text="Item" />
<TextView
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:paddingRight="15dp"
android:paddingBottom="15dp"
android:paddingLeft="50dp"
android:text="Subtitle"
android:layout_below="#+id/text" />
</RelativeLayout>
My adapter is here:
private final List<Model> list;
private final List<Model> list2;
private final Activity context;
boolean checkAll_flag = false;
boolean checkItem_flag = false;
public Adapter(Activity context, List<Model> list, List<Model> list2) {
super(context, R.layout.listview, list);
this.context = context;
this.list = list;
this.list2 = list2;
}
static class ViewHolder {
protected TextView text;
protected TextView text2;
protected CheckBox checkbox;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
convertView = inflator.inflate(R.layout.listview, null);
viewHolder = new ViewHolder();
viewHolder.text = (TextView) convertView.findViewById(R.id.text);
viewHolder.text2 = (TextView) convertView.findViewById(R.id.text2);
viewHolder.checkbox = (CheckBox) convertView.findViewById(R.id.cb);
viewHolder.checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int getPosition = (Integer) buttonView.getTag();
list.get(getPosition).sec(buttonView.isChecked());
}
});
convertView.setTag(viewHolder);
convertView.setTag(R.id.text, viewHolder.text);
convertView.setTag(R.id.text2, viewHolder.text2);
convertView.setTag(R.id.cb, viewHolder.checkbox);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.checkbox.setTag(position);
viewHolder.text.setText(list.get(position).isimGetir());
viewHolder.text2.setText(list2.get(position).isimGetir());
viewHolder.checkbox.setChecked(list.get(position).secilimi());
return convertView;
}
My aim is that getting checked items from a method placed in Main activity. However I cannot catch the values of checkboxes because of they're custom.
An approach you might use is to keep track of the checked items in the main activity by calling back to the main activity via intent or public method to maintain a list of them. Add and remove as the checked condition changes. You can fire off the intent or method whenever the checked value changes or on load in the adapter.
Related
I'm using an inflated ListView in my project. The layout file is
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/background2" >
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:cacheColorHint="#00000000"
android:fastScrollEnabled="true"
android:smoothScrollbar="true" >
</ListView>
</RelativeLayout>
And the inflated layout file is
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="70dp"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="70dp"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="70dp"
android:layout_height="70dp"
android:src="#drawable/contact" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<CheckBox
android:id="#+id/checkBox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
The above code works fine when I'm using API level 11 or above, but below API level 11, it behaves in an awkward fashion, like the textView1 becomes totally invisible while textView2 is still visible. Also, while scrolling, all the items are VISIBLE but when the scrolling is finished, it again turns invisible. I'm using Actionbarsherlock. And yeah, one last thing, I'm using SearchView in actionbar, the bottom part of which strangely appears like a blue highlighted line in API 8 while everything works perfect in higher android levels
EDIT
This is my code snippet of ListView adapter
private class ContactViewHolder {
CheckBox checkBox;
TextView textView;
TextView textView2;
ImageView iv;
}
private class ContactArrayAdapter extends ArrayAdapter<Contact> {
//private LayoutInflater inflater;
List<Contact> myList;
Context mContext;
//Cursor cursor;
public ContactArrayAdapter(Context context, List<Contact> planetList) {
super(context, R.layout.simplerow, R.id.textView1, planetList);
// Cache the LayoutInflate to avoid asking for a new one each time.
//inflater = LayoutInflater.from(context);
mContext = context;
myList = planetList;
}
#Override
public int getCount() {
if(myList != null)
return myList.size();
return 0;
}
#Override
public Contact getItem(int position) {
if(myList != null)
return myList.get(position);
return null;
}
#Override
public long getItemId(int position) {
if(myList != null)
return myList.get(position).hashCode();
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Contact to display
ContactViewHolder holder;
//If the listview does not have an xml layout ready set the layout
if (convertView == null){
//we need a new holder to hold the structure of the cell
holder = new ContactViewHolder();
//get the XML inflation service
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//Inflate our xml cell to the convertView
convertView = inflater.inflate(R.layout.simplerow, null);
//Get xml components into our holder class
holder.textView = (TextView) convertView.findViewById(R.id.textView1);
holder.textView2 = (TextView) convertView.findViewById(R.id.textView2);
holder.checkBox = (CheckBox) convertView.findViewById(R.id.checkBox1);
holder.iv = (ImageView) convertView.findViewById(R.id.imageView1);
holder.checkBox.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v;
Contact contact = (Contact) cb.getTag();
contact.setChecked(cb.isChecked());
}
});
//Attach our holder class to this particular cell
convertView.setTag(holder);
}else{
//The listview cell is not empty and contains already components loaded, get the tagged holder
holder = (ContactViewHolder) convertView.getTag();
}
//Fill our cell with data
//get our person object from the list we passed to the adapter
Contact contact = getItem(position);
//Fill our view components with data
holder.textView.setText(name1.get(position));
holder.textView2.setText(num1.get(position));
holder.checkBox.setChecked(contact.checked);
return convertView;
}
}
The Contact class is
private static class Contact {
private String name = "";
private boolean checked = false;
public Contact() {
}
public Contact(String name) {
this.name = name;
}
public Contact(String name, boolean checked) {
this.name = name;
this.checked = checked;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
}
public String toString() {
return name;
}
public void toggleChecked() {
checked = !checked;
}
}
Here is how to write a good adapater for your listview
public class MyAdapter extends ArrayAdapter<Person> {
Context context;
List<Person>myList;
public MyAdapter(Context context, int resource, List<Person> objects) {
super(context, resource, objects);
this.context = context;
this.myList = objects;
}
#Override
public int getCount() {
if(myList != null)
return myList.size();
return 0;
}
#Override
public Person getItem(int position) {
if(myList != null)
return myList.get(position);
return null;
}
#Override
public long getItemId(int position) {
if(myList != null)
return myList.get(position).hashCode();
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder;
//If the listview does not have an xml layout ready set the layout
if (convertView == null){
//we need a new holder to hold the structure of the cell
holder = new Holder();
//get the XML inflation service
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//Inflate our xml cell to the convertView
convertView = inflater.inflate(R.layout.person_cell, null);
//Get xml components into our holder class
holder.txtName = (TextView)convertView.findViewById(R.id.person_cell_txtName);
holder.txtSurname = (TextView)convertView.findViewById(R.id.person_cell_txtSurname);
holder.imageView = (ImageView)convertView.findViewById(R.id.person_cell_imageview);
//Attach our holder class to this particular cell
convertView.setTag(holder);
}else{
//The listview cell is not empty and contains already components loaded, get the tagged holder
holder = (Holder)convertView.getTag();
}
//Fill our cell with data
//get our person object from the list we passed to the adapter
Person person = getItem(position);
//Fill our view components with data
holder.txtName.setText(person.getName());
holder.txtSurname.setText(person.getSurname());
Picasso.with(context).load(person.getImageUrl()).fit().into(holder.imageView);
return convertView;
}
/**
* This holder must replicate the components in the person_cell.xml
* We have a textview for the name and the surname and an imageview for the picture
*/
private class Holder{
TextView txtName;
TextView txtSurname;
ImageView imageView;
}
}
Notice that for Holder class you only set the properties reflecting the inflated xml. You dont need any constructor or getter/setters
In the get view you have to attach the holder class to the convertView tag property (convertView.setTag(holder))
retrieve the tagged holder if the convertView is not null
try to follow this pattern for the adapter
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="70dp"
android:layout_height="70dp"
android:src="#drawable/contact" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="fill_vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<CheckBox
android:id="#+id/checkBox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp" />
</LinearLayout>
</LinearLayout>
Im working on simple feedreader app. in my main activity i have listview that show all items . in each row i have imagebutton for save that item and when user click on that the image of imagebutton must be change(like fav icon on twitter) but it does not change ! After scrolling changes are observed !
this is my row layout .
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants" >
<TextView
android:id="#+id/tvListViewItemTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="15dp"
android:layout_marginTop="15dp"
android:text="#string/listview_item_title"
android:textSize="25dp" />
<TextView
android:id="#+id/tvListViewItemText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="#+id/tvListViewItemTitle"
android:layout_below="#+id/tvListViewItemTitle"
android:layout_marginTop="20dp"
android:text="#string/listview_item_text"
android:textSize="18dp" />
<TextView
android:id="#+id/tvListViewItemTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="#+id/tvListViewItemText"
android:layout_below="#+id/tvListViewItemText"
android:layout_marginTop="22dp"
android:paddingTop="5dp"
android:text="#string/listview_item_time" />
<ImageButton
android:id="#+id/ibListViewItemSave"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignTop="#+id/tvListViewItemTime"
android:layout_marginLeft="20dp"
android:paddingTop="11dp"
android:src="#drawable/icon_save_story_2x"
android:background="#null" />
and this is my custom adapter class.
public class FeedListAdapter extends ArrayAdapter<FeedItem> {
private final Activity context;
private final List<FeedItem> list;
public FeedListAdapter(Activity context, List<FeedItem> list) {
super(context, R.layout.feed_listview_item_type1, list);
this.context = context;
this.list = list;
}
static class ViewHolder {
TextView tvTitle;
TextView tvText;
TextView tvTime;
ImageButton ibSave;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflater.inflate(R.layout.feed_listview_item_type1, parent,false);
// configure view holder
ViewHolder holder = new ViewHolder();
holder.tvTitle = (TextView)rowView.findViewById(R.id.tvListViewItemTitle);
holder.tvText = (TextView)rowView.findViewById(R.id.tvListViewItemText);
holder.tvTime = (TextView)rowView.findViewById(R.id.tvListViewItemTime);
holder.ibSave = (ImageButton)rowView.findViewById(R.id.ibListViewItemSave);
rowView.setTag(holder);
}
// fill data
ViewHolder holder = (ViewHolder) rowView.getTag();
final FeedItem feedItem = list.get(position);
holder.tvTitle.setText(feedItem.getTitle());
holder.tvText.setText(feedItem.getText());
holder.tvTime.setText(feedItem.getTime());
if(feedItem.isSave()) holder.ibSave.setImageResource(R.drawable.icon_saved_story_2x);
else holder.ibSave.setImageResource(R.drawable.icon_save_story_2x);
final String msg = " "+(position+1);
holder.ibSave.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
if(feedItem.isSave()){
feedItem.setSave(false);
Toast.makeText(context,
msg+"deleted", Toast.LENGTH_SHORT).show();
//holder.ibSave.setImageResource(R.drawable.icon_save_story_2x);
}else{
feedItem.setSave(true);
Toast.makeText(context,
msg+"saved", Toast.LENGTH_SHORT).show();
//holder.ibSave.setImageResource(R.drawable.icon_saved_story_2x);
}
}
});
return rowView;
}
}
Call notifyDataSetChanged in your onClick after the if else.
At present the FeedListAdapter does not realize that you have made some changes to the list
I have a list (ExpandableListView), and every item of the list has a ToggleButton that shows/hides the child items when toggled (the child is always 1 and it's a sort of toolbar with two buttons). Thanks to this tutorial I could set a custom button instead of the expandablelistview's indicator and I made it so that I can do something else than showing the toolbar when clicking on a list item. Also, I used the answer to this question to automatically close an open toolbar when opening another one.
So, I need to collapse the currently expanded toolbar when touching anything on the screen that is not its ToggleButton (I would need to collapse it even when clicking on one of the toolbar's buttons, as long as its own "onClick" is sent anyway).
here's an image of the app:
Here's the ExpandableListView:
<ExpandableListView
android:id="#+id/normalList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:groupIndicator="#drawable/toggle_button_selector" >
</ExpandableListView>
Here's the xml of the group item:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/filesListDrawerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp" >
<ImageView
android:id="#+id/img"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_margin="2dp"
android:contentDescription="#string/icondescription" />
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="29dp"
android:layout_alignTop="#+id/img"
android:layout_marginLeft="15dp"
android:layout_toRightOf="#+id/img"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/counter"
android:layout_width="wrap_content"
android:layout_height="19dp"
android:layout_alignBottom="#+id/img"
android:layout_below="#+id/text"
android:layout_marginLeft="15dp"
android:layout_toRightOf="#+id/img"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall" />
<ToggleButton
android:id="#+id/toggle"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignParentRight="true"
android:layout_below="#+id/text"
android:layout_marginRight="15dp"
android:background="#drawable/toggle_button_selector"
android:focusable="false"
android:focusableInTouchMode="false"
android:textColorLink="#android:color/transparent"
android:textOff=""
android:textOn="" />
The child item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/details"
android:layout_width="0dp"
android:layout_height="57dip"
android:layout_weight="1"
android:clickable="true"
android:drawableTop="#drawable/ic_action_about"
android:drawablePadding="-12dp"
android:background="#drawable/toolbar_selector"
android:gravity="center"
android:text="#string/details" />
<TextView
android:id="#+id/send"
android:layout_width="0dp"
android:layout_height="57dip"
android:layout_weight="1"
android:clickable="true"
android:drawableTop="#drawable/ic_action_new_email"
android:drawablePadding="-12dp"
android:background="#drawable/toolbar_selector"
android:gravity="center"
android:text="#string/send" />
</LinearLayout>
The relevant parts of the adapter:
public class CustomList extends BaseExpandableListAdapter {
private final Activity context;
public final List<Item> names; //Item is a custom Object
private final Integer[] imageId;
private int lastExpandedGroupPosition;
public CustomList(Activity context, List<Item> names, Integer[] imageId) {
this.context = context;
this.names = names;
this.imageId = imageId;
}
public View getGroupView(final int position, boolean isExpanded, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.list_single, null);
}
TextView txtTitle = (TextView) convertView.findViewById(R.id.text);
TextView txtData = (TextView) convertView.findViewById(R.id.counter);
ImageView imageView = (ImageView) convertView.findViewById(R.id.img);
ToggleButton toggle = (ToggleButton) convertView.findViewById(R.id.toggle);
final ExpandableListView list = (ExpandableListView) parent.findViewById(R.id.normalList);
txtTitle.setText(names.get(position).getName());
txtData.setText(names.get(position).getData());
if(/*some conditions*/) {
imageView.setImageResource(imageId[0]);
toggle.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
list.expandGroup(position, true);
} else {
list.collapseGroup(position);
}
}
});
} else if(/*other conditions*/) {
imageView.setImageResource(imageId[2]);
toggle.setVisibility(View.GONE);
} else {
imageView.setImageResource(imageId[1]);
toggle.setVisibility(View.GONE);
}
return convertView;
}
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_child, null);
}
TextView details = (TextView) convertView.findViewById(R.id.details);
TextView send = (TextView) convertView.findViewById(R.id.send);
details.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//do something
}
});
send.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//do something else
}
});
return convertView;
}
#Override
public void onGroupExpanded(int groupPosition) {
ToggleButton button = (ToggleButton) ((ExpandableListView) context
.findViewById(R.id.normalList)).getChildAt(lastExpandedGroupPosition)
.findViewById(R.id.toggle);
if(groupPosition != lastExpandedGroupPosition && button.isChecked()) {
button.performClick();
}
super.onGroupExpanded(groupPosition);
lastExpandedGroupPosition = groupPosition;
}
}
And finally the important parts in the activity:
lv = (ExpandableListView)findViewById(R.id.normalList);
lv.setGroupIndicator(null);
lv.setOnGroupClickListener(new OnGroupClickListener() {
public boolean onGroupClick(ExpandableListView parent, View v, int position, long id) {
//do some things
return true; //this tells the list that it mustn't show the child items
}
});
adapter = new CustomList(myActivity.this, list, icons);
lv.setAdapter(adapter);
P.S.: The code to hide the open toolbars doesn't work properly, but I really can't understand why. But this is another story...
--- EDIT ---
About the P.S. above: now I know why that happens.
Your list looks like ExpandableListView. Did you try to use it? It has build it second level rows, expanding, hiding, etc. Simply add your pdf rows as group headers and then add tool rows as child rows. Then you can handle row clicks to show and hide rows you would like to show/hide. See: http://developer.android.com/reference/android/widget/ExpandableListView.html
And, btw., using additional rows with hiding is a bit wrong UX design. Maybe it would be better to use drop down lists or custom dialog windows? Both of them have built in functionality do disappear when touched outside.
You can simply put all your ToggleButton whenfilling the list in an ArrayList. This way you just have to force the click on each button of list toggled when one of them is clicked.
Ok I solved the problem.
Instead of toggling the buttons with "performClick()" or "setChecked" in some methods and managing the expand/collapse action in an OnCheckedChangedListener, I decided to store the status of the togglebuttons in an array, and to expand/collapse the child views in the "getGroupView" method depending on the state of the groupview's button, whose position in the array corresponds to the groupview's position in the list. To update the list, I call notifyDataSetChanged() on the adapter.
I added a FrameLayout around the ToggleButton to increase its clickable area.
Here's the code for clarity:
The relevant parts of the MainActivity:
public class MainActivity extends ActionBarActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
.
.
.
ExpandableListView lv = (ExpandableListView) findViewById(R.id.normalList);
CustomList adapter = new CustomList(MainActivity.this, list /*the list of Items, declared elsewhere*/, lv);
lv.setAdapter(adapter);
DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.filesListDrawerLayout);
lv.setOnGroupClickListener(new OnGroupClickListener() {
public boolean onGroupClick(ExpandableListView parent, View v, int position, long id) {
uncheckButtons(mDrawerLayout);
//do some unrelated stuff
return true;
}
});
}
public void uncheckButtons(ViewGroup vg) {
for(int i = 0; i < adapter.buttons.length; ++i)
adapter.buttons[i] = false;
adapter.lastChecked = -1;
adapter.notifyList();
}
The relevant parts of the adapter:
public class CustomList extends BaseExpandableListAdapter {
private final Activity context;
public final List<Item> names; //Item is a custom Object
public boolean[] buttons;
public int lastChecked;
private final Integer[] imageId = new Integer[] { R.drawable.image1, R.drawable.image1, R.drawable.image3 };
private ExpandableListView list;
public CustomList(Activity context, List<Item> names, boolean forUpload, ExpandableListView list) {
this.context = context;
this.names = names;
this.list = list;
this.buttons = new boolean[names.size()];
this.lastChecked = -1;
}
private static class GroupHolder {
TextView txtTitle;
TextView txtData;
ImageView imageView;
ToggleButton toggle;
FrameLayout frame;
}
public View getGroupView(final int position, boolean isExpanded, View convertView, ViewGroup parent) {
GroupHolder holder;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_single, null);
holder.txtTitle = (TextView) convertView.findViewById(R.id.text);
holder.txtData = (TextView) convertView.findViewById(R.id.counter);
holder.imageView = (ImageView) convertView.findViewById(R.id.img);
holder.toggle = (ToggleButton) convertView.findViewById(R.id.toggle);
holder.frame = (FrameLayout) convertView.findViewById(R.id.frame);
convertView.setTag(holder);
} else {
holder = (GroupHolder) convertView.getTag();
}
txtTitle.setText(names.get(position).getName());
txtData.setText(names.get(position).getData());
if(/*some conditions*/) {
imageView.setImageResource(imageId[0]);
holder.frame.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP) {
if(lastChecked != -1) {//if there's a checked button
buttons[lastChecked] = !buttons[lastChecked];//uncheck it
if(position == lastChecked)//if I clicked on the last checked button
lastChecked = -1;//there's no checked button
else {
buttons[position] = !buttons[position];//check the button
lastChecked = position;//and set it as the last checked one
}
notifyList();
}
return false;
}
});
holder.toggle.setChecked(buttons[position]);
if(holder.toggle.isChecked()) {
if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2)
list.expandGroup(position);
else
list.expandGroup(position, true);
} else {
list.collapseGroup(position);
}
} else if(/*other conditions*/) {
//do other stuff with the views that don't interest us
}
return convertView;
}
private static class ChildHolder {
TextView details;
TextView send;
TextView other;
}
public View getChildView(final int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
ChildHolder holder;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_child, null);
holder = new ChildHolder();
holder.details = (TextView) convertView.findViewById(R.id.details);
holder.send = (TextView) convertView.findViewById(R.id.send);
holder.other = (TextView) convertView.findViewById(R.id.other);
} else {
holder = (ChildHolder) convertView.getTag();
}
//maybe I could manage the listeners more nicely and without redundance...
holder.details.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
buttons[lastChecked] = !buttons[lastChecked];//uncheck the only checked button (it always exists at this point)
lastChecked = -1;//there's no checked button
notifyList();
//call a certain method in the main activity...
}
});
holder.send.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
buttons[lastChecked] = !buttons[lastChecked];//uncheck the only checked button (it always exists at this point)
lastChecked = -1;//there's no checked button
notifyList();
//call a certain method in the main activity...
}
});
holder.other.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
buttons[lastChecked] = !buttons[lastChecked];//uncheck the only checked button (it always exists at this point)
lastChecked = -1;//there's no checked button
notifyList();
//call a certain method in the main activity...
}
});
return convertView;
}
public void notifyList() {
this.notifyDataSetChanged();
}
//I don't need OnGroupExpanded anymore
The ExpandableListView:
<ExpandableListView
android:id="#+id/normalList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="singleChoice"
android:groupIndicator="#drawable/toggle_button_selector" >
</ExpandableListView>
The xml of the group item:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/filesListDrawerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp" >
<ImageView
android:id="#+id/img"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="2dp"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:contentDescription="#string/icondescription" />
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="29dp"
android:layout_alignTop="#+id/img"
android:layout_marginLeft="15dp"
android:layout_toRightOf="#+id/img"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#color/black" />
<TextView
android:id="#+id/counter"
android:layout_width="wrap_content"
android:layout_height="19dp"
android:layout_alignBottom="#+id/img"
android:layout_below="#+id/text"
android:layout_marginLeft="15dp"
android:layout_toRightOf="#+id/img"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#color/black" />
<FrameLayout
android:id="#+id/frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#+id/text"
android:layout_marginTop="-15dp"
android:clickable="true"
android:paddingTop="10dp"
android:paddingRight="15dp"
android:paddingLeft="10dp" >
<ToggleButton
android:id="#+id/toggle"
android:layout_width="25dp"
android:layout_height="25dp"
android:background="#drawable/toggle_button_selector"
android:clickable="false"
android:duplicateParentState="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:textColorLink="#android:color/transparent"
android:textOff=""
android:textOn="" />
</FrameLayout>
</RelativeLayout>
The xml of the child item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/details"
android:layout_width="0dp"
android:layout_height="57dip"
android:layout_weight="1"
android:clickable="true"
android:drawableTop="#drawable/ic_action_about"
android:drawablePadding="-12dp"
android:background="#drawable/toolbar_selector"
android:gravity="center"
android:text="#string/details" />
<TextView
android:id="#+id/send"
android:layout_width="0dp"
android:layout_height="57dip"
android:layout_weight="1"
android:clickable="true"
android:drawableTop="#drawable/ic_action_new_email"
android:drawablePadding="-12dp"
android:background="#drawable/toolbar_selector"
android:gravity="center"
android:text="#string/send" />
<!-- this one is new -->
<TextView
android:id="#+id/other"
android:layout_width="0dp"
android:layout_height="57dip"
android:layout_weight="1"
android:background="#drawable/toolbar_selector"
android:clickable="true"
android:drawablePadding="-12dp"
android:drawableTop="#drawable/ic_action_other"
android:gravity="center"
android:text="#string/other" />
</LinearLayout>
There. I'm happy now.
I'm doing something quite similar to the tutorial http://www.vogella.com/articles/AndroidListView/article.html#listadvanced_interactive.
I now want to put a button at the bottom. Then click the button and do something with the selected Values.
I understand, that I need some new layout, because adding the button to the existing one would just add a button to every textview. But I cant figure out how to do it.
Some help would be very nice. Thanks in advance. :)
Edit: That's my layout at the moment.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#+id/label"
android:textSize="30px" >
</TextView>
<CheckBox
android:id="#+id/check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="4px"
android:layout_marginRight="10px" >
</CheckBox>
</RelativeLayout>
This creates something that looks like this:
http://i.stack.imgur.com/cN8Dl.png
My adapter looks like this:
public class AttributeAdapter extends ArrayAdapter<Attribute> {
private final List<Attribute> list;
private final Activity context;
public AttributeAdapter(Activity context, List<Attribute> list) {
super(context, R.layout.activity_select_attributes, list);
this.context = context;
this.list = list;
}
static class ViewHolder {
protected TextView text;
protected CheckBox checkbox;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
view = inflator.inflate(R.layout.activity_select_attributes, null);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.text = (TextView) view.findViewById(R.id.label);
viewHolder.checkbox = (CheckBox) view.findViewById(R.id.check);
viewHolder.checkbox
.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
Attribute element = (Attribute) viewHolder.checkbox
.getTag();
element.setSelected(buttonView.isChecked());
}
});
view.setTag(viewHolder);
viewHolder.checkbox.setTag(list.get(position));
} else {
view = convertView;
((ViewHolder) view.getTag()).checkbox.setTag(list.get(position));
}
ViewHolder holder = (ViewHolder) view.getTag();
holder.text.setText(list.get(position).getName() + " " + list.get(position).getType());
holder.checkbox.setChecked(list.get(position).isSelected());
return view;
}
Now i want a button at the bottom to continue with the selected values.
Create a new layout or xml file named activity_base and add following:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".BaseActivity" >
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/button1"
>
</ListView>
<Button
android:id="#+id/button1"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Button" />
</RelativeLayout>
in your ListActivity in the Oncreate add setContentView(R.layout.activity_base);
This should do the job.
I googled and i tried to do this but couldnt implement successly.
My layout file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="#android:id/list"></ListView>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="buyButtonClickProduct"
android:id="#+id/buyButtonClickProduct"></Button>
</LinearLayout>
I have a custom adapter as :
private final List<Products> list;
private final Activity context;
public ProductsCustomAdapter(Activity context, List<Products> list) {
super(context, R.layout.coposite_product_info, list);
this.context = context;
this.list = list;
}
static class ViewHolder {
protected TextView productInfoText;
protected CheckBox checkbox;
protected ImageView imageOfProduct;
}
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
view = inflator.inflate(R.layout.coposite_product_info, null);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.imageOfProduct = (ImageView) view.findViewById(R.id.productImageView);
viewHolder.productInfoText = (TextView) view.findViewById(R.id.productInfoText);
viewHolder.checkbox = (CheckBox) view.findViewById(R.id.productCheck);
viewHolder.checkbox
.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
Products element = (Products) viewHolder.checkbox
.getTag();
element.setChecked(buttonView.isChecked());
}
});
view.setTag(viewHolder);
viewHolder.checkbox.setTag(list.get(position));
} else {
view = convertView;
((ViewHolder) view.getTag()).checkbox.setTag(list.get(position));
}
ViewHolder holder = (ViewHolder) view.getTag();
holder.productInfoText.setText(list.get(position).getInformation());
holder.imageOfProduct.setImageBitmap(list.get(position).getProductImage());
holder.checkbox.setChecked(list.get(position).isChecked());
return view;
}
I wanna get checked items from these but i couldn't reach them. When i debug it on my main class which is call listview.getCheckedItemPositions(); always turn for me "null"
This doesn't crash actually just always show "null" but i can see all my data in my listview.
SparseBooleanArray checkedItems = shopListView.getCheckedItemPositions();