I'm trying to identify a view that has been clicked in an expandableListView. When I set an OnItemLongClickListener I get an argument that shows me the position of the clicked view inside the list. However, it also counts child views. I'd like it to count only groups, so when a group was clicked I can determine which one it was. Is there a way to do that?
No, the long parameter is not the packed value, this is the ID generated by your adapter (getCombinedChildId()). Attempting to interpret an ID, even if you generate it in a certain way would be a bad idea. Id is an id.
I believe the right way is to use ExpandableListView.getExpandableListPosition(flatPos) method. Your "pos" argument passed to the listener is, in fact, flat list position. getExpandableListPosition() method returns the packed position which can be then decoded into separate group and child positions using the static methods of ExpandableListView.
I have hit this problem myself today so I am describing the solution I have found working for me.
The long id parameter passed by the onItemLongLongClick method is a packed value.
You can retrieve group position with ExpandableListView.getPackedPositionGroup(id)
Child position is obtained with ExpandableListView.getPackedPositionChild(id).
If Child == -1 then the long click was on the group item.
Below is an example listener class demonstrating unpacking of id.
private class expandableListLongClickListener implements AdapterView.OnItemLongClickListener {
public boolean onItemLongClick (AdapterView<?> p, View v, int pos, long id) {
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setTitle("Long Click Info");
String msg = "pos="+pos+" id="+id;
msg += "\ngroup=" + ExpandableListView.getPackedPositionGroup(id);
msg += "\nchild=" + ExpandableListView.getPackedPositionChild(id);
builder.setMessage(msg);
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) { }
} );
AlertDialog alert = builder.create();
alert.show();
return true;
}
}
Related
I am new to android and currently i'm confronted with a problem i can't solve.
I have an ExpandableListView with a custom adapter which extends the BaseExpandableListAdapter.
Only the group data is loaded when the ExpandableListView is initiated. The corresponding child data is loaded when I click on the group.
The group data holds an object. When I click on a group I get the ID of the groups object. I then pass this ID to a database procedure. The database procedure then returns the corresponding child data for that particular group. I perform this database call inside of an AsyncTask.
For the click I use a ExpandableListView.OnGroupClickListener.
And here is my problem:
When I perform the click, the group expands before the child data is returned by the database procedure. When I collapse the group right after I first expanded it, and then expand it again, the child data is displayed.
So basically what I found is, that there is a timing problem.
The AsyncTask is not finished before the group is expanded.
My preferrable solution:
The group should not be expanded before the child data is returned from the database procedure (So basically the group should not be expanded while the AsyncTask is doint its work).
Or the group should automatically refresh itself after the AsyncTask is finished, without collapsing, and display the child data.
Here is my code:
The onclick event!
lv.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
selected = (DoitService) lv.getExpandableListAdapter().getGroup(groupPosition);
servId = selected.getServiceIdService();
if (!isConnected) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getParentActivity());
// set title
alertDialogBuilder.setTitle("MyApp");
alertDialogBuilder.setMessage("Your Internet Connection is not sufficient to perform this task ")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
} else {
AsyncCallIndividualService asyncCallIndividualService = new AsyncCallIndividualService();
asyncCallIndividualService.execute(servId);
}
return false;
}
});
The onPostExecute code of AsyncCallIndividualService (m1String is the new child data which is returned by the database procedure):
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
List<String> childData = new ArrayList<String>();
childData.add(m1String);
Log.d("m1String on Expand: ", m1String);
// Add children as an array to the HashMap
ExpandableServiceListAdapter. _listDataChild.put(selected, childData);
}
}
PS: I already tried the onGroupExpanded method from the BaseExpandableListAdapter. I had the same problem with it.
I'm really grateful for every help!
Thanks
I have a ListView that contains items with checkboxes that should behave sometimes like a CHOICE_MODE_MULTIPLE and sometimes like a CHOICE_MODE_SINGLE. What I mean is for certain items in the list, when selected certain other items needs to be deselected whilst other can remain selected.
So when item A is checked I can find in my data the item B that needs to be unchecked but how do I get the UI to refresh to show this as I (I believe) cannot find the actual View that represents B but just it's data?
It sounds like you're off to a good start. You're right that you should be manipulating the underlying data source for item B when A is clicked.
Two tips that may help you:
Your getView() method in the Adapter should be looking at your data source and changing convertView based on what it finds. You cannot find the actual View that represents B because in a ListView, the Views are recycled and get reused as different data needs to be displayed. Basically, when an item is scrolled off the list, the View that was used gets passed to the getView() function as convertView, ready to handle the next element's data. For this reason, you should probably never directly change a View in a ListView based on user input, but rather the underlying data.
You can call notifyDataSetChanged() from within your adapter to signal that somewhere the underlying data has been changed and getView() should be called again for the elements currently displayed in your list.
If you're still having trouble, feel free to post some code that illustrates the specific problem that you're having. It's much easier to provide concrete advice when the problem is better defined. Hope this helps!
you can use singleChoice alartDialog, i have used like:
private int i = 0; // this is global
private final CharSequence[] items = {"Breakfast", "Lunch", "Dinner"}; // this is global
Button settings = (Button)view.findViewById(R.id.settings);
settings.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
//Title of Popup
builder.setTitle("Settings");
builder.setSingleChoiceItems(items, i,
new DialogInterface.OnClickListener() {
// When you click the radio button
public void onClick(DialogInterface dialog, int item){
i=item;
}
});
builder.setPositiveButton("Confirm",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
if (i == 0) {
//it means 1st item is checked, so do your code
}
if (i == 1) {
//it means 2nd item is checked, so do your code
} /// for more item do if statement
}
});
//When you click Cancel, Leaves PopUp.
builder.setNegativeButton("Cancel", null);
builder.create().show();
}
});
i have initialized i=0, so that for the very first time when user click on settings button, the first item is selected. and after then when user select other item, i have saved the i value so that next time when user click settings button, i can show user his/her previously selected item is selected.
I come across and solve this question today.
public class ItemChooceActivity extends Activity implements OnItemClickListener {
private int chosenOne = -1;
class Madapter extends BaseAdapter {
.....
.....
#Override
public View getView(final int position, View convertView,
ViewGroup parent) {
// TODO Auto-generated method stub
if (chosenOne != position) {
set the view in A style
} else {
set the view in B style
}
return convertView;
}
}
#Override
public void onItemClick(AdapterView<?> arg0, View view, int position,
long arg3) {
,,,,
chosenOne = position;
adapter.notifyDataSetChanged();
,,,
}
}
UPDATE
The original question i asked was about my long id value but because you guys were right in the way u said i had the correct id i removed my error. Thanks for the help. read my answer for more detail.
1) My app uses the local android SQLiteDatabase and has three tables. I have no problems for two of the tables but turns out my third one is presenting some issues because of my column declarations are public static final string COLUMN_NAME = "name"; ,etc.
My Activities are not extending the ListActivity so that I can have custom lists and listviews for each activity.
I am getting my listview by listview = (ListView) findViewById(R.id.myList); and adding a listener to the listview by listview.setOnItemClickListener(ListListener); Then here is my method for the list listener:
OnItemClickListener ListListener = new OnItemClickListener(){
public void onItemClick(AdapterView<?> arg0, View v, int position,
final long id)
{
AlertDialog.Builder dialog = new AlertDialog.Builder(ExerciseList.this)
.setIcon(R.drawable.edit)
.setTitle("Update Selected Exercise")
.setMessage("Would you like to update the current Exercise? Click continue to proceed.")
.setPositiveButton("Continue", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
final Intent i = new Intent(getBaseContext(), AddExercise.class);
i.putExtra(ExerciseDbAdapter.KEY_ROW_ID, id);
startActivityForResult(i, EDIT_EXERCISE);
}
})
.setNegativeButton("Back", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
dialog.show();
}
};
This above method is just a working on list item click listener!
Intent.putExtra("Key",value) is right way to put the data in intent so
i.putExtra("INSERT THE KEY HERE",ExerciseDbAdapter.KEY_ROW_ID, id);
Okay guys so i found the issue with my application and you were all right. I was getting the correct row id from the application.
I however was passing another data member through my intent causing the setRowIdFromIntent() method to change the id from null to 0. or from not null to 0.
Basically no matter what the value i was passing it was being set to 0 from my setRowIdFromIntent() method because of the data member i passed through. Therefore the above code is almost irrelevant to my problem.
So if you want a working on click list listener the one above will definitely help you pass the correct id to your new activity. Sorry again for this confusion I had on my side. Thanks again for all other postings!
I can use SimpleCursorTreeAdapter to create ExpandableListView with correct groupcursors and childcursors. For my program, each child contains three TextViews. When I expand group and click on child, I use custom dialog to show the three values in EditText view.
The program is ok if I only open "ONE" group at a time. I can get correct child values if clicked. But if I expand several groups at the same time. It only shows the latest children under latest group.
For example: Group A has 3 items, Group B has 5 items, Group C has 2 items. First I clicked on children under Group A, no problem, then children under Group B, no problem, but if I go back to click children under Group A, it still shows child under Group B. I don't know how can show correct children. If I use Toast to display, all children are correct, so strange. What can I do in this methods ?
epView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener()
{
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long row)
{
return false;
}
});
epView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id)
{
int tempid = childcursor.getInt(0);
String temp1 = childcursor.getString(1);
String temp2 = childcursor.getString(2);
String temp3 = childcursor.getString(3);
CustomDialog custom = new CustomDialog(ListCateActivity.this,catecursor,childcursor,temp1,temp2,temp3,tempid);
custom.setTitle("Record Information");
custom.show();
Toast.makeText(ListCateActivity.this, "Group:"+String.valueOf(groupPosition).toString()+" Child: "+String.valueOf(childPosition).toString()+temp1+" "+temp2+" "+temp3, Toast.LENGTH_SHORT).show();
return true;
}
});
thanks !!
Finally I know what happened to my code now, but it is so strange. As I define childcursor in getChildrenCursor method. It should be inherited as I define childcursor as instance variable, so it can be shared among the class. Anyway, Java and Android is interesting. But when you are stuck with unexpected result, you need to debug to find out what the problem is.
I would like to open a custom dialog when someone clicks on a listview entry. That dialog will need to know the text that was clicked on in order to display additional information on that particular entry. Can anyone point me in the right direction on how to accomplish that?
Thanks!
On the ListActivity, override the onListItemClick method. There, you will get the position of the item that was clicked. As you said you want to know the text that is on the item that was clicked, I suppose you have a simple List. In that case, I guess you have, for instance, an array with strings to populate the list.
public void onListItemClick(ListView parent, View v, int position,
long id) {
String itemText = items[position]);
}
So, in this case I'm supposing you have an array of Strings called items. The next step would be to create a Dialog, which can be done this way:
public void onListItemClick(ListView parent, View v, int position,
long id) {
String itemText = items[position]);
new AlertDialog.Builder(this)
.setTitle("Title for " + itemText)
.setMessage("Custom message for "+itemText)
.setNeutralButton("Close", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int sumthin) {
// do whatever you want to do
}
}).show();
}
By the way... if you want to receive nice answers here, make sure you provide nice questions. By "nice question" I mean something with a little bit of your code, so that we can get a better idea of how to help you ;)