im using gridview CHOICE_MODE_MULTIPLE_MODAL to select multiple items(images) in my gridview .
I used MultiChoiceModeListener to achieve this, the problem is selected items are not get highlighted
Selector xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_selected="true" android:drawable="#color/green"/>
<item android:state_pressed="true"
android:drawable="#color/blue"/> <!-- pressed state -->
<item android:state_focused="true"
android:drawable="#color/blue"/> <!-- focused state -->
<item android:drawable="#android:color/transparent"/> <!-- default state -->
</selector>
When I touch an item it get covered with blue (i think this happens bcoz i used gridView.setDrawSelectorOnTop(true); )...as soon as i lift my finger blue color get removed.
I want the selected items to get highlighted with semi transparent blue color and it should stay highlighted until I deselect the item.
Java Code:
public class HappyFragment extends ParentFragment {
public HappyImageAdapter imageAdapter;
private List<ResolveInfo> mApps;
GridView gridView;
public static HappyFragment newInstance() {
HappyFragment fragment = new HappyFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// if ((savedInstanceState != null) && savedInstanceState.containsKey(KEY_CONTENT)) {
// // mContent = savedInstanceState.getString(KEY_CONTENT);
// }
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.happy_fragment_layout, container, false);
// ImageView iv= (ImageView) view.findViewById(R.id.imageView1);
gridView = (GridView)view.findViewById(R.id.gvHappy);
// Instance of ImageAdapter Class
imageAdapter = new HappyImageAdapter(getActivity());
gridView.setAdapter(imageAdapter);
gridView.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE_MODAL);
gridView.setMultiChoiceModeListener(new MultiChoiceModeListener());
gridView.setDrawSelectorOnTop(true);
gridView.setSelector(getResources().getDrawable(R.drawable.gridview_selector));
gridView.setOnItemLongClickListener(new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
Toast.makeText(getActivity(), String.valueOf(imageAdapter.mThumbIds[position]), Toast.LENGTH_SHORT).show();
return true;
}
});
gridView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View v,int position, long id) {
if(BaseActivity.isinint) { // check if any app cares for the result
int ImageResourse=imageAdapter.mThumbIds[position];
Uri path = Uri.parse("android.resource://dragonflymobile.stickers.lifestickers/" + ImageResourse);
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND, path); //Create a new intent. First parameter means that you want to send the file. The second parameter is the URI pointing to a file on the sd card. (openprev has the datatype File)
((Activity)getActivity()).setResult(Activity.RESULT_OK, shareIntent); //set the file/intent as result
((Activity)getActivity()).finish(); //close your application and get back to the requesting application like GMail and WhatsApp
return; //do not execute code below, not important
} else {
Intent intent = new Intent(getActivity(), PreviewActivity.class);
intent.putExtra("Image Int", imageAdapter.mThumbIds[position]);
startActivity(intent);
}
}
});
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// outState.putString(KEY_CONTENT, mContent);
}
//multi select mode codes
public class MultiChoiceModeListener implements GridView.MultiChoiceModeListener {
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.setTitle("Select Items");
mode.setSubtitle("One item selected");
return true;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return true;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return true;
}
public void onDestroyActionMode(ActionMode mode) {
}
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
int selectCount = gridView.getCheckedItemCount();
switch (selectCount) {
case 1:
mode.setSubtitle("One item selected");
break;
default:
mode.setSubtitle("" + selectCount + " items selected");
break;
}
}
}
}
just follow this,
1.put your grid view child item in FrameLayout
2.give FrameLayout property android:foreground="?android:attr/activatedBackgroundIndicator"
that's it... no need to use extra library
okay i found this 3rd party library which do exactly this with less code
here is the github link
and here is a gridview with images tutorial link
In case that anyone wants a solution without thrid library just put this code inside
onItemCheckedStateChanged (here gv is your gridView name)
if(checked){
View tv = (View) gv.getChildAt(position);
tv.setBackgroundColor(Color.RED);
}else{
View tv = (View) gv.getChildAt(position);
tv.setBackgroundColor(Color.TRANSPARENT);
}
gridView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(android.view.ActionMode actionMode, int i, long l, boolean b) {
// Capture total checked items
final int checkedCount = gridView.getCheckedItemCount();
// Set the CAB title according to total checked items
actionMode.setTitle(checkedCount + " Selected");
if(gridView.getChildAt(i).isSelected()) {
gridView.getChildAt(i).setBackgroundColor(Color.parseColor("#FF4081"));
}else{
gridView.getChildAt(i).setBackgroundColor(Color.parseColor("#b1e76905"));
}
// Calls toggleSelection method from ListViewAdapter Class
adapter.toggleSelection(i);
}
Related
I have a list view and I edit its items via contextual menu, I need to get the row id of an item then pass it to another activity via bundle then in second activity the data will be shown from database and from there they can be edited.
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
data_ID = adapterView.getItemIdAtPosition(i);
actionMode = Block_A_Info.this.startActionMode(new android.view.ActionMode.Callback() {
#Override
public boolean onCreateActionMode(android.view.ActionMode actionMode, Menu menu) {
actionMode.getMenuInflater().inflate(R.menu.contextual_menu,menu);
return true;
}
#Override
public boolean onPrepareActionMode(android.view.ActionMode actionMode, Menu menu) {
actionMode.setTitle("Edit");
return false;
}
#Override
public boolean onActionItemClicked(android.view.ActionMode actionMode, MenuItem menuItem) {
Intent open = new Intent(Block_A_Info.this,Edit_A_Info.class);
Bundle bundle = new Bundle();
bundle.putLong("ID_INFO",data_ID);
open.putExtras(bundle);
startActivity(open);
return false;
}
but in that case there is an id positioned 0!! and another problem will arise when i delete one row then it will select wrong position for an item.
here is the code written in another activity to set the data in textvies:
Bundle int_id = getIntent().getExtras();
set_id = int_id.getLong("ID_INFO");
Cursor info_rec = myDb.RecoveryInfo(set_id.toString());
if(info_rec.getCount() == 0){
Toast.makeText(Edit_A_Info.this,"Error!",Toast.LENGTH_LONG).show();
return;
}
while (info_rec.moveToNext()) {
et_num.setText(info_rec.getString(1));
et_name.setText(info_rec.getString(2));
et_person.setText(info_rec.getString(3));
et_phone.setText(info_rec.getString(4));
et_data.setText(info_rec.getString(5));
}
how can I select the desire item in a list-view?
Thanks in advance
The code populates the listview with items using baseadapter. On clicking on the item it changes background color and goes to the next activity. Now i want to change the back ground color on first click and it should stay selected. Then on next click it should go to the next activity. Is it possible to do so.
Activity
nameList = (ListView) findViewById(R.id.list_names);
nameList.setAdapter(listAdapter);
listAdapter.notifyDataSetChanged();
nameList.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long viewId)
{
TextView PCNtv = (TextView) view.findViewById(R.id.value_Name);
String P_Name = PCNtv.getText().toString();
Intent intents = new Intent(getApplicationContext(), Activity2.class);
intents.putExtra("P_Name", P_Name);
view.setSelected(true);
startActivity(intents);
}
});
In drawable
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="#drawable/blue_color"/>
<item android:state_pressed="true" android:drawable="#drawable/white_color"/>
<item android:state_focused="true" android:drawable="#drawable/red_color"/>
</selector>
Use the views selected property to detect the second click. First click will select the view, the second will open the activity.
nameList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long viewId)
{
TextView PCNtv = (TextView) view.findViewById(R.id.value_Name);
String P_Name = PCNtv.getText().toString();
if ( view.isSelected() ) {
Intent intents = new Intent(getApplicationContext(), Activity2.class);
intents.putExtra("P_Name", P_Name);
startActivity(intents);
}
view.setSelected(true);
});
}
Update
The selection is lost when the users presses the view again, so the code above does not work. Here is a solution involving the adapter tracking the currently selected position.
The click event:
nameList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
// Check to see which item in the adapter is already
// selected, if the same has been selected twice, start new activity
if ( i == ((TestAdapter)adapter).getSelectedIndex()) {
// Start your new activity here.
Log.d("TAG", "second push");
}
((TestAdapter)adapter).setSelectedIndex(i);
}
});
You did not show the code for your adapter, so here is a simple one with the selected index added:
public class TestAdapter extends ArrayAdapter<String> {
private final Activity context;
private int mSelection = -1;
public TestAdapter(Activity context, String[] objects) {
super(context, R.layout.text_layout, objects);
this.context = context;
}
// Call this when an item is clicked, this sets the
// internal index for the selected item and notifies the view
// that the data has changes, this will force the view to draw
// allowing it to correctly highlight the selected item
public void setSelectedIndex(int index) {
mSelection = index;
notifyDataSetChanged();
}
// This is needed for the click listener to check to see which
// item is already selected
public int getSelectedIndex() {
return mSelection;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView = inflater.inflate(R.layout.text_layout, null);
TextView tv = (TextView)rowView.findViewById(R.id.text3);
tv.setText(getItem(position));
// Adds or removes the selection on the view so
// it will display as selected
if ( mSelection == position ) {
tv.setSelected(true);
} else {
tv.setSelected(false);
}
return rowView;
}
}
Updated: added inline comments
I know a lot have asked similar questions, but none of their solutions works for me.
I have a master/detail flow with a expandable list as the list. I can click the groups and expand them, but I can't click the children.
I have set them to selectable (at first I thought that was the problem), they do not have any checkboxes or images on them, just plain text. I've even set that text to not be focusable (as focusable elements seemed to be the problem for others).
This is what I have:
A custom BaseExpandableAdapter:
public class CabinetAndRacksExpandAdapter extends BaseExpandableListAdapter {
//(some fields that probably aren't relevant)
#Override
public int getGroupCount() {
return cabinets.size();
}
(more override methods here, probably not relevant)
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.listrow_cabinet, null);
}
Cabinet cabinet = (Cabinet) getGroup(groupPosition);
((CheckedTextView) convertView).setText(cabinet.toString());
((CheckedTextView) convertView).setChecked(isExpanded);
return convertView;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
final Rack rack = (Rack) getChild(groupPosition, childPosition);
TextView text = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.listrow_rack, null);
}
final View view = convertView;
text = (TextView) convertView.findViewById(R.id.textView1);
text.setText(rack.toString());
return convertView;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
I also have a fragment (the list fragment in the master/detail flow). It should listen to the clicks, both child and group, so it implements those listeners:
public class CabinetListFragment extends Fragment implements ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupClickListener{
//(some stuff that's probably not relevant)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_cabinet_list, container, false);
listView = (ExpandableListView) rootView;
listView.setOnChildClickListener(this);
listView.setOnGroupClickListener(this);
Bundle extras = getActivity().getIntent().getExtras();
if(extras != null)
{
String orderId = extras.getString(CabinetListActivity.ARG_ORDER_ID);
order = service.getOrderFromId(service.intFromString(orderId));
}
CabinetAndRacksExpandAdapter adapter = new CabinetAndRacksExpandAdapter(getActivity(), service.getCabinetsForOrder(order));
listView.setAdapter(adapter);
return rootView;
}
#Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
Log.d("CabinetListFragment", "onChildClick");
mCallbacks.onChildSelected(groupPosition, childPosition);
return true;
}
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id)
{
Log.d("CabinetListFragment", "onGroupClick");
mCallbacks.onGroupSelected(groupPosition);
return false;
}
/**
* A callback interface that all activities containing this fragment must
* implement. This mechanism allows activities to be notified of item
* selections.
*/
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
public void onChildSelected(int groupPosition, int childPosition);
public void onGroupSelected(int groupPosition);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Activities containing this fragment must implement its callbacks.
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException("Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks) activity;
}
}
This fragment belongs to an Activity that implements the Callback as it should:
public class CabinetListActivity extends FragmentActivity
implements CabinetListFragment.Callbacks{
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
public static final String ARG_ORDER_ID = "order_id";
private Service service;
private Order order;
private String orderId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cabinet_list);
service = Service.getInstance();
if (findViewById(R.id.cabinet_detail_container) != null) {
mTwoPane = true;
}
Bundle extras = getIntent().getExtras();
if(extras != null)
{
String orderId = extras.getString(ARG_ORDER_ID);
order = service.getOrderFromId(service.intFromString(orderId));
this.orderId = orderId;
}
}
/**
* Callback method from {#link CabinetListFragment.Callbacks}
* indicating which item was selected.
*/
#Override
public void onChildSelected(int groupPosition, int childPosition) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
Bundle arguments = new Bundle();
arguments.putString(CabinetDetailFragment.ARG_CHILD_ID, childPosition+"");
arguments.putString(CabinetDetailFragment.ARG_GROUP_ID, groupPosition+"");
arguments.putBoolean(CabinetDetailFragment.ARG_RACKMODE, true);
CabinetDetailFragment fragment = new CabinetDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.cabinet_detail_container, fragment)
.commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Log.d("CabinetListActivity", "show rack");
Intent detailIntent = new Intent(this, CabinetDetailActivity.class);
detailIntent.putExtra(CabinetDetailFragment.ARG_CHILD_ID, childPosition + "");
detailIntent.putExtra(CabinetDetailFragment.ARG_GROUP_ID, groupPosition+"");
detailIntent.putExtra(CabinetDetailFragment.ARG_RACKMODE, true);
startActivity(detailIntent);
}
}
#Override
public void onGroupSelected(int groupPosition) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
Bundle arguments = new Bundle();
arguments.putString(CabinetDetailFragment.ARG_GROUP_ID, groupPosition+"");
arguments.putString(CabinetDetailFragment.ARG_ORDER_ID, orderId);
arguments.putBoolean(CabinetDetailFragment.ARG_RACKMODE, false);
CabinetDetailFragment fragment = new CabinetDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.cabinet_detail_container, fragment)
.commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, CabinetDetailActivity.class);
detailIntent.putExtra(CabinetDetailFragment.ARG_GROUP_ID, groupPosition+"");
detailIntent.putExtra(CabinetDetailFragment.ARG_ORDER_ID, orderId);
detailIntent.putExtra(CabinetDetailFragment.ARG_RACKMODE, false);
startActivity(detailIntent);
}
}
//(more stuff that's probably not relevant)
}
I cannot see where my childClick event is different from the GroupClick event.
As stated, the GroupClick fires and is handled as intended, but the childClick is not even fired (I have tried logging from the onChildClick in the Fragment).
BTW, it does not seem to make any difference whether that method return true or false (naturally, since it is never called).
I have tried creating a listener directly on the childView, and that works. But I need to do stuff from within either the fragment or activity (preferably the activity, but it ought to be the fragment that listens for the event) upon click, so that won't do.
Why is my fragment not notified of the onChildClick event when it is registered as a listener? Is the event never fired for some reason? Or is it handled elsewhere?
Just a shot in the dark, but did you implement among those not relevant methods
int getChildrenCount(int groupPosition) {
// Return whatever the children's count is
}
and
public boolean areAllItemsEnabled() {
return true;
}
In the Layout XML R.layout.listrow_rack, have you by any chence disabled the item, or associated a click listener to it that fires silently?
Maybe, what your are trying to do is something similar to this:
public class FaltasFragmentActivity extends Activity {
//Lista de faltas
private ExpandableListView mExpandalbeView;
private ExpandableListAdapter listAdapter;
private int posicion;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.conduccion_faltas);
mExpandalbeView = (ExpandableListView) findViewById(R.id.expandable_faltas);
mExpandalbeView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
// Codigo para cerra el ultiom grupo abierto antes de abrir el nuevo
Toast.makeText(FaltasFragmentActivity.this, "pulsado group: " + groupPosition, Toast.LENGTH_SHORT).show();
return false;
}
});
// Listview on child click listener
mExpandalbeView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
Toast.makeText(FaltasFragmentActivity.this, "pulsado child: (" + groupPosition + ", " + childPosition + ")", Toast.LENGTH_SHORT).show();
return false;
}
});
// Listview Group expanded listener
mExpandalbeView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
#Override
public void onGroupExpand(int groupPosition) {
Toast.makeText(FaltasFragmentActivity.this, "pulsado expand", Toast.LENGTH_SHORT).show();
}
});
// Listview Group collasped listener
mExpandalbeView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
#Override
public void onGroupCollapse(int groupPosition) {
Toast.makeText(FaltasFragmentActivity.this, "pulsado collapse", Toast.LENGTH_SHORT).show();
}
});
listAdapter = new ExpandableListAdapter(FaltasFragmentActivity.this, root, posicion, filtroBusqueda);
mExpandalbeView.setAdapter(listAdapter);
}
}
Where ExpandableListAdapter(...) is:
public class ExpandableListAdapter extends BaseExpandableListAdapter{...}
This worked for me!
Hope this helps!
Ok, so here is what was the problem:
This was my listrow_rack:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="40dp"
android:clickable="true"
android:orientation="vertical"
android:paddingLeft="40dp"
tools:context=".OrdreDetailActivity" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="5dp"
android:gravity="center_vertical"
android:text="#string/hello_world"
android:textSize="14sp"
android:textStyle="bold">
</TextView>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#android:color/black" />
The problem was this specific line:
android:clickable="true"
I'm not sure why, but maybe it adds a listener, or maybe for some other reason. But when I removed it, it works.
Props to Andras Baláz Lathja for pointing me in the right direction.
I have implemented CAB and MultiChoiceModeListener on ListView and everything works perfect except changing background color of the list item when selected (multi selection). Here is my code:
listView.xml:
<ListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#ebebeb"
android:dividerHeight="1dip"
android:listSelector="#drawable/list_selector"/>
list_selector:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="#android:color/holo_green_light"/>
<item android:state_pressed="true" android:drawable="#android:color/holo_blue_light"/>
<item android:state_focused="true" android:drawable="#android:color/holo_blue_dark"/>
<item android:drawable="#android:color/white"/>
</selector>
Fragment:
l.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
l.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(android.view.ActionMode mode, int position, long id, boolean checked) {
int checkedCount = l.getCheckedItemCount();
mode.setTitle(checkedCount + " Selected");
}
#Override
public boolean onCreateActionMode(android.view.ActionMode mode, Menu menu) {
return true;
}
#Override
public boolean onPrepareActionMode(android.view.ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) {
}
#Override
public void onDestroyActionMode(android.view.ActionMode mode) {
}
});
What I did was saving the data about the items to see if it was selected and then just calling the adapter's notifyDataSetChanged to create the view again. In my case it was about changing an icon in the item list.
This is the relevant MultiChoiceModeListener part:
mylist.setMultiChoiceModeListener(new MultiChoiceModeListener()
{
private int numberOfSelected = 0;
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked)
{
// Here you can do something when items are
// selected/de-selected,
// such as update the title in the CAB
if (checked)
{
numberOfSelected++;
} else
{
numberOfSelected--;
}
mode.setTitle(numberOfSelected + " items selected");
itemsData.get(position).isChecked = checked; //a collection of data item's status
m_listAdapter.notifyDataSetChanged();
}
...
And this is what I did in the adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View vi = convertView;
if (vi == null)
{
vi = m_inflater.inflate(R.layout.item_view, null);
}
ImageView theIcon = (ImageView) vi.findViewById(R.id.icon);
if (dataItems.get(position).isChecked)
{
theIcon.setImageResource(R.drawable.icon1);
} else
{
contactIcon.setImageResource(R.drawable.icon2);
}
return vi;
}
So i simply build the list items again after selecting an item.
After reading and try'n'error for days, I´m giving up and ask for help.
< edit >
I am using ActionBarSherlock.
< /edit >
What I want to achieve:
A ListView with a custom layout for each row, where the user can select multiple list items.
A selected list item should have a different background color. When there is at least one item selected, a contextual action bar (CAB) should be shown.
It should look more or less like the multiple selection of emails in the GMail app. The only difference is that in the gmail app the selection is done by clicking the checkbox of a row, whereas I don´t want to have a checkbox, but a row should be selected no matter, where the user clicks.
What I tried:
Following this tutorial, using a Checkable row layout with some logic to change the background color when the check state was toggled, I got everything working except that I could not register a click listener like OnItemClickListener on the ListView to show the CAB. Neither providing a click listener for each row View helped because this prevented to change the background color of the selected items.
I also tried adding a MultiChoiceModeListener to the ListView like that
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new MultiChoiceModeListener() { //.. });
With the same result, no background color change.
What I am looking for: A hint or a tutorial or sample code how to do this. If you need some code snippets to help, let me know.
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;
}
}
}
The R.layout.adapters_cabselection_row is a custom layout for the row(a very simple one) with a green background:
<?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:background="#99cc00" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_launcher" />
<TextView
android:id="#+id/the_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textSize="17sp"
android:textStyle="bold" />
</LinearLayout>
R.menu.cabselection_menu is a menu file with 3 options(edit, delete, finish the CAB) which don't do anything except pop a Toast with a message regarding the rows selected:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/edit_entry"
android:icon="#android:drawable/ic_menu_edit"
android:title="Edit!"/>
<item
android:id="#+id/delete_entry"
android:icon="#android:drawable/ic_menu_delete"
android:title="Delete!"/>
<item
android:id="#+id/finish_it"
android:icon="#android:drawable/ic_menu_crop"
android:title="Get me out!"/>
</menu>
I think the easiest way is to apply
android:background="android:attr/activatedBackgroundIndicator"
To which ever layout is the one you will be clicking.
This highlights the layout when selected using
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
worked for me anyway
Using ActionBarSherlock the MultiChoiceModeListener used in Luksprog´s answer is not yet available if you want to support API level < 11.
A workaround is to use the onItemClickListener.
List setup:
listView = (ListView) timeline.findViewById(android.R.id.list);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setItemsCanFocus(false);
listView.setAdapter(new ListAdapter(getActivity(), R.layout.cleaning_list_item, items));
Listener of ListFragment or ListActivity:
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
SparseBooleanArray checked = listView.getCheckedItemPositions();
boolean hasCheckedElement = false;
for (int i = 0; i < checked.size() && !hasCheckedElement; i++) {
hasCheckedElement = checked.valueAt(i);
}
if (hasCheckedElement) {
if (mMode == null) {
mMode = ((SherlockFragmentActivity) getActivity()).startActionMode(new MyActionMode());
mMode.invalidate();
} else {
mMode.invalidate();
}
} else {
if (mMode != null) {
mMode.finish();
}
}
}
Where MyActionMode is an implementation of ActionMode.Callback:
private final class MyActionMode implements ActionMode.Callback { /* ... */ }