I've just gotten an ExpandableListView setup and everything works fine so far. On the group/parent I have a TextView and and Button. The purpose of the list is to have people sample different sounds that are included in the app, and it they click the button then the sounds will be saved to the SD Card. Here's a link to what I have so far: http://imgur.com/djSCIrG
My question is whether or not it's possible that after someone clicks the button and chooses to purchase the pack if it's possible to hide just that one button and not all of the buttons in every group.
Here's is my main layout (expandablelistview_main.xml):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="#+id/soundpacktitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/expandablelistview_main_soundpacktitle_topmargin"
android:layout_centerHorizontal="true"
android:text="#string/soundpacktitle"
android:textSize="#dimen/expandablelistview_main_soundpacktitle_textsize" />
<ExpandableListView
android:id="#+id/soundpacklist"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_below="#+id/soundpacktitle"
android:layout_above="#+id/soundpackbottombar"
android:layout_marginTop="#dimen/expandablelistview_main_soundpacklist_topmargin"
android:transcriptMode="disabled"
android:cacheColorHint="#00000000"
android:listSelector="#android:color/transparent" />
</RelativeLayout>
Here is my group/parent layout (expandablelistview_group.xml):
<?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="?android:attr/listPreferredItemHeight"
android:orientation="horizontal" >
<TextView
android:id="#+id/grouptextview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:layout_marginLeft="#dimen/expandablelistview_group_grouptextview_leftmargin"
android:textSize="#dimen/expandablelistview_group_grouptextview_textsize" />
<Button
android:id="#+id/buypackbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_alignParentRight="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="#string/buypack"
android:padding="#dimen/expandablelistview_group_buypackbutton_padding"
android:textSize="#dimen/expandablelistview_group_buypackbutton_textsize"
android:textStyle="bold" />
</RelativeLayout>
Here is my java class:
public class InAppSounds extends Activity {
private ExpandableListView soundpacklist;
private ArrayList<String> groups;
private ArrayList<ArrayList<ArrayList<String>>> childs;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.expandablelistview_main);
TextView soundpacktitle = (TextView) findViewById(R.id.soundpacktitle);
soundpacktitle.setTypeface(printbold);
// Declare the ExpandableListView and set's the indicator to the list arrows
soundpacklist = (ExpandableListView) findViewById(R.id.soundpacklist);
soundpacklist.setGroupIndicator(getResources().getDrawable(R.drawable.list_groupselector));
LoadData();
myExpandableAdapter adapter = new myExpandableAdapter(this, groups, childs);
soundpacklist.setAdapter(adapter);
}
// Loads the ExpandableListView with parent and children groups
private void LoadData() {
groups = new ArrayList<String>();
childs = new ArrayList<ArrayList<ArrayList<String>>>();
// String array that stores the parent and child names
String[] soundpackgroups = getResources().getStringArray(R.array.soundpackgroups);
String[] soundpack1 = getResources().getStringArray(R.array.soundpack1);
String[] soundpack2 = getResources().getStringArray(R.array.soundpack2);
String[] soundpack3 = getResources().getStringArray(R.array.soundpack3);
// First Sound Pack and their songs
groups.add(soundpackgroups[0]);
childs.add(new ArrayList<ArrayList<String>>());
for (int a = 0; a < soundpack1.length; a++) {
childs.get(0).add(new ArrayList<String>());
childs.get(0).get(a).add(soundpack1[a]);
}
// Second Sound Pack and their songs
groups.add(soundpackgroups[1]);
childs.add(new ArrayList<ArrayList<String>>());
for (int a = 0; a < soundpack2.length; a++) {
childs.get(1).add(new ArrayList<String>());
childs.get(1).get(a).add(soundpack2[a]);
}
// Third Sound Pack and their songs
groups.add(soundpackgroups[2]);
childs.add(new ArrayList<ArrayList<String>>());
for (int a = 0; a < soundpack3.length; a++) {
childs.get(2).add(new ArrayList<String>());
childs.get(2).get(a).add(soundpack3[a]);
}
}
public class myExpandableAdapter extends BaseExpandableListAdapter {
private final ArrayList<String> groups;
private final ArrayList<ArrayList<ArrayList<String>>> children;
private final Context context;
public myExpandableAdapter(Context context, ArrayList<String> groups,
ArrayList<ArrayList<ArrayList<String>>> children) {
this.context = context;
this.groups = groups;
this.children = childs;
}
#Override
public boolean areAllItemsEnabled() {
return true;
}
#Override
public ArrayList<String> getChild(int groupPosition, int childPosition) {
return children.get(groupPosition).get(childPosition);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
String child = getChild(groupPosition, childPosition).get(0);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.expandablelistview_child, null);
}
// TypeFace variable for the PrintBold
printbold = Typeface.createFromAsset(getAssets(), "fonts/PrintBold.otf");
TextView childtxt = (TextView) convertView.findViewById(R.id.childtextview);
childtxt.setTypeface(printbold);
childtxt.setText(child);
return convertView;
}
#Override
public int getChildrenCount(int groupPosition) {
return children.get(groupPosition).size();
}
#Override
public String getGroup(int groupPosition) {
return groups.get(groupPosition);
}
#Override
public int getGroupCount() {
return groups.size();
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
final String group = getGroup(groupPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.expandablelistview_group, null);
}
// TypeFace variable for the PrintBold
printbold = Typeface.createFromAsset(getAssets(), "fonts/PrintBold.otf");
TextView grouptxt = (TextView) convertView.findViewById(R.id.grouptextview);
grouptxt.setTypeface(printbold);
grouptxt.setText(group);
final Button buypackbutton = (Button) convertView.findViewById(R.id.buypackbutton);
buypackbutton.setClickable(true);
buypackbutton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
AlertDialog.Builder alert = new AlertDialog.Builder(InAppSounds.this);
if (group.equals("Pack #1")) {
alert.setCancelable(false);
alert.setTitle(getString(R.string.buypacktitle));
alert.setIcon(getResources().getDrawable(R.drawable.ic_audioicon));
alert.setMessage(getString(R.string.buypackmsg));
alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// check to make sure the SD card is mounted
// if not display an AlertDialog
if (!isSDPresent()) {
sdcardalert();
}
else {
// this will erase the button in all the groups, not just this group
buypackbutton.setVisibility(View.INVISIBLE);
}
}
});
alert.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alert.show();
}
}
});
return convertView;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
}
I would appreciate any guidance in this matter. Thanks
Yes. It's easy. All that you have to do is get a reference to your button and set the visibility to gone. Like this:
Button sampleButton = (Button) findViewById(R.id.sample_button);
sampleButton.setVisiblity(View.GONE);
Note: when you set it to View.GONE the layout space that was initially given to it is also removed. If you just want to remove the button and keep the layout space use
View.INVISIBLE instead.
EDIT: Here's how I would keep the button from reappearing: First, I would use a boolean to track the status of the button while the activity is active. Then in your override of getChildView I would check this boolean and set the visibility accordingly. Maybe insert something like this into the getChildView callback to keep the button from reappearing when the list item is clicked:
if (!showButton) {
Button button = (Button) findViewById(R.id.sample_button);
button.setVisibility(View.GONE);
}
As for coming back to the screen. To keep track of the whether not to show the button I would use a boolean and store it in SharedPreferences. Then, also in the getChildView callback, check the status of the boolean and set it accordingly. Something like this:
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean showButtonStatusPref = settings.getBoolean("showButton", true);
if(!showButtonStatusPref) {
Button button = (Button) findViewById(R.id.sample_button);
button.setVisibility(View.GONE);
}
The only other thing you need to do is manage the status of each button.
EDIT 2: I completely overlooked the fact that the same layout is used for the child views (duh! brain cramp :)).
You could still use shared preferences to keep track of which samples have been downloaded (you could use Set for this). You would also need to create a way to assign "identifiers" to each sample. From there all that you would have to do is perform a check every time getChildView() is called and, if the Set contains the selected sample identifier, set the button visibility to gone. That should take care of showing the button when the sample hasn't been downloaded and not showing the button when the sample has been downloaded. Maybe something like this in the getChildView():
Set<String> defaultSet = new SortedSet<String>();
defaultSet.add("Nothing downloaded");
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SortedSet<String> listOfDowloaded = settings.getStringSet("isDownloadedList", );
if (listOfDownLoaded.contains(sampleDownloadIdentifier)) {
Button button = (Button) findViewById(R.id.some_id);
button.setVisiblity(View.GONE);
}
Related
I am trying to filter a custom List View with a custom Adapter. I am having problems with duplicating the original Data and putting it back in the list, when the search parameter changes or goes to empty. The filtering does work for the first input character, but if this is changed, it won't search the whole dataset again. I know that this is because I need a duplicate list of the original data but I can't really get it to work, because I don't know how to properly implement it because I am using a custom Class as my Datatype. I only use the name and category property of it though, the names are the actual items and it is also sorted by categories.
I based my Adapter off of this example: https://gist.github.com/fjfish/3024308
And here is my code for the List Adapter:
class DataListAdapter extends BaseAdapter implements Filterable {
private Context mContext;
private List<Object> originalData = null;
private List<Object> filteredData = null;
private static final int CARRIER = 0;
private static final int HEADER = 1;
private LayoutInflater inflater;
private ItemFilter mFilter = new ItemFilter();
DataListAdapter(Context context, List<Object> input) {
this.mContext = context;
this.originalData = input;
this.filteredData = input;
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getItemViewType(int position) {
if (originalData.get(position) instanceof Carrier) {
return CARRIER;
} else {
return HEADER;
}
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getCount() {
return originalData.size();
}
#Override
public Object getItem(int position) {
return originalData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#SuppressLint("InflateParams")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
switch (getItemViewType(position)) {
case CARRIER:
convertView = inflater.inflate(R.layout.listview_item_data_layout, null);
break;
case HEADER:
convertView = inflater.inflate(R.layout.listview_header_data_layout, null);
break;
}
}
switch (getItemViewType(position)) {
case CARRIER:
TextView name = (TextView) convertView.findViewById(R.id.fragment_data_list_view_carrier_name);
name.setText(((Carrier) originalData.get(position)).get_name());
break;
case HEADER:
TextView category = (TextView) convertView.findViewById(R.id.fragment_data_list_view_category);
category.setText((String) originalData.get(position));
break;
}
return convertView;
}
#Override
public Filter getFilter() {
return mFilter;
}
private class ItemFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
DatabaseHelper dbHelper = new DatabaseHelper(mContext, null, null, 1);
String filterString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
final List<Object> list = originalData;
int count = list.size();
final List<Object> nlist = new ArrayList<>(count);
String filterableString = "";
for (int i = 0; i < count; i++) {
switch (getItemViewType(i)) {
case CARRIER:
filterableString = ((Carrier)list.get(i)).get_name();
break;
case HEADER:
filterableString = "";
break;
}
if(filterableString.toLowerCase().contains(filterString)) {
nlist.add(dbHelper.getCarriersWithName(filterableString).get(0));
}
}
results.values = nlist;
results.count = nlist.size();
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if(results.count == 0) {
notifyDataSetInvalidated();
} else {
originalData = (List<Object>)results.values;
notifyDataSetChanged();
}
}
}
}
My main activity obviously looks like this, which should be fine. The problem lays in the filtered Data List, which I can't get to work.
List<Object> combinedCategoryCarrierList = dbHelper.getCombinedCategoryCarrierList();
adapter = new DataListAdapter(mContext, combinedCategoryCarrierList);
listView.setAdapter(adapter);
listView.setTextFilterEnabled(true);
searchEditText = (EditText) view.findViewById(R.id.fragment_data_search);
searchEditText.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) {
}
#Override
public void afterTextChanged(Editable s) {
adapter.getFilter().filter(searchEditText.getText().toString());
}
});
I would greatly appreciate it if someone can show me an example of how to do that with custom data types and section headers combined. Or even change my code :) I can't really find examples where all of that applies.
Edit: The screen looks like this, so I want to keep the category headers when filtering.
I did not find a solution to my original problem, but I came up with a better approach to the whole situation. I didn't know there was an ExpandableListView available in Android. This is basically a ListView, but the items are divided into Groups and their Childs which are expandable and collapsable, so exactly what I wanted.
Here is how I implemented it with working filters and groups:
So, to start off, here is my main layout file. Please note that I am using Fragments, which is why the code is a bit different in terms of getting the context for example. The functionality of the component stays the same though.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<EditText
android:id="#+id/fragment_data_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:hint="#string/data_search_hint"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp" />
<ExpandableListView
android:id="#+id/fragment_data_expandable_list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:groupIndicator="#null" />
</LinearLayout>
You will also need two layout files for your header/group items and for your child items. My header item has a TextView which displays the category name and an ImageView which displays a + or - to show if the category is collapsed or expanded.
Here is my header layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorAccent"
android:descendantFocusability="blocksDescendants" >
<TextView
android:id="#+id/fragment_data_list_view_category"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:gravity="start"
android:textStyle="bold"
android:textSize="18sp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:textColor="#android:color/primary_text_light"
android:text="#string/placeholder_header_listview"
android:maxLines="1"
android:ellipsize="end" />
<ImageView
android:id="#+id/fragment_data_list_view_category_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_gravity="end"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:contentDescription="#string/content_description_list_view_header"
android:src="#drawable/ic_remove_black_24dp"
android:tag="maximized"/>
</RelativeLayout>
The property android:descendantFocusability="blocksDescendants" fixed a bug when I tried setting an onItemClickListener. If you have that problem, try using RelativeLayout's for your child layout if you're not already. It fixed it for me, the onClickItemListener did not execute with a LinearLayout.
And here is my layout file for the child items:
<?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"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:descendantFocusability="blocksDescendants" >
<TextView
android:id="#+id/fragment_data_list_view_carrier_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/placeholder_item_listview"
android:textSize="18sp"
android:textStyle="normal"
android:textColor="#android:color/primary_text_light"
android:maxLines="1"
android:ellipsize="end" />
</RelativeLayout>
The following code is from my fragment class, which handles all the logic for the ExpandableListView:
public class Fragment_Data extends Fragment {
private Context mContext;
private ExpandableListView expandableListView;
private List<String> categories_list;
private HashMap<String, List<Carrier>> carriers_list;
private DataExpandableListAdapter adapter;
private DatabaseHelper dbHelper;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle(R.string.nav_item_data);
}
This first part shows the declaration of needed variables and the necessary method onViewCreated. The Carrier class is a custom object with properties like name, category and so on. The DatabaseHelper is also a custom class which handley my database and gets all the data for me, which is casted into Carrier objects. You can of course use anything you like as data types.
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_data_layout, container, false);
mContext = getContext();
expandableListView = (ExpandableListView) view.findViewById(R.id.fragment_data_expandable_list_view);
dbHelper = new DatabaseHelper(mContext, null, null, 1);
adapter = new DataExpandableListAdapter(mContext, categories_list, carriers_list);
displayList();
expandAllGroups();
EditText searchEditText = (EditText) view.findViewById(R.id.fragment_data_search);
searchEditText.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) {
adapter.filterData(s.toString());
expandAllGroups();
}
#Override
public void afterTextChanged(Editable s) {
}
});
expandableListView.setOnItemLongClickListener(deleteSelectedItem);
expandableListView.setOnChildClickListener(editSelectedItem);
return view;
}
The onCreate method deals with all the important stuff like setting the adapter, inflating the layout and setting onClick events for the items and a onTextChange event for the search field.
private void expandAllGroups() {
for(int i = 0; i < adapter.getGroupCount(); i++) {
expandableListView.expandGroup(i);
}
}
private void displayList() {
prepareListData();
adapter = new DataExpandableListAdapter(mContext, categories_list, carriers_list);
expandableListView.setAdapter(adapter);
expandAllGroups();
}
private void prepareListData() {
categories_list = new ArrayList<>();
carriers_list = new HashMap<>();
categories_list = dbHelper.getCategoryList();
for(int i = 0; i < categories_list.size(); i++) {
List<Carrier> carrierList = dbHelper.getCarriersWithCategory(categories_list.get(i));
carriers_list.put(categories_list.get(i), carrierList);
}
}
With expandAllGroups() you can simply expand all groups, because they are collapsed by default. The displayList() simply sets the Adapter for the ExpandableListView and calls prepareListData(), which fills both the category (group) list and the carrier (child) list. Note that the child List is a hashmap with the key being the category and the value a Carrier List by itself, so the Adapter knows which child items belong to which parent.
Here is the code for the Adapter:
class DataExpandableListAdapter extends BaseExpandableListAdapter {
private Context mContext;
private List<String> list_categories = new ArrayList<>();
private List<String> list_categories_original = new ArrayList<>();
private HashMap<String, List<Carrier>> list_carriers = new HashMap<>();
private HashMap<String, List<Carrier>> list_carriers_original = new HashMap<>();
DataExpandableListAdapter(Context context, List<String> categories, HashMap<String, List<Carrier>> carriers) {
this.mContext = context;
this.list_categories = categories;
this.list_categories_original = categories;
this.list_carriers = carriers;
this.list_carriers_original = carriers;
}
You need to have a copy of both of your original lists, if you want to use filtering. This is used for restoring all data when the search query is empty or again or simply different. The filter deletes all items that do not match from the original list.
#Override
public int getGroupCount() {
return this.list_categories.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return this.list_carriers.get(this.list_categories.get(groupPosition)).size();
}
#Override
public Object getGroup(int groupPosition) {
return this.list_categories.get(groupPosition);
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return this.list_carriers.get(this.list_categories.get(groupPosition)).get(childPosition);
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
Those methods need to be overwritten when you expand the BaseExpandableListAdapter. You can replace all the return null; statements with something similar like this, depending on your data.
#SuppressLint("InflateParams")
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.listview_header_data_layout, null);
}
TextView lblListHeader = (TextView) convertView.findViewById(R.id.fragment_data_list_view_category);
lblListHeader.setText(headerTitle);
ImageView expandIcon = (ImageView) convertView.findViewById(R.id.fragment_data_list_view_category_icon);
if(isExpanded) {
expandIcon.setImageResource(R.drawable.ic_remove_black_24dp);
} else {
expandIcon.setImageResource(R.drawable.ic_add_black_24dp);
}
return convertView;
}
This overriden method simply inflates the layout for each header/group/category item and sets it text and image depending on the state of the group, if it's collapsed or expanded.
#SuppressLint("InflateParams")
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
final String carrierName = ((Carrier)getChild(groupPosition, childPosition)).get_name();
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.listview_item_data_layout, null);
}
TextView txtListChild = (TextView) convertView.findViewById(R.id.fragment_data_list_view_carrier_name);
txtListChild.setText(carrierName);
return convertView;
}
Same thing with the child items.
Now finally to the filtering:
I use this custom method to filter out all items that I need matching the search query. Remember that this method is called each time the text of the EditText changes.
void filterData(String query) {
query = query.toLowerCase();
list_categories = new ArrayList<>();
list_carriers = new HashMap<>();
DatabaseHelper dbHelper = new DatabaseHelper(mContext, null, null, 1);
if(query.trim().isEmpty()) {
list_categories = new ArrayList<>(list_categories_original);
list_carriers = new HashMap<>(list_carriers_original);
notifyDataSetInvalidated();
}
else {
//Filter all data with the given search query. Yes, it's complicated
List<String> new_categories_list = new ArrayList<>();
HashMap<String, List<Carrier>> new_carriers_list = new HashMap<>();
List<String> all_categories_list = dbHelper.getCategoryList();
for(int i = 0; i < all_categories_list.size(); i++) {
List<Carrier> carriersWithCategoryList = dbHelper.getCarriersWithCategory(all_categories_list.get(i));
List<Carrier> matchingCarriersInCategory = new ArrayList<>();
for(Carrier carrierInCategory : carriersWithCategoryList) {
if(carrierInCategory.get_name().toLowerCase().contains(query)) {
matchingCarriersInCategory.add(carrierInCategory);
if(!new_categories_list.contains(all_categories_list.get(i))) {
new_categories_list.add(all_categories_list.get(i));
}
}
}
new_carriers_list.put(all_categories_list.get(i), matchingCarriersInCategory);
}
if(new_categories_list.size() > 0 && new_carriers_list.size() > 0) {
list_categories.clear();
list_categories.addAll(new_categories_list);
list_carriers.clear();
list_carriers.putAll(new_carriers_list);
}
notifyDataSetChanged();
}
}`
This might be very confusing, but it needs to be that complicated in my case because of my data structure. It might be easier in your case.
What this basically does is, that it first checks if the search query is empty. And if it is empty it resets both lists to the "backup" lists which I assigned in the constructor. I then call notifyDataSetInvalidated(); to tell the Adapter that it's content will be refilled. It might work aswell with notifyDataSetChanged();, I didn't test that, but it should since we set the original lists back to their old state.
Now, if the search query is not empty I go through every category and see if that specific category has any items that match the search query. If that is the case, that item is added to a new child list and it's category/parent will also be added to a new parent list, if it's not already in there.
And last but not least, the method checks if both lists are not empty. If they are not empty, the original lists are emptied and the new, filtered data, is put in and the Adapter is notified by calling notifyDataSetChanged();
I hope this will help anyone.
For my Android project, I have a listview which has a checkbox for every item. The data is loaded from an SQLite database by using a CursorAdapter class. However, whenever I scroll, the checkbox positions will get moved and get carried down to the next part of the listview. How can I fix this problem?
GIF of my CheckBox Problem
Here's my Cursor Adapter Class:
public class VocabCursorAdapter extends CursorAdapter {
private static final int DIFFICULT = 0;
private static final int FAMILIAR = 1;
private static final int EASY = 2;
private static final int PERFECT = 3;
public VocabCursorAdapter(Context context, Cursor c, int flags) {
super(context, c, 0);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.item_vocab, parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// Find fields to populate in inflated template
TextView tvVocabName = (TextView) view.findViewById(R.id.vocabName);
TextView tvVocabDefinition = (TextView) view.findViewById(R.id.vocabDefinition);
ImageView tvVocabLevel = (ImageView) view.findViewById(R.id.vocabLevel);
// Extract properties from cursor
String vocab = cursor.getString(cursor.getColumnIndexOrThrow(VocabDbContract.COLUMN_NAME_VOCAB));
String definition = cursor.getString(cursor.getColumnIndexOrThrow(VocabDbContract.COLUMN_NAME_DEFINITION));
int level = cursor.getInt(cursor.getColumnIndexOrThrow(VocabDbContract.COLUMN_NAME_LEVEL));
// Populate fields with extracted properties
tvVocabName.setText(vocab);
tvVocabDefinition.setText(definition);
if (level == DIFFICULT) {
tvVocabLevel.setImageResource(R.drawable.level_bars_difficult);
tvVocabLevel.setTag(DIFFICULT);
}
else if (level == FAMILIAR) {
tvVocabLevel.setImageResource(R.drawable.level_bars_familiar);
tvVocabLevel.setTag(FAMILIAR);
}
else if (level == EASY) {
tvVocabLevel.setImageResource(R.drawable.level_bars_easy);
tvVocabLevel.setTag(EASY);
}
else if (level == PERFECT) {
tvVocabLevel.setImageResource(R.drawable.level_bars_perfect);
tvVocabLevel.setTag(PERFECT);
}
}
And here's my list item xml, item_vocab.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:longClickable="true">
<ImageView
android:layout_width="36sp"
android:layout_height="36sp"
android:id="#+id/vocabLevel"
android:layout_gravity="right"
android:src="#drawable/level_bars"
android:scaleType="fitXY"
android:contentDescription="#string/vocab_level"
android:layout_centerVertical="true"
android:layout_toLeftOf="#+id/editCheckbox"
android:layout_toStartOf="#+id/editCheckbox"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/vocabName"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="#+id/vocabLevel"
android:layout_toStartOf="#+id/vocabLevel"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/vocabDefinition"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="#+id/vocabLevel"
android:layout_toStartOf="#+id/vocabLevel"
android:layout_below="#id/vocabName"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/editCheckbox"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
</RelativeLayout>
And here's my xml which contains a listview
<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=".controller.MyVocab"
android:paddingLeft="5dp">
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/mVocabList"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/empty_text_view"
android:id="#android:id/empty"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
</RelativeLayout>
I have looked at a lot of different solutions on StackOverflow, but I wasn't able to successfully do it in my own app. For an example, this post has a similar problem, but its solution used getView and I had trouble understanding how to implement it with newView and bindView instead.
And some other solutions might be examples where a cursoradapter is not involved. Any help is much appreciated, thanks a lot!
Edit #1: After incorporating Phan's changes, the checkbox states get resets to false rather than keeping its states when I scroll the listview (See ).
Reason : ListView re-uses the views.
Solution :
class VocabCursorAdapter extends CursorAdapter {
List<Integer> selectedItemsPositions;//to store all selected items position
public VocabCursorAdapter(Context context, Cursor c,int flags) {
super(context, c,0);
selectedItemsPositions = new ArrayList<>();
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
View view = LayoutInflater.from(context).inflate(R.layout.item_vocab, viewGroup, false);
CheckBox box = (CheckBox) view.findViewById(R.id.editCheckbox);
box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
int position = (int) compoundButton.getTag();
if (b) {
//check whether its already selected or not
if (!selectedItemsPositions.contains(position))
selectedItemsPositions.add(position);
} else {
//remove position if unchecked checked item
selectedItemsPositions.remove((Object) position);
}
}
});
return view;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
//your other stuff
CheckBox box = (CheckBox) view.findViewById(R.id.editCheckbox);
box.setTag(cursor.getPosition());
if (selectedItemsPositions.contains(cursor.getPosition()))
box.setChecked(true);
else
box.setChecked(false);
}
}
Try this
public class VocabCursorAdapter extends CursorAdapter {
private ArrayList<Boolean> itemChecked = new ArrayList<Boolean>(); // array list for store state of each checkbox
public VocabCursorAdapter(Context context, Cursor c, int flags) {
for (int i = 0; i < c.getCount(); i++) { // c.getCount() return total number of your Cursor
itemChecked.add(i, false); // initializes all items value with false
}
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
...
final int position = cursor.getPosition(); // get position by cursor
CheckBox checkBox = (CheckBox) view.findViewById(R.id.editCheckbox);
checkBox.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (itemChecked.get(position) == true) { // if current checkbox is checked, when you click -> change it to false
itemChecked.set(position, false);
} else {
itemChecked.set(position, true);
}
}
});
checkBox.setChecked(itemChecked.get(position)); // set the checkbox state base on arraylist object state
Log.i("In VocabCursorAdapter","position: "+position+" - checkbox state: "+itemChecked.get(position));
}
}
public class ObservationselectattributeFragment extends Fragment {
DatabaseHandler mDBHandler;
ListView mListView;
SimpleCursorAdapter mSCA;
Cursor mCsr;
ArrayList<String> attributeItems = new ArrayList<>();
public ObservationselectattributeFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate the layout for this fragment
View view1=inflater.inflate(R.layout.fragment_observationselectattribute, container, false);
//Bundle bundle2 = getArguments();
Bundle bundle1 = getArguments();
final int firsttext= bundle1.getInt("TotalCount");
final String selectedtreatment= bundle1.getString("SelectedTreatment");
Toast.makeText(getActivity(),"value \n"+firsttext+"\n"+"treatment \n"+selectedtreatment, Toast.LENGTH_SHORT).show();
// Toast.makeText(getActivity(),"SelectedTreatment \n"+selectedtreatment, Toast.LENGTH_SHORT).show();
mListView = (ListView)view1.findViewById(R.id.lv001);
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
Button addattribute = (Button)view1.findViewById(R.id.addattribute);
addattribute.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String items1="";
Integer tcount1=0;
for(String item1:attributeItems){
items1+="-"+item1+"\n";
tcount1++;
}
Toast.makeText(getActivity(),"you have selected \n"+items1,Toast.LENGTH_LONG).show();
Toast.makeText(getActivity(),"you have selected \n"+tcount1,Toast.LENGTH_LONG).show();
/*FragmentTransaction fr= getFragmentManager().beginTransaction();
fr.replace(R.id.main_container, new ShowObservationDataRecordingFragment()).addToBackStack("ObservationselectattributeFragment");
fr.commit();*/
Bundle bundle = new Bundle();
bundle.putInt("TotalCount2",firsttext);
bundle.putInt("TotalCount1", tcount1);
bundle.putString("SelectedTreatment", selectedtreatment);
Fragment showobservationdatarecordingfragment = new ShowObservationDataRecordingFragment();
showobservationdatarecordingfragment.setArguments(bundle);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.main_container, showobservationdatarecordingfragment).addToBackStack("ObservationselectattributeFragment").commit();
}
});
mDBHandler = new DatabaseHandler(this.getActivity());
mCsr = mDBHandler.getAllRecords();
// Prepare a list of the columns to get the data from, for the ListViewt
String[] columns_to_get_data_from = new String[]{
DatabaseHandler.KEY_IDS,
DatabaseHandler.KEY_NAMES,
DatabaseHandler.KEY_FNAME,
DatabaseHandler.KEY_MONAME,
DatabaseHandler.KEY_SNAME
};
// Prepare a list of the Views into which to place the data
int[] itemviews_to_place_data_in = new int[]{
R.id.euserid,
R.id.eusername,
R.id.efname,
R.id.emoname,
R.id.esname
};
// get and instance of SimpleCursorAdapter
mSCA = new SimpleCursorAdapter(getActivity(),
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
0);
// Save the ListView state (= includes scroll position) as a Parceble
Parcelable state = mListView.onSaveInstanceState();
// get and instance of SimpleCursorAdapter the listviewitem_record layout
mListView.setAdapter(mSCA);
// Restore previous state (including selected item index and scroll position)
mListView.onRestoreInstanceState(state);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String attributeItem1 = ((TextView)view.findViewById(R.id.euserid)).getText().toString();
String attributeItem2 = ((TextView)view.findViewById(R.id.eusername)).getText().toString();
String attributeItem3 = ((TextView)view.findViewById(R.id.efname)).getText().toString();
String attributeItem4 = ((TextView)view.findViewById(R.id.emoname)).getText().toString();
String attributeItem5 = ((TextView)view.findViewById(R.id.esname)).getText().toString();
String attributeItem = attributeItem1 + attributeItem2 + attributeItem3 + attributeItem4 + attributeItem5;
// CheckedTextView box = (CheckedTextView) view.findViewById(R.id.record_checkbox);
// box.setChecked(true);
CheckedTextView checkedTextView = (CheckedTextView) view.findViewById(R.id.record_checkbox);
if(checkedTextView.isChecked()) {
checkedTextView.setChecked(false);
} else {
checkedTextView.setChecked(true);
}
if(attributeItems.contains(attributeItem)){
attributeItems.remove(attributeItem);//uncheck item
}
else
{
attributeItems.add(attributeItem);
}
Toast.makeText(getActivity(), "Item1 = " + attributeItem1 +"\n"+ "Item2 ="+attributeItem2 +"\n"+"Item3 ="+attributeItem3+"\n"+"Item4 ="+attributeItem4+"\n"+"Item5 ="+attributeItem5, Toast.LENGTH_SHORT).show();
}
});
((HomeActivity) getActivity())
.setActionBarTitle("Select Attribute");
return view1;
}
}
Using a custom ListPreference, I'm trying to ask the user to choose between 2 pre-defined values, and a custom value he can set using an edittext.
Everything seems to work, except that the keyboard doesn't show up when I click on the EditText.
However, the EditText seems to gain focus, as it would normally.
Here is the image of what I'm obtaining (see the focus seems to be alright)
https://www.dropbox.com/s/isejjkveonwnb3f/Screenshot_2013-05-30-21-43-41.png
Here is the layout of the custom list preference row:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingBottom="8dip"
android:paddingTop="8dip"
android:paddingLeft="10dip"
android:paddingRight="10dip">
<EditText
android:id="#+id/ET_prefs_customText"
android:layout_width="0dip"
android:layout_weight="1"
android:hint="#string/SP_address_hint"
android:layout_height="wrap_content"
/>
<RadioButton
android:id="#+id/custom_list_view_row_radio_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false" />
</LinearLayout>
And here is my CustomListPreference code:
public class CustomListPreference extends ListPreference
{
/*
* removed useless stuff
*/
#Override
protected void onPrepareDialogBuilder(Builder builder)
{
entries = getEntries();
entryValues = getEntryValues();
if (entries == null || entryValues == null || entries.length != entryValues.length )
{
throw new IllegalStateException(
"ListPreference requires an entries array and an entryValues array which are both the same length");
}
customListPreferenceAdapter = new CustomListPreferenceAdapter(mContext);
builder.setAdapter(customListPreferenceAdapter, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
}
});
}
private class CustomListPreferenceAdapter extends BaseAdapter
{
private SharedPreferences prefs;
public CustomListPreferenceAdapter(Context context)
{
this.prefs = PreferenceManager.getDefaultSharedPreferences(context);
}
/*
* removed usual adapter stuff (getCount, getItem...)
*/
public View getView(final int position, View convertView, ViewGroup parent)
{
View row = convertView;
if(row == null)
{
//If it's not the last one: use a normal holder...
if(position < 2)
{
NormalHolder holder = null;
row = mInflater.inflate(R.layout.normal_list_preference_row, parent, false);
if(prefs.getString(mContext.getString(R.string.SP_address), "0").equals(entryValues[position])) {
holder = new NormalHolder(row, position,true);
} else {
holder = new NormalHolder(row, position,false);
}
row.setTag(holder);
row.setClickable(true);
row.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
for(RadioButton rb : rButtonList)
{
if(rb.getId() != position)
rb.setChecked(false);
}
int index = position;
String value = entryValues[index].toString();
Log.v("Editor", "putting string" + value);
editor.putString(mContext.getString(R.string.SP_address), value);
editor.commit();
Dialog mDialog = getDialog();
mDialog.dismiss();
}
});
//Otherwise, if it is the last one...
} else {
//Use the custom row
row = mInflater.inflate(R.layout.custom_list_preference_row, parent, false);
String fromPref = prefs.getString(mContext.getString(R.string.SP_address), "0");
boolean flag=false;
for(CharSequence entry : entryValues) {
if(entry.toString().equals(fromPref)) {
flag=true;
}
}
//And use a "custom holder"
CustomHolder holder;
if(!flag) {
holder = new CustomHolder(row, position, fromPref, true);
} else {
holder = new CustomHolder(row, position, "", false);
}
row.setTag(holder);
}
}
return row;
}
/*
* This class just shows the information in row from the position and the PreferenceList entries
*/
class NormalHolder
{
private TextView text = null;
private RadioButton rButton = null;
NormalHolder(View row, int position, boolean isCheked)
{
text = (TextView)row.findViewById(R.id.custom_list_view_row_text_view);
text.setText(entries[position]);
rButton = (RadioButton)row.findViewById(R.id.custom_list_view_row_radio_button);
rButton.setId(position);
rButton.setChecked(isCheked);
// also need to do something to check your preference and set the right button as checked
rButtonList.add(rButton);
rButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if(isChecked)
{
/*
* Put stuff into SharedPreference
*/
}
}
});
}
}
/*
* This class display the text within the EditText
*/
class CustomHolder
{
private EditText text = null;
private RadioButton rButton = null;
CustomHolder(View row, int position, String pref, boolean checked)
{
text = (EditText)row.findViewById(R.id.ET_prefs_customText);
text.setText(pref);
rButton = (RadioButton)row.findViewById(R.id.custom_list_view_row_radio_button);
rButton.setId(position);
rButton.setChecked(checked);
rButtonList.add(rButton);
rButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if(isChecked)
{
/*
* Put stuff into SharedPreference
*/
}
}
});
}
}
}
}
Note that this was based on another answered found here: custom row in a listPreference?
Edit: I've added a few code above (see onPrepareDialogBuilder), because it might come from the Dialog built.
Ok, I managed to solve this out.
As said here: https://stackoverflow.com/a/9118027/1376834
The problem seems to be (at least in my case), that since the place where you enter text is hidden initially (or nested or something), AlertDialog is automatically setting the flag WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM (or some combination of that and WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) so that things don't trigger a soft input to show up.
So I just added
getDialog().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
in my CustomHolder constructor, so that the Dialog is already built when I do so.
I’m trying to make a ListView show multiple highlights after each item is selected, but I get strange behavior from the View. If you click on the first item, it is highlighted (after clicking the OK button on the popup window). If you click on the second item however, the last item is also highlighted. Here is the log showing that the renderer.setBackgroundResource is only called the appropriate number of times.
01-30 00:54:07.957: I/HighlightActivity(343): ListView.onItemClick: selected = 0
01-30 00:54:09.757: I/HighlightActivity(343): FINISHED_WORDS[0].equals(set)
01-30 00:54:11.387: I/HighlightActivity(343): ListView.onItemClick: selected = 1
01-30 00:54:12.757: I/HighlightActivity(343): FINISHED_WORDS[0].equals(set)
01-30 00:54:12.776: I/HighlightActivity(343): FINISHED_WORDS[1].equals(set)
If you try different selection orders, all kinds of weird behavior happens. I’m not sure if this is the best way to do this, or what the problem is. (Using Android 2.3.3 API 10)
Thanks for your help,
Curchod.
Here is the Activity:
public class HighlightActivity extends ListActivity
{
private static final String DEBUG_TAG = "HighlightActivity";
final Context context = this;
private String[] FINISHED_WORDS = {"","","","","",""};
private String[] WORDS = {"one","two","three","four","five","six"};
int selected;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.setListAdapter(new ArrayAdapter<String>(this, R.layout.activity_highlight,
R.id.highlight_layout, WORDS)
{
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
final View renderer = super.getView(position, convertView, parent);
if (FINISHED_WORDS[position].equals("set"))
{
renderer.setBackgroundResource(android.R.color.darker_gray);
Log.i(DEBUG_TAG, "FINISHED_WORDS["+position+"].equals(set)");
}
return renderer;
}
});
ListView list_view = getListView();
list_view.setTextFilterEnabled(true);
list_view.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
selected = position;
Log.i(DEBUG_TAG, "ListView.onItemClick: selected = "+selected);
final String selected_word = WORDS[position];
LayoutInflater layout_inflater = LayoutInflater.from(context);
View popup_view = layout_inflater.inflate(R.layout.highlight_popup, null);
final AlertDialog.Builder alert_dialog_builder = new AlertDialog.Builder(context);
alert_dialog_builder.setView(popup_view);
final TextView ard_player_words_popup_text = (TextView) popup_view.findViewById(R.id.highlight_popup_text);
ard_player_words_popup_text.setText(selected_word+" selected");
alert_dialog_builder.setCancelable(false).setPositiveButton("OK",
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog,int id)
{
FINISHED_WORDS[selected] = "set";
dialog.cancel();
ListView list_view = getListView();
ArrayAdapter<?> adapter = (ArrayAdapter<?>) list_view.getAdapter();
adapter.notifyDataSetChanged();
}
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog,int id)
{
dialog.cancel();
}
});
AlertDialog alert_dialog = alert_dialog_builder.create();
alert_dialog.show();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.activity_highlight, menu);
return true;
}
}
Here is the actrivity_highlight.xml layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/highlight_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp"
android:textSize="20sp" >
</TextView>
</RelativeLayout>
And here is the highlight_popup.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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/highlight_popup_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
It's possible your getView method is getting a recycled convertView, with a background already set.
Try this:
if (FINISHED_WORDS[position].equals("set"))
{
renderer.setBackgroundResource(android.R.color.darker_gray);
Log.i(DEBUG_TAG, "FINISHED_WORDS["+position+"].equals(set)");
}
else
{
renderer.setBackgroundResource(R.color.normal_background);
}
I'm new to programming and having problem with using getCheckedItemPositions() for check boxes and getting edit values from edit text in custom list view. Can anyone help me with an example to create custom list view which has above functionality. Thanks.
*this is custom listview xml code
<CheckBox android:id="#+id/checkBox" android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_alignParentRight="true"
android:text="CheckBox"
android:onClick="clickHandler"
></CheckBox>
<TextView android:layout_height="wrap_content"
android:layout_width="fill_parent" android:text="TextView"
android:id="#+id/textView1"
android:layout_alignParentLeft="true"
android:layout_centerHorizontal="true" android:layout_marginBottom="14dp"
android:layout_toLeftOf="#+id/checkBox">
*This is code for set up listview
lv1 = (ListView)dialog.findViewById(R.id.l1);
adapter2 = new SimpleCursorAdapter(
this,
R.layout.custom,
cursor2,
new String[] {"ItemName"},
new int[] {R.id.textView1});
lv1.setItemsCanFocus(false);
lv1.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
lv1.setAdapter(adapter2);
*this what I tried to do when checked
public void onClick(View v) {
int len = lv1.getCount();
SparseBooleanArray checked = lv1.getCheckedItemPositions();
for (int i = 0 ; i < len; i++)
if (checked.get(i)) {
String item = mArrayList.get(i);
mItems.add(mArrayList.get(i));
System.out.println(item);
/* do whatever you want with the checked item */
}
But this is not working. And also I want to use edit text in this manner for getting values.when I checked and click the button app terminate.
The following code will solve your problem.
public class SimpleCursorAdapter extends ArrayAdapter {
private Context mcontext;
private View rowview;
LayoutInflater inflater;
public static ArrayList<Boolean > itemchecked=new ArrayList<Boolean>();
public SimpleCursorAdapter(Context context,ArrayList<String> mylist)
{
super(context,your layout id);
mcontext=context;
//this is the important step
for (int i = 0; i < this.getCount(); i++)
{
itemchecked.add(i,false); // initializes all items value with false
}
}
public View getView(final int position, View convertView, ViewGroup parent) {
rowview=convertView;
if(convertView==null)
{
rowview = inflater.inflate(R.yourlayout, parent, false);
}
TextView textView_heading = (TextView) rowview.findViewById(R.id.textView1);
CheckBox checkbox_detail=(CheckBox) rowview.findViewById(R.id.checkBox1);
checkbox_detail.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
CheckBox cb = (CheckBox) v.findViewById(R.id.checkBox1);
if (cb.isChecked()) {
itemchecked.set(position, true);
// do some operations here
} else if (!cb.isChecked()) {
itemchecked.set(position, false);
// do some operations here
}
}
});
checkbox_detail.setChecked(itemchecked.get(position));
textView_heading.setText(userheading_list.get(position));
return rowview;
}
}
//now the custom list part finish
Now, to get all the information from list and also watch which checkbox is checked:
for(int i=0;i<yourlistadapterobject.getCount();i++)
{
View content_view=msg_adapter.getView(i,null , user_detail_list);
System.out.println("the list count"+user_detail_list.getCount());
if(MyContactAdapter.itemchecked.get(i))
{
System.out.println("is checked true");
TextView tv_heading= (TextView) content_view.findViewById(R.id.textView1);
String text=tv_heading.getText();
}
}
By doing this, you can get all the information against checkbox which is checked.