I have an ExpandableListView on a fragment and when I choose an item I am changing the background and text colour of this item (TextView). This works fine. However when I collapse the group which contains the currently selected item, the selection is lost. How can I stop this from happening/set the selected item back to what it should be?
I have tried messing around with the onGroupExpand/CollapseListener's but not had any success. For example I have tried this:
_list.setOnGroupExpandListener(new OnGroupExpandListener() {
#Override
public void onGroupExpand(int groupPosition) {
_list.setItemChecked(_activePosition, true);
}
});
Note: _list and _activePosition are declared at class level.
Here is my code for setting the checked item, from the examples I've seen I think this is standard practice, but please advise if not as I'm new to android.
HelpItemsFragment.java
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final List<HelpCategory> itemList = new ArrayList<HelpCategory>();
HelpCategory helpCategory;
//replace this with database stuff later
helpCategory = new HelpCategory();
helpCategory.setTitle("Group 1");
helpCategory.addHelpItem(new HelpItem((long) 1, "1.1", "Details for 1.1"));
helpCategory.addHelpItem(new HelpItem((long) 1, "1.2", "Details for 1.2"));
helpCategory.addHelpItem(new HelpItem((long) 1, "1.3", "Details for 1.3"));
itemList.add(helpCategory);
helpCategory = new HelpCategory();
helpCategory.setTitle("Group 2");
helpCategory.addHelpItem(new HelpItem((long) 2, "2.1", "Details for 2.1"));
helpCategory.addHelpItem(new HelpItem((long) 2, "2.2", "Details for 2.2"));
helpCategory.addHelpItem(new HelpItem((long) 2, "2.3", "Details for 2.3"));
itemList.add(helpCategory);
HelpExpandableListAdapter listAdapter = new HelpExpandableListAdapter(this.getActivity(), itemList);
_list.setAdapter(listAdapter);
_list.setOnChildClickListener(new OnChildClickListener() {
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
int index = parent.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
HelpItem helpItem = itemList.get(groupPosition).getHelpItemList().get(childPosition);
_activePosition = index;
_callback.onItemSelected(null, helpItem.getTitle(), helpItem.getDetail(), _activePosition);
parent.setItemChecked(index, true);
return true;
}
});
Adapter class HelpExpandableListAdapter should be like
public class HelpExpandableListAdapter extends BaseExpandableListAdapter {
private LayoutInflater inflater;
private ArrayList<CategoryGroup> mParent;
public ExpandableListItems(Context context, ArrayList<CategoryGroup> parent) {
mParent = parent;
inflater = LayoutInflater.from(context);
}
#Override
//counts the number of parent items so the list knows how many times calls getGroupView() method
public int getGroupCount() {
return mParent.size();
}
#Override
//counts the number of children items so the list knows how many times calls getChildView() method
public int getChildrenCount(int i) {
return mParent.get(i).getArrayChildren().size();
}
#Override
//gets the title of each parent/group
public Object getGroup(int i) {
return mParent.get(i).getTitle();
}
#Override
//gets the name of each item
public Object getChild(int i, int i1) {
return mParent.get(i).getArrayChildren().get(i1);
}
#Override
public long getGroupId(int i) {
return i;
}
#Override
public long getChildId(int i, int i1) {
return i1;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
//in this method you must set the text to see the parent/group on the list
public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
if (view == null) {
System.out.println("i: " + i + "; b: " + b );
view = inflater.inflate(R.layout.grouprow, viewGroup, false);
}
TextView textView = (TextView) view.findViewById(R.id.rowname);
//"i" is the position of the parent/group in the list
textView.setText(getGroup(i).toString());
//return the entire view
return view;
}
#Override
//in this method you must set the text to see the children on the list
public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
if (view == null) {
view = inflater.inflate(R.layout.childrow, viewGroup, false);
}
TextView textView = (TextView) view.findViewById(R.id.grpchild);
//"i" is the position of the parent/group in the list and
//"i1" is the position of the child
textView.setText(mParent.get(i).getArrayChildren().get(i1));
//return the entire view
return view;
}
#Override
public boolean isChildSelectable(int i, int i1) {
return true;
}
#Override
public void registerDataSetObserver(DataSetObserver observer) {
/* used to make the notifyDataSetChanged() method work */
super.registerDataSetObserver(observer);
}
}
Group class
public class CategoryGroup {
private String mTitle;
private ArrayList<String> mArrayChildren;
public String getTitle() {
return mTitle;
}
public void setTitle(String mTitle) {
this.mTitle = mTitle;
}
public ArrayList<String> getArrayChildren() {
return mArrayChildren;
}
public void setArrayChildren(ArrayList<String> mArrayChildren) {
this.mArrayChildren = new ArrayList(mArrayChildren);
}
}
In the onCreateView()
ArrayList<CategoryGroup> arrayParentsGroups = new ArrayList<CategoryGroup>();
arrayParentsGroups = createGroupList();
listAdapter = new HelpExpandableListAdapter(this, arrayParentsGroups);
_list.setAdapter(listAdapter);
private List createGroupList() {
ArrayList arrayParents = new ArrayList();
for( int i = 0 ; i < 10 ; ++i ) { // 10 groups........
CategoryGroup parent = new CategoryGroup();
parent.setTitle("Group row" + i);
ArrayList<String> arrayChildren = new ArrayList<String>();
for (int j = 0; j < 3; j++) {
arrayChildren.add("Child row" + j);
}
parent.setArrayChildren(arrayChildren);
arrayParents.add(parent);
}
return arrayParents;
}
Related
I want Header View on expandable List View is automatically changed background color right after initial program if there is at least one of Child View be highlighted
I get this program from http://tutorialscache.com/expandable-listview-android-tutorials/ as an example
Here is the ExpandableCustomAdapter Class
public class ExpandableCustomAdapter extends BaseExpandableListAdapter{
//Initializing variables
private List<String> headerData;
private HashMap<String, ArrayList<ChildDataModel>> childData;
private Context mContext;
private LayoutInflater layoutInflater;
// constructor
public ExpandableCustomAdapter(Context mContext, List<String> headerData,
HashMap<String, ArrayList<ChildDataModel>> childData) {
this.mContext = mContext;
this.headerData = headerData;
this.childData = childData;
this.layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getGroupCount() {
return this.headerData.size();
}
#Override
public int getChildrenCount(int headPosition) {
return this.childData.get(this.headerData.get(headPosition)).size();
}
#Override
public Object getGroup(int headPosition) {
return this.headerData.get(headPosition);
}
#Override
public Object getChild(int headPosition, int childPosition) {
return this.childData.get(this.headerData.get(headPosition))
.get(childPosition);
}
#Override
public long getGroupId(int headPosition) {
return headPosition;
}
#Override
public long getChildId(int headPosition, int childPosition) {
return this.childData.get(this.headerData.get(headPosition))
.get(childPosition).getId();
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public View getGroupView(int headPosition, boolean is_expanded, View view, ViewGroup headGroup) {
// Heading of each group
String heading = (String) getGroup(headPosition);
if (view==null){
view = layoutInflater.inflate(R.layout.list_header,null);
}
TextView headerTv = view.findViewById(R.id.headerTv);
headerTv.setText(heading+"");
headerTv.setBackgroundColor( Color.BLUE );
return view;
}
#Override
public View getChildView(int headPosition, int childPosition, boolean islastChild, View view, ViewGroup viewGroup) {
ChildDataModel child = (ChildDataModel) getChild(headPosition, childPosition);
if (view == null) {
view = layoutInflater.inflate(R.layout.child_item, null);
}
TextView childTv = (TextView) view.findViewById(R.id.childTv);
ImageView childImg = (ImageView) view.findViewById(R.id.childImg);
childTv.setText(child.getTitle());
if(child.getTitle().equalsIgnoreCase( "China" ))
{
childTv.setBackgroundColor( Color.RED );
}
childImg.setImageResource(child.getImage());
return view;
}
#Override
public boolean isChildSelectable(int headPosition, int childPosition) {
return true;
}
}
Here is ChildDataModel Class
public class ChildDataModel {
long id;
int image;
String title;
public ChildDataModel(int id, String country, int image) {
this.setId(id);
this.setTitle(country);
this.setImage(image);
}
public int getImage() {
return image;
}
public void setImage(int image) {
this.image = image;
}
public long getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Override
public String toString() {
Log.d("response ","ID: "+getId()+" Title: "+getTitle());
return super.toString();
}
}
Here is MainActivity Class
public class MainActivity extends AppCompatActivity {
ExpandableCustomAdapter expandableCustomAdapter;
ExpandableListView expandableListView;
List<String> headerData;
HashMap<String,ArrayList<ChildDataModel>> childData;
ChildDataModel childDataModel;
Context mContext;
ArrayList<ChildDataModel> asianCountries,africanCountries,nAmericanCountries,sAmericanCountries;
private int lastExpandedPosition = -1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
//initializing arraylists
headerData = new ArrayList<>();
childData = new HashMap<String,ArrayList<ChildDataModel>>();
asianCountries = new ArrayList<>();
africanCountries = new ArrayList<>();
nAmericanCountries = new ArrayList<>();
sAmericanCountries = new ArrayList<>();
// link listview from activity_main.xml
expandableListView = findViewById(R.id.expandAbleListView);
//populating data of world continents and their countries.
headerData.add("ASIA");
//adding countries to Asian continent
childDataModel = new ChildDataModel(1,"Afghanistan",R.drawable.afghanistan);
asianCountries.add(childDataModel);
childDataModel = new ChildDataModel(2,"China",R.drawable.china);
asianCountries.add(childDataModel);
childDataModel = new ChildDataModel(3,"India",R.drawable.india);
asianCountries.add(childDataModel);
childDataModel = new ChildDataModel(4,"Pakistan",R.drawable.pakistan);
asianCountries.add(childDataModel);
childData.put(headerData.get(0),asianCountries);
headerData.add("AFRICA");
//adding countries to African continent
childDataModel = new ChildDataModel(1,"South Africa",R.drawable.southafrica);
africanCountries.add(childDataModel);
childDataModel = new ChildDataModel(2,"Zimbabwe",R.drawable.zimbabwe);
childData.put(headerData.get(1),africanCountries);
headerData.add("NORTH AMERICA");
//adding countries to NORTH AMERICA continent
childDataModel = new ChildDataModel(1,"Canada",R.drawable.canada);
nAmericanCountries.add(childDataModel);
childData.put(headerData.get(2),nAmericanCountries);
headerData.add("SOUTH AMERICA");
//adding countries to SOUTH AMERICA continent
childDataModel = new ChildDataModel(1,"Argentina",R.drawable.argentena);
sAmericanCountries.add(childDataModel);
childData.put(headerData.get(3),sAmericanCountries);
//set adapter to list view
expandableCustomAdapter = new ExpandableCustomAdapter(mContext,headerData,childData);
expandableListView.setAdapter(expandableCustomAdapter);
//child click listener
expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView expandableListView, View view, int headPosition, int childPosition, long id) {
Toast.makeText(mContext,
headerData.get(headPosition)
+ " has country "
+ childData.get(
headerData.get(headPosition)).get(
childPosition).getTitle(), Toast.LENGTH_SHORT)
.show();
return false;
}
});
//group expanded
expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
#Override
public void onGroupExpand(int headPosition) {
if (lastExpandedPosition != -1
&& headPosition != lastExpandedPosition) {
expandableListView.collapseGroup(lastExpandedPosition);
}
lastExpandedPosition = headPosition;
Toast.makeText(mContext,
headerData.get(headPosition) + " continent expanded",
Toast.LENGTH_SHORT).show();
}
});
//group collapsed
expandableListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
#Override
public void onGroupCollapse(int headPosition) {
Toast.makeText(mContext,
headerData.get(headPosition) + " continent collapsed",
Toast.LENGTH_SHORT).show();
}
});
//Group Indicator
expandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
parent.smoothScrollToPosition(groupPosition);
if (parent.isGroupExpanded(groupPosition)) {
ImageView imageView = v.findViewById(R.id.expandable_icon);
imageView.setImageDrawable(getResources().getDrawable(R.drawable.arrow_right));
} else {
ImageView imageView = v.findViewById(R.id.expandable_icon);
imageView.setImageDrawable(getResources().getDrawable(R.drawable.arrow_down));
}
return false ;
}
});
}
}
I expect to handle it without event like setOnChildClickListener, setOnGroupExpandListener,setOnGroupCollapseListener, etc. Thanks for help
change getGroupView to:
#Override
public View getGroupView(int headPosition, boolean is_expanded, View view, ViewGroup headGroup) {
// Heading of each group
String heading = (String) getGroup(headPosition);
if (view==null){
view = layoutInflater.inflate(R.layout.list_header,null);
}
TextView headerTv = view.findViewById(R.id.headerTv);
headerTv.setText(heading+"");
boolean hasSelected = false;
ArrayList<ChildDataModel> childs =
childData.get(headerData.getItemAtIndex(headPosition));
for(int i=0;i<childs.size();i++){
if(childs.get(i).isSelected){
hasSelected = true;
}}
if(hasSelected)
headerTv.setBackgroundColor( Color.BLUE );
else
headerTv.setBackgroundColor( Color.RED);
return view;
}
you most highlight the header view when getGroupView executed if childs highl sign selected chileds and if selected eny then highlight header
Thank you #hunixa siuri It does work well. However Code must be edited a little as below
#Override
public View getGroupView(int headPosition, boolean is_expanded, View view, ViewGroup headGroup) {
// Heading of each group
String heading = (String) getGroup(headPosition);
if (view==null){
view = layoutInflater.inflate(R.layout.list_header,null);
}
TextView headerTv = view.findViewById(R.id.headerTv);
headerTv.setText(heading+"");
boolean hasSelected = false;
ArrayList<ChildDataModel> childs = childData.get(headerData.get(headPosition));
for(int i=0;i<childs.size();i++){
if(childs.get(i).getTitle().equalsIgnoreCase( "China" )){
hasSelected = true;
}}
if(hasSelected)
view.setBackgroundColor( Color.BLUE );
else
view.setBackgroundColor( Color.RED);
return view;
}
I'm implementing an ExpandableListView on my app and I try to detect when the scroll hits the bottom of this ExpandableListView. I've tried using onScrollListener and onScrollChangedListener.
For the onScrollListener, it is called way too many times to be an acceptable solution.
However for the onScrollChangedListener, it seems to be what I want. The problem is that as ExpandableListView doesn't have 1 child level but 2, I don't manage to find a way to identify the last visible element.
Has anyone already implemented this kind of behaviour on an ExpandableListView ?
You can done via getting position of last group when it expand
expandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
if(groupPosition == expandableListView.getExpandableListAdapter().getGroupCount()){
// your code goes here
}
return false;
}
});
Try below sample:-
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<ExpandableListView
android:id="#+id/elvMain"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ExpandableListView>
</LinearLayout>
MainActivity.java:
public class MainActivity extends AppCompatActivity {
ArrayList<String> mainGroupList;
HashMap<String, ArrayList<String>> mainChildList;
CustomAdapter mainAdapter;
ExpandableListView elvMain;
int newDataSet = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
elvMain = findViewById(R.id.elvMain);
mainGroupList = new ArrayList<>();
mainChildList = new HashMap<>();
for(int i = 0; i < 20; i++){
ArrayList<String> tmpList = new ArrayList<>();
for(int j = 0; j< 17; j++){
tmpList.add("Child " + j);
}
mainChildList.put("Group " + i, tmpList);
mainGroupList.add("Group " + i);
}
mainAdapter = new CustomAdapter(this, mainGroupList, mainChildList);
elvMain.setAdapter(mainAdapter);
elvMain.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView absListView, int i) {}
#Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
if(i2 == i + i1){
View lastView = absListView.getChildAt(i1 - 1);
if(lastView.getBottom() == absListView.getBottom()){
try{
String viewTag = lastView.getTag().toString();
if(viewTag.equals("Group")){
Toast.makeText(getApplicationContext(),
"No more data, unless expanded the last group!!",
Toast.LENGTH_SHORT).show();
//elvMain.expandGroup(mainAdapter.getGroupCount() - 1);
}
}catch(Exception e){
addNewData();
}
}
}
}
});
}
private void addNewData(){
newDataSet++;
for(int i = 0; i < 5; i++){
ArrayList<String> tmpList = new ArrayList<>();
for(int j = 0; j< 7; j++){
tmpList.add("Child " + j);
}
mainChildList.put("Added " + newDataSet + ",Group " + i, tmpList);
mainGroupList.add("Added " + newDataSet + ",Group " + i);
}
mainAdapter.notifyDataSetChanged();
}
}
CustomAdapter.java:
public class CustomAdapter extends BaseExpandableListAdapter {
ArrayList<String> groupList;
HashMap<String, ArrayList<String>> childList;
LayoutInflater inflater;
public CustomAdapter(Context context, ArrayList<String> groupList, HashMap<String, ArrayList<String>> childList) {
this.inflater = LayoutInflater.from(context);
this.groupList = groupList;
this.childList = childList;
}
#Override
public int getGroupCount() {
return groupList.size();
}
#Override
public int getChildrenCount(int i) {
return childList.get(groupList.get(i)).size();
}
#Override
public String getGroup(int i) {
return groupList.get(i);
}
#Override
public String getChild(int i, int i1) {
return childList.get(groupList.get(i)).get(i1);
}
#Override
public long getGroupId(int i) {
return i;
}
#Override
public long getChildId(int i, int i1) {
return 0;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
if(view == null) view = inflater.inflate(android.R.layout.simple_list_item_1, null);
TextView textView = view.findViewById(android.R.id.text1);
textView.setText(getGroup(i));
view.setTag("Group");
return view;
}
#Override
public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
if(view == null) view = inflater.inflate(android.R.layout.simple_list_item_1, null);
TextView textView = view.findViewById(android.R.id.text1);
textView.setText(getChild(i, i1));
return view;
}
#Override
public boolean isChildSelectable(int i, int i1) {
return false;
}
}
In this sample, I use setTag() to identify the view is "Group". If you use different layouts for group view and child view, then you may use findViewById() to find a view that is inside the group view and so no changes in your adapter.
In addition, inside the try-catch, you can comment out the Toast() and enable the code elvMain.expandGroup(mainAdapter.getGroupCount() - 1); which automatically expand the last group when the list is scrolled to the bottom, so the ExpandableListView becomes endless.
Hope that helps!
try this solution
Detect when RecyclerView reaches the bottom most position while scrolling - check answer of Kaustubh Bhagwat
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (!recyclerView.canScrollVertically(1)) {
Toast.makeText(YourActivity.this, "Last", Toast.LENGTH_LONG).show();
}
}
});
In java main activity i have loaded the data in my initData method, however when i run the app, the category grouping only lists one category from the database with the datalist items for each category listing. The correct functioning is to list all the category data and then the item lists under each grouping. Below is my code
I have created an Expandable list view in XML and also created the Expandable list Adapter class, which pulls item Category and item category list from two tables in my SQLite db . In java main activity i have loaded the data, however when i run the app, the category grouping only list one category from the database with the datalist items.
this is my initData method
private void initData() {
Cursor category1 = controller.categotyforGroupedLv();
Cursor itemListCategory = controller.getFPMsster();
listDataHeader = new ArrayList<>();
List<String> listDataItem = new ArrayList<>();
listHash = new HashMap<>();
if (category1.getCount() != 0) {
//move to the first row
category1.moveToFirst();
// Toast.makeText(this, "Data found", Toast.LENGTH_SHORT).show();
//return;
}
for (int i = 0; i < category1.getCount(); i++) {
while (category1.moveToNext()) {
while (itemListCategory.moveToNext()) {
listDataHeader.add(" " + category1.getString(1));
listDataItem.add(" " + itemListCategory.getString(2));
}
listHash.put(listDataHeader.get(0), listDataItem);
}
}
}
}
this is my expandable List Adapter class
public class ExpandableListAdapter extends BaseExpandableListAdapter {
private Context context;
private List<String> listDataHeader;
private HashMap<String,List<String>> listHashMap;
public ExpandableListAdapter(Context context, List<String> listDataHeader, HashMap<String, List<String>> listHashMap) {
this.context = context;
this.listDataHeader = listDataHeader;
this.listHashMap = listHashMap;
}
#Override
public int getGroupCount() {
return listDataHeader.size();
}
#Override
public int getChildrenCount(int i) {
return listHashMap.get(listDataHeader.get(i)).size();
}
#Override
public Object getGroup(int i) {
return listDataHeader.get(i);
}
#Override
public Object getChild(int i, int i1) {
return listHashMap.get(listDataHeader.get(i)).get(i1); //i = group item , i1 =Child item
}
#Override
public long getGroupId(int i) {
return i;
}
#Override
public long getChildId(int i, int i1) {
return i1;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
String headerTitle = (String)getGroup(i);
if (view == null)
{
LayoutInflater inflater = (LayoutInflater)this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.order_taking_screen_listgroup_for_listview, null);
}
TextView listheader1 = (TextView)view.findViewById(R.id.listheader);
listheader1.setTypeface(null, Typeface.BOLD);
listheader1.setText(headerTitle);
return view;
}
#Override
public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
final String childText = (String)getChild(i, i1);
if(view == null)
{
LayoutInflater inflater = (LayoutInflater)this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.order_taking_screen_listitem_for_listview, null);
}
TextView listchild = (TextView)view.findViewById(R.id.listitem);
listchild.setText(childText);
return view;
}
#Override
public boolean isChildSelectable(int i, int i1) {
return true;
}
}
Try this:
private void initData() {
Cursor category1 = controller.categotyforGroupedLv();
Cursor itemListCategory;
listDataHeader = new ArrayList<>();
listHash = new HashMap<>();
if (category1.getCount() != 0) {
//move to the first row
category1.moveToFirst();
// Toast.makeText(this, "Data found", Toast.LENGTH_SHORT).show();
//return;
while (category1.moveToNext()) {
listDataHeader.add(" " + category1.getString(1));
// Child item should be based on group data.
itemListCategory = controller.getFPMsster(category1.getString(1));
// Create single child list.
List<String> listDataItem = new ArrayList<>();
if (itemListCategory.getCount() != 0) {
while(itemListCategory.moveToNext()) {
listDataItem.add(" " + itemListCategory.getString(2));
}
}
// Add single child into the overall child list.
listHash.put(listDataHeader.get(listDataHeader.size() - 1), listDataItem);
}
}
}
Please note that you need to change your getFPMsster() method to take an argument because the cursor should only return data for a specific group. You may also take a look of this link: GridView Within ExpandableListView With Database Hope that helps!
So I have this ExpandableListView that should highlight the groups that are clicked.
I do this by running
eList.getChildAt(eList.getFlatListPosition(ExpandableListView.getPackedPositionForGroup(i))).setBackgroundColor(Color.LTGRAY);
whereas i is the index of the group's view that was clicked.
However, as you can see in the image provided here, it only returns the correct view when I'm traversing upwards the list.
http://i.imgur.com/I9e943A.gif
I should note that when I have the onGroupClick() set to return false, getChildAt returns the correct value and the correct group view is highlighted. However, having it set to false would result in groups opening twice when clicked(twice as many child elements), as I'm "manually" collapsing/expanding the groups as the /searchterm/ changes.
For debugging purposes I tried to highlight the getChildAt(1) when any group was clicked. The "1" group was highlighted in all cases except for when I clicked the "0" group, whereas the last group was highlighted instead.
Classes can be found below
MainActivity:
public class MainActivity extends ActionBarActivity {
HashMap<String, List<String>> categoryName;
List<String> categoryList;
ExpandableListView eList;
CategoryAdapter adapter;
EditText textField;
int lastHighlightParent = -1;
int lastHighlightChild = -1;
int groupToHighlight;
String prevDirName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("Laboration 2");
setContentView(R.layout.activity_main);
textField = (EditText) findViewById(R.id.etTextField);
textField.setText("€/€");
eList = (ExpandableListView) findViewById(R.id.exp_list);
textField.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
if (lastHighlightChild != -1 && lastHighlightParent != -1) {
eList.getChildAt(
eList.getFlatListPosition(ExpandableListView
.getPackedPositionForChild(
lastHighlightParent,
lastHighlightChild)))
.setBackgroundColor(Color.TRANSPARENT);
lastHighlightChild = -1;
lastHighlightParent = -1;
}
for (int i = 0; i < eList.getChildCount(); i++) {
eList.getChildAt(i).setBackgroundColor(Color.TRANSPARENT);
}
boolean match = false;
for (int i = 0; i < adapter.getGroupCount(); i++) {
for (int j = 0; j < adapter.getChildrenCount(i); j++) {
String tempPath = "/" + adapter.getGroupText(i) + "/"
+ adapter.getChildText(i, j);
if (tempPath.startsWith(s.toString())
&& s.toString().length() > 1 && match != true) {
groupToHighlight = eList.getFlatListPosition(ExpandableListView
.getPackedPositionForGroup(i));
eList.getChildAt(eList.getFlatListPosition(ExpandableListView
.getPackedPositionForGroup(i))).setBackgroundColor(Color.LTGRAY);
textField.setBackgroundColor(Color.TRANSPARENT);
match = true;
} else if (s.toString().equals("/") || s.length() == 0) {
textField.setBackgroundColor(Color.TRANSPARENT);
} else {
if (match != true) {
eList.getChildAt(i).setBackgroundColor(
Color.TRANSPARENT);
textField.setBackgroundColor(Color.RED);
}
}
}
}
for (int i = 0; i < adapter.getGroupCount(); i++) {
if (s.toString().startsWith(
"/" + adapter.getGroupText(i) + "/")) {
if (!eList.isGroupExpanded(i)) {
eList.expandGroup(i);
}
for (int j = 0; j < adapter.getChildrenCount(i); j++) {
if (s.toString().endsWith(
adapter.getChildText(i, j))) {
eList.getChildAt(
eList.getFlatListPosition(ExpandableListView
.getPackedPositionForChild(i, j)))
.setBackgroundColor(Color.GRAY);
lastHighlightParent = i;
lastHighlightChild = j;
}
}
} else {
eList.collapseGroup(i);
}
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
eList.setOnChildClickListener(new OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
textField.setText("/" + adapter.getGroupText(groupPosition)
+ "/"
+ adapter.getChildText(groupPosition, childPosition));
return false;
}
});
eList.setOnGroupClickListener(new OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
if (adapter.getGroupText(groupPosition).equals(prevDirName)
&& eList.isGroupExpanded(groupPosition)) {
eList.collapseGroup(groupPosition);
} else {
textField.setText("/" + adapter.getGroupText(groupPosition)
+ "/");
}
prevDirName = adapter.getGroupText(groupPosition);
return true;
}
});
categoryName = listData();
categoryList = new ArrayList<String>(categoryName.keySet());
adapter = new CategoryAdapter(this, categoryName, categoryList);
eList.setAdapter(adapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private HashMap<String, List<String>> listData() {
HashMap<String, List<String>> categoryDetail = new HashMap<String, List<String>>();
List<String> drinks = new ArrayList<String>();
drinks.add("Tea");
drinks.add("Coffee");
drinks.add("Water");
drinks.add("Lemonade");
drinks.add("Beer");
List<String> animals = new ArrayList<String>();
animals.add("Cat");
animals.add("Dog");
animals.add("Dromedary");
animals.add("Boar");
List<String> vegetables = new ArrayList<String>();
vegetables.add("Lettuce");
vegetables.add("Tomato");
vegetables.add("Spinach");
vegetables.add("Cucumber");
List<String> colors = new ArrayList<String>();
colors.add("Blue");
colors.add("Red");
colors.add("Pink");
colors.add("Brown");
List<String> sodas = new ArrayList<String>();
sodas.add("Cola");
sodas.add("Pepsi");
sodas.add("Fanta");
sodas.add("7-up");
categoryDetail.put("Animals", animals);
categoryDetail.put("Vegetables", vegetables);
categoryDetail.put("Colors", colors);
categoryDetail.put("Sodas", sodas);
categoryDetail.put("Drinks", drinks);
return categoryDetail;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
textField.setText(item.getTitle());
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Adapter:
public class CategoryAdapter extends BaseExpandableListAdapter {
private Context context;
private HashMap<String, List<String>> categories;
private List<String> categoryList;
public CategoryAdapter(Context m_context, HashMap<String, List<String>> m_categories, List<String> m_categoryList){
this.context = m_context;
this.categories = m_categories;
this.categoryList = m_categoryList;
}
public String getGroupText(int groupPosition){
Object[] keys = this.categories.keySet().toArray();
return (String) keys[groupPosition];
}
public String getChildText(int groupPosition, int childPosition){
Object[] keys = this.categories.keySet().toArray();
return (String) categories.get(keys[groupPosition]).get(childPosition);
}
#Override
public int getGroupCount() {
return categoryList.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return categories.get(categoryList.get(groupPosition)).size();
}
#Override
public Object getGroup(int groupPosition) {
return categoryList.get(groupPosition);
}
#Override
public Object getChild(int parent, int child) {
return categories.get(categoryList.get(parent)).get(child);
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public long getChildId(int parent, int child){
return child;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public View getGroupView(int parent, boolean isExpanded,
View convertView, ViewGroup parentView) {
String groupTitle = (String) getGroup(parent);
if(convertView == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.parent_layout, parentView, false);
}
TextView parentTextView = (TextView) convertView.findViewById(R.id.parent_txt);
parentTextView.setTypeface(null, Typeface.BOLD);
parentTextView.setText(groupTitle);
return convertView;
}
#Override
public View getChildView(int parent, int child,
boolean isLastChild, View convertView, ViewGroup parentView) {
String childTitle = (String) getChild(parent, child);
if (convertView == null) {
LayoutInflater inflat = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflat.inflate(R.layout.child_layout, parentView, false);
}
TextView childTextView = (TextView) convertView.findViewById(R.id.child_txt);
childTextView.setText(childTitle);
return convertView;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
I have a custom list view, contains delete button and spinner (the spinner contain A-E characters).
And I have an issue with deleting the true row from my custom list view.
Custom list view code:
public class customListView extends BaseAdapter
{
public Activity context;
ArrayList<MyActivity.UserProperties> userPropertieses;
public String[] spinnerValues;
public LayoutInflater inflater;
public customListView(Activity context, ArrayList<MyActivity.UserProperties> userPropertieses, String[] spinnerArray)
{
super();
this.context = context;
this.userPropertieses = userPropertieses;
spinnerValues = spinnerArray;
this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() { return userPropertieses.size(); }
#Override
public Object getItem(int i) { return null; }
#Override
public long getItemId(int i) { return 0; }
class ViewHolder
{
Button btnRemove;
Spinner spinner;
}
#Override
public View getView(final int i, View view, ViewGroup viewGroup)
{
final ViewHolder holder;
if (view == null)
{
holder = new ViewHolder();
view = inflater.inflate(R.layout.custom_layout, null);
holder.spinner = (Spinner) view.findViewById(R.id.spinner);
holder.btnRemove = (Button) view.findViewById(R.id.bu_Remove);
// populate spinner
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>
(view.getContext(), android.R.layout.simple_spinner_item, spinnerValues);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
holder.spinner.setFocusable(true);
holder.spinner.requestFocus();
holder.spinner.setAdapter(dataAdapter);
view.setTag(holder);
// remove user implementation
holder.btnRemove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i("custom list view debug", "i = " + i); // debug. verify i value is correct
((MyActivity) context).deleteUser(i);
}
});
}
else
holder = (ViewHolder) view.getTag();
return view;
}
}
And my main activity code looks like this:
public class MyActivity extends Activity
{
ListView listView;
ArrayList<UserProperties> userProperties = new ArrayList<UserProperties>();
customListView adapter;
SensorManager sensorManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
for (int i = 0; i<5; i++) {
userProperties.add(new UserProperties());
}
listView = (ListView) findViewById(R.id.listView);
String[] spinnerValues = new String[] {"A", "B", "C", "D", "E"};
adapter = new customListView(MyActivity.this, userProperties, spinnerValues);
listView.setAdapter(adapter);
}
public void deleteUser (int index)
{
Log.i("debug", "Removing item " + index); // the index is really true and the true node deleting from the ArrayList but somehow the latest delete from the UI
userProperties.remove(index);
adapter.notifyDataSetChanged();
}
}
When I click on the Remove button deleteUser method called with the right index. but although the right node deleting from userProperties ArrayList somehow after notiftDataSetChanged is still alive
and the latest node delete.
So, How can I delete the right node/row (from the ArrayList and UI...)
Thank you!
EDIT:
Just to be clear, i variable contain true index. The true node deleted from the ArrayList. but something append after I called notify method.
I prefer to stay with BaseAdapter and not implement ArrayAdapter. Thank you!
EDIT 2:
After more debugging I found out my question was wrong. the true row really deleted just spinner values somehow update their values. I cannot close the question because it already answered. Thanks.
((MyActivity) context).deleteUser(i);
This line will always delete the first value from the ListView
You can use CAB (contextual action bar)
See if the code helps you(it's basically a ListActivity with a custom adapter to hold the status of checked items(+ different background)):
public class CABSelection extends ListActivity {
private ArrayList<String> mItems = new ArrayList<String>();
private SelectionAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
for (int i = 0; i < 24; i++) {
mItems.add("Name" + i);
}
// R.layout.adapters_cabselection_row is a LinearLayout(with green
// background(#99cc00)) that wraps an ImageView and a TextView
mAdapter = new SelectionAdapter(this,
R.layout.adapters_cabselection_row, R.id.the_text, mItems);
setListAdapter(mAdapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() {
private int nr = 0;
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.cabselection_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
StringBuilder sb = new StringBuilder();
Set<Integer> positions = mAdapter.getCurrentCheckedPosition();
for (Integer pos : positions) {
sb.append(" " + pos + ",");
}
switch (item.getItemId()) {
case R.id.edit_entry:
Toast.makeText(CABSelection.this, "Edited entries: " + sb.toString(),
Toast.LENGTH_SHORT).show();
break;
case R.id.delete_entry:
Toast.makeText(CABSelection.this, "Deleted entries : " + sb.toString(),
Toast.LENGTH_SHORT).show();
break;
case R.id.finish_it:
nr = 0;
mAdapter.clearSelection();
Toast.makeText(CABSelection.this, "Finish the CAB!",
Toast.LENGTH_SHORT).show();
mode.finish();
}
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
nr = 0;
mAdapter.clearSelection();
}
#Override
public void onItemCheckedStateChanged(ActionMode mode,
int position, long id, boolean checked) {
if (checked) {
nr++;
mAdapter.setNewSelection(position, checked);
} else {
nr--;
mAdapter.removeSelection(position);
}
mode.setTitle(nr + " rows selected!");
}
});
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
l.setItemChecked(position, !mAdapter.isPositionChecked(position));
}
private class SelectionAdapter extends ArrayAdapter<String> {
private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
public SelectionAdapter(Context context, int resource,
int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
}
public void setNewSelection(int position, boolean value) {
mSelection.put(position, value);
notifyDataSetChanged();
}
public boolean isPositionChecked(int position) {
Boolean result = mSelection.get(position);
return result == null ? false : result;
}
public Set<Integer> getCurrentCheckedPosition() {
return mSelection.keySet();
}
public void removeSelection(int position) {
mSelection.remove(position);
notifyDataSetChanged();
}
public void clearSelection() {
mSelection = new HashMap<Integer, Boolean>();
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);//let the adapter handle setting up the row views
v.setBackgroundColor(Color.parseColor("#99cc00")); //default color
if (mSelection.get(position) != null) {
v.setBackgroundColor(Color.RED);// this is a selected position so make it red
}
return v;
}
}
}
Another way
adapter = new MyListAdapter(this);
lv = (ListView) findViewById(android.R.id.list);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> a, View v, int position, long id) {
AlertDialog.Builder adb=new AlertDialog.Builder(MyActivity.this);
adb.setTitle("Delete?");
adb.setMessage("Are you sure you want to delete " + position);
final int positionToRemove = position;
adb.setNegativeButton("Cancel", null);
adb.setPositiveButton("Ok", new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
MyDataObject.remove(positionToRemove);
adapter.notifyDataSetChanged();
}});
adb.show();
}
});
getView(final int i,
Do not make i final. You did that to use i in onClick(). But that is not possible. So remove the final. Add:
holder.btnRemove.setTag(i);
And in onClick:
int position = v.getTag();
..deleteUser(position);
Maybe you have to cast something somewhere..
Remark: You have to set the tag always. So do it just before return view;.
Please do not use an i for position.