I'm setting a Contextual Action Bar for my List in a Fragment.
Using ActionBarSherlock to get CAB with Multiple selection in pre-HONEYCOMB version of android.
I'm flowing this tutorial, but application crashes after performing a long click.
This is my code:
public class CreateFragment extends SherlockFragment {
private ArrayList<Game> myGames;
public ArrayAdapter<String> adapter;
private TipspromenadApplication app;
private ListView listView;
private ActionMode mActionMode;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.fragment_create, container, false);
listView = (ListView) view.findViewById(R.id.createdGames);
View header = getActivity().getLayoutInflater().inflate(R.layout.list_header_create_fragment, null);
listView.addHeaderView(header);
final ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < myGames.size(); i++) {
list.add(myGames.get(i).getLocation() + " " + new SimpleDateFormat("dd/MM/yy", Locale.getDefault()).format(myGames.get(i).getEventDate()));
}
// adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_multiple_choice, list);
// listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
Intent intent= new Intent(getActivity(), CreateTabActivity.class);
intent.putExtra("GameID", position-1);
startActivity(intent);
}
});
listView.setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long id) {
onListItemCheck(position);
return true;
}
});
listView.setAdapter(new SelectableAdapter(this, list));
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = (TipspromenadApplication) getActivity().getApplication();
this.myGames = app.loadGames();
}
//#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
if(mActionMode == null) {
// no items selected, so perform item click actions
} else
// add or remove selection for current list item
onListItemCheck(position);
}
private void onListItemCheck(int position) {
SelectableAdapter adapter = (SelectableAdapter) listView.getAdapter();
adapter.toggleSelection(position);
boolean hasCheckedItems = adapter.getSelectedCount() > 0;
if (hasCheckedItems && mActionMode == null)
// there are some selected items, start the actionMode
mActionMode = getSherlockActivity().startActionMode(new ActionModeCallback());
else if (!hasCheckedItems && mActionMode != null)
// there no selected items, finish the actionMode
mActionMode.finish();
if(mActionMode != null)
mActionMode.setTitle(String.valueOf(adapter.getSelectedCount()) + " selected");
}
private class SelectableAdapter extends ArrayAdapter<String>{
private SparseBooleanArray mSelectedItemsIds;
public SelectableAdapter(CreateFragment createFragment, ArrayList<String> list) {
super(getActivity(), android.R.layout.simple_list_item_1, list);
mSelectedItemsIds = new SparseBooleanArray();
}
public void toggleSelection(int position)
{
selectView(position, !mSelectedItemsIds.get(position));
}
public void removeSelection() {
mSelectedItemsIds = new SparseBooleanArray();
notifyDataSetChanged();
}
public void selectView(int position, boolean value)
{
if(value)
mSelectedItemsIds.put(position, value);
else
mSelectedItemsIds.delete(position);
notifyDataSetChanged();
}
public int getSelectedCount() {
return mSelectedItemsIds.size();// mSelectedCount;
}
public SparseBooleanArray getSelectedIds() {
return mSelectedItemsIds;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(android.R.layout.simple_list_item_1, null);
}
((TextView) convertView).setText(getItem(position));
//change background color if list item is selected
convertView.setBackgroundColor(mSelectedItemsIds.get(position)? 0x9934B5E4: Color.TRANSPARENT);
return convertView;
}
}
private class ActionModeCallback implements ActionMode.Callback {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// inflate contextual menu
mode.getMenuInflater().inflate(R.menu.create, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// Respond to clicks on the actions in the CAB
switch (item.getItemId()) {
case R.id.share:
// do s.th.
mode.finish(); // Action picked, so close the CAB
return true;
case R.id.delete:
// do s.th.
mode.finish(); // Action picked, so close the CAB
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode mode) {
// remove selection
SelectableAdapter adapter = (SelectableAdapter) listView.getAdapter();
adapter.removeSelection();
mActionMode = null;
}
}
}
And this is the error in LogCat:
FATAL EXCEPTION: main
java.lang.ClassCastException: android.widget.HeaderViewListAdapter cannot be cast to com.damson.android.tipspromenad.tabs.CreateFragment$SelectableAdapter
at com.damson.android.tipspromenad.tabs.CreateFragment.onListItemCheck(CreateFragment.java:113)
at com.damson.android.tipspromenad.tabs.CreateFragment.access$2(CreateFragment.java:112)
at com.damson.android.tipspromenad.tabs.CreateFragment$2.onItemLongClick(CreateFragment.java:66)
at android.widget.AbsListView.performLongPress(AbsListView.java:2925)
at android.widget.AbsListView$CheckForLongPress.run(AbsListView.java:2875)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:213)
at android.app.ActivityThread.main(ActivityThread.java:4787)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556)
at dalvik.system.NativeStart.main(Native Method)
Sorry for a long question! I hope you can help me :) Thanks!
That tutorial does not use addHeaderView(). Your code uses addHeaderView(). Your error is involving the header view:
java.lang.ClassCastException: android.widget.HeaderViewListAdapter cannot be cast to com.damson.android.tipspromenad.tabs.CreateFragment$SelectableAdapter
This is because when you call addHeaderView(), getListAdapter() will no longer return your own adapter, but rather a new adapter, one that wraps yours and supplies the header view.
Call getWrappedAdapter() on the HeaderViewListAdapter to get your SelectableAdapter.
UPDATE
HeaderViewListAdapter wasThisReallySoHard=(HeaderViewListAdapter)listView.getAdapter();
SelectableAdapter adapter=(SelectableAdapter)wasThisReallySoHard.getWrappedAdapter();
Related
I'm having an issue with a long press on a row to get highlighted.
I looked over how to handle the single click to lead to another activity and a long press to get the contextual action bar comes up. I decided to switch the listview choice by ListView.CHOICE_MODE_MULTIPLE_MODAL and ListView.CHOICE_MODE_NONE to let the built in android methods to do their work on selected rows. The single click is working as it is intended.
The multiple modal is working and the contextual action bar is showing the number of the notes selected yet the rows aren't highlighted. I have checked the theme and it doesn't work either for Theme.AppCompat and Theme.AppCompat.Light.
Here are the code -
Classes
MainActivity extends AppCompatActivity {}
ObjectListFragment extends ListFragment implements
AdapterView.OnItemLongClickListener, AbsListView.MultiChoiceModeListener {}
NoteListAdapter extends ArrayAdapter<NoteTO> {}
initialization of listeners and other objects in ListFragment
//get the data
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
LogUtils.LOGD(getClass().getSimpleName(), "onViewCreated");
ListView listView = getListView();
listView.setOnItemLongClickListener(this);
listView.setMultiChoiceModeListener(this);
int choiceMode = (savedInstanceState == null ? ListView.CHOICE_MODE_NONE : savedInstanceState.getInt(STATE_CHOICE_MODE));
listView.setChoiceMode(choiceMode);
}
Action mode methods, long press method and private methods
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
l.setItemChecked(position, true);
NoteTO note = (NoteTO) l.getItemAtPosition(position);
Intent i = new Intent(getActivity(), NoteActivity.class);
NotePreferences.setNote(getActivity(), note);
AppPreferences.setActionFlag(getActivity(), AppConstants.ACTION_UPDATE);
startActivityForResult(i, 1);
}
#Override
public void onItemCheckedStateChanged(ActionMode actionMode, int i, long l, boolean b) {
if (mActiveMode != null) {
updateSubtitle(actionMode);
}
}
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.contextual_menu, menu);
this.mActiveMode = actionMode;
updateSubtitle(mActiveMode);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
boolean result = performActions(menuItem);
updateSubtitle(mActiveMode);
return(result);
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
if (mActiveMode != null) {
mActiveMode = null;
getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);
getListView().setAdapter(getListView().getAdapter());
}
}
public boolean performActions(MenuItem item) {
List<NoteTO> list = listAdapter.getList();
Set<Integer> positionSet = listAdapter.getCurrentCheckedPosition();
Integer[] positions = listAdapter.getCurrentCheckedPosition().toArray(new Integer[positionSet.size()]);
if(item.getItemId() == R.id.item_delete) {
List<NoteTO> notesToBeDeleted = new ArrayList<NoteTO>();
String text = "";
for(int i = 0; i < positions.length; i++) {
NoteTO note = (NoteTO) list.get(positions[i]);
notesToBeDeleted.add(note);
}
task = new ObjectListFragment.deleteNotesTask().execute(notesToBeDeleted);
return true;
}
else if(item.getItemId() == R.id.item_share) {
String text = "";
for(int i = 0; i < positions.length; i++) {
NoteTO note = (NoteTO) list.get(positions[i]);
text = text + note.getBody() + "\r\n"+ "\r\n";
}
shareNotes(text);
return true;
}
return false;
}
private void updateSubtitle(ActionMode mode) {
mode.setSubtitle("(" + getListView().getCheckedItemCount() + ")");
}
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long id) {
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
getListView().setItemChecked(position, true);
return(true);
}
Adapter - there isn't any code that overwrite up the selectors of the rows.
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View row = super.getView(position, convertView, parent);
NoteHolder holder = (NoteHolder) row.getTag();
if(holder == null) {
holder = new NoteHolder(row);
row.setTag(holder);
}
NoteTO note = getItem(position);
if(mSettings.getListSingleLine() == 0) {
holder.textviewNote.setEllipsize(null);
holder.textviewNote.setSingleLine(false);
}
else {
holder.textviewNote.setEllipsize(TextUtils.TruncateAt.END);
holder.textviewNote.setSingleLine();
}
holder.textviewNote.setText(note.getBody());
holder.textviewNote.setTextSize(getmSettings().getListViewTextSize());
holder.textviewNote.setTypeface(getmSettings().getGeneralFontStyleTypeFace());
//holder.textviewNote.setBackgroundColor(ContextCompat.getColor(context, android.R.color.background_dark));
//holder.textviewNote.setBackground(selector);
//arraylist has containers to get the boolean of the position
if (mSelection.get(position) != null) {
//holder.textviewNote.setSelected(true);
//holder.textviewNote.setBackgroundColor(ContextCompat.getColor(context, android.R.color.holo_blue_light));
//holder.textviewNote.setTextColor(mSettings.getListViewTextColor());
//holder.textviewNote.setBackground(selector);
}
return row;
}
I found the solution, I overlooked the styles where will get the highlighted rows -
<item name="android:background">?android:attr/activatedBackgroundIndicator</item>
Thanks to
Highlight custom listview item when long click
and
Commonsware - The Busy Coder's Guide to Android Development
I'm quite new at Android developing and I was trying to put a a context menu on my Listview that uses a CursorAdapter, I followed this examples https://www.youtube.com/watch?v=Pq9YQl0nfEk Using contextmenu with listview in android but the menu doesn't appear and I don't no why, appearently everything's OK.
These is the code of my activity
public class ProductsView extends AppCompatActivity {
private FloatingActionButton botonAnadir;
private ListView lvProducts;
SetOfProductList mylist;
private ProductAdapter productAdapter;
Cursor cursor;
private ProductList productList;
private Long idProductList;
private DBManager dbManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getIntent().getExtras();
if (bundle != null){
productList = bundle.getParcelable("productList");
setTitle(getResources().getString(R.string.show_products) + " " + productList.getName());
}
setContentView(R.layout.products_view);
initialize();
}
private void initialize(){
botonAnadir = (FloatingActionButton)findViewById(R.id.button_add_product);
lvProducts = (ListView)findViewById(R.id.listViewProducts);
dbManager = new DBManager(getApplicationContext());
loadProducts();
registerForContextMenu(lvProducts);
botonAnadir.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
creaNuevaLista();
}
});
lvProducts.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Product aux = getProduct(position);
goToNewProduct(aux);
}
});
lvProducts.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
// markAsPurchased(position);
return true;
}
});
}
private void markAsPurchased(int position){
Product p = getProduct(position);
TextView item = (TextView) findViewById(R.id.textview_product_name);
if (p.getPurchased() == 0){
p.setPurchased(1); //mark as a purchased
item.setPaintFlags(item.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
else{
p.setPurchased(0); //mark as a purchased
item.setPaintFlags(item.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
}
editProduct(p); //makes de update
loadProducts();
}
private void editProduct(Product product){
dbManager.updateProduct(product);
}
private void goToNewProduct(Product p){
Intent intent = new Intent(this,NewProductActivity.class);
Bundle b = new Bundle();
b.putBoolean("editMode",true);
b.putParcelable("product", p);
intent.putExtras(b);
startActivity(intent);
}
private void creaNuevaLista(){
Intent i = new Intent(this,NewProductActivity.class);
Bundle b = new Bundle();
b.putParcelable("productList", productList);
i.putExtras(b);
startActivityForResult(i, 0);
}
private void loadProducts(){
cursor = dbManager.getAllProductsWithCursor(productList);
productAdapter = new ProductAdapter(this,cursor);
lvProducts.setAdapter(productAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if (v.getId() == R.id.listViewProducts){
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.prodcut_view_context_menu,menu);
}
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()){
case R.id.delete_id:
return true;
default:
return super.onContextItemSelected(item);
}
}
}
And this is the adapter that I'm using
public class ProductAdapter extends CursorAdapter {
private LayoutInflater inflater;
//Constructor
public ProductAdapter(Context context, Cursor cursor) {
super(context, cursor,false);
}
// The newView method is used to inflate a new view and return it,
// you don't bind any data to the view at this point.
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.layout_product_row,parent,false);
return view;
}
// The bindView method is used to bind all data to a given view
// such as setting the text on a TextView.
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView tv_product_name = (TextView) view.findViewById(R.id.textview_product_name); // Find fields to populate in inflated template
String product_name = cursor.getString(cursor.getColumnIndexOrThrow("name"));// Extract properties from cursor
// Populate fields with extracted properties
tv_product_name.setText(product_name);
if (cursor.getInt(cursor.getColumnIndexOrThrow("purchased")) == 1){
tv_product_name.setPaintFlags(tv_product_name.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
}
public Product getProduct(int position, Cursor cursor) {
Product p=null;
if(cursor.moveToPosition(position)) {
Log.e("PRODUCTLISTADAPTER","nombre es: "+cursor.getString(cursor.getColumnIndex("name")));
p = new Product (cursor.getLong(cursor.getColumnIndex("_id")),cursor.getString(cursor.getColumnIndex("name")),
cursor.getString(cursor.getColumnIndex("unit_type")),cursor.getDouble(cursor.getColumnIndex("value")),cursor.getInt(cursor.getColumnIndex("purchased")),cursor.getLong(cursor.getColumnIndex("id_pl")));
}
return p;
}
}
Can anyone exaplin me why it isn't working? isn't it necessary to make something on the LongClickListener ? because I don't see that the menu is being created.
Thanks in advance.
You've set an OnItemLongClickListener for the ListView, which will run before the context Menu is created. Returning true from its onItemLongClick() method indicates that the long click is being consumed there, so the Menu will not be created.
If you don't actually need the OnItemLongClickListener, you can remove the relevant code. If you do need it as well, for some reason, you can return false from onItemLongClick(), and your Menu will then show.
I have a listview in fragment and my problem is when I select items on listview then it's fine, but when I scroll my listview then item's background is checked for another items, but I don't want that. You can see my image, first I select 3 items (Browser, Calendar, Contact), when I scroll listview then 2 items (Dev tool, Camera) have a changed background, if I continue scroll then listview has more items like that.
Here is my code:
#SuppressLint("NewApi") public class Tab2 extends Fragment{
private PackageManager packageManager = null;
private List<ApplicationInfo> applist = null;
public static ApplicationAdapter listadaptor = null;
public static ListView list;
private ActionMode acMode;
private int counterChecked = 0;
private SparseBooleanArray sp;
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.tab2test,container,false);
list = (ListView)v.findViewById(R.id.list_view2);
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
list.setItemsCanFocus(false);
packageManager = getActivity().getPackageManager();
applist = checkForLaunchIntent(packageManager.getInstalledApplications(PackageManager.GET_META_DATA));
listadaptor = new ApplicationAdapter(getActivity().getApplicationContext(),R.layout.snippet_list_row, applist);
list.setAdapter(listadaptor);
sp = list.getCheckedItemPositions();
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
//Here i set item's color and unselected color
view.setBackgroundColor(sp.get(position)? 0x9934B5E4: Color.WHITE);
if(counterChecked<1){
acMode = ((AppCompatActivity) getActivity()).startSupportActionMode(mActionModeCallback);
}
String str="";
int i=0;
for(i=0;i<sp.size();i++)
{
if(sp.valueAt(i)){
str+=sp.keyAt(i)+",";
}
}
if(list.isItemChecked(position)){
Log.d("list1", String.valueOf(position));
list.setItemChecked(position, true);
counterChecked++;
}else{
list.setItemChecked(position, false);
counterChecked--;
}
if(counterChecked<1){
mActionModeCallback.onDestroyActionMode(acMode);
}
}
});
return v;
}
private List<ApplicationInfo> checkForLaunchIntent(List<ApplicationInfo> list) {
ArrayList<ApplicationInfo> applist = new ArrayList<ApplicationInfo>();
for (ApplicationInfo info : list) {
try {
if(isSystemPackage(info)){
if (null != packageManager.getLaunchIntentForPackage(info.packageName)) {
applist.add(info);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return applist;
}
private boolean isSystemPackage(ApplicationInfo AInfo) {
return ((AInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) ? true
: false;
}
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback(){
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.cab_menu, menu);
MainActivity.toolbar.setVisibility(View.GONE);
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
mode.finish();
MainActivity.toolbar.setVisibility(View.VISIBLE);
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode arg0, Menu arg1) {
// TODO Auto-generated method stub
return false;
}
};
}
You actually trigger OnItemClickListener when scrolling which causes a multiple select for items that you didn't want to include.
A better approach would be using a checkBox inside your listView Item and mark the item as selected when the check box is checked: check out this link on how to Get Selected Item Using Checkbox in Listview.
If you incest on using onClick then you can implement longClickListener on your listView Items which may prevent get item selected when scrolling but my advice to you is to go with checkBoxes.
OnLongClickListener Implementation:
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> arg0, View v,
int index, long arg3) {
// TODO Auto-generated method stub
String str=listView.getItemAtPosition(index).toString();
return true;
}
});
I have a custom list view, contains delete button and spinner (the spinner contain A-E characters).
And I have an issue with deleting the true row from my custom list view.
Custom list view code:
public class customListView extends BaseAdapter
{
public Activity context;
ArrayList<MyActivity.UserProperties> userPropertieses;
public String[] spinnerValues;
public LayoutInflater inflater;
public customListView(Activity context, ArrayList<MyActivity.UserProperties> userPropertieses, String[] spinnerArray)
{
super();
this.context = context;
this.userPropertieses = userPropertieses;
spinnerValues = spinnerArray;
this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() { return userPropertieses.size(); }
#Override
public Object getItem(int i) { return null; }
#Override
public long getItemId(int i) { return 0; }
class ViewHolder
{
Button btnRemove;
Spinner spinner;
}
#Override
public View getView(final int i, View view, ViewGroup viewGroup)
{
final ViewHolder holder;
if (view == null)
{
holder = new ViewHolder();
view = inflater.inflate(R.layout.custom_layout, null);
holder.spinner = (Spinner) view.findViewById(R.id.spinner);
holder.btnRemove = (Button) view.findViewById(R.id.bu_Remove);
// populate spinner
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>
(view.getContext(), android.R.layout.simple_spinner_item, spinnerValues);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
holder.spinner.setFocusable(true);
holder.spinner.requestFocus();
holder.spinner.setAdapter(dataAdapter);
view.setTag(holder);
// remove user implementation
holder.btnRemove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i("custom list view debug", "i = " + i); // debug. verify i value is correct
((MyActivity) context).deleteUser(i);
}
});
}
else
holder = (ViewHolder) view.getTag();
return view;
}
}
And my main activity code looks like this:
public class MyActivity extends Activity
{
ListView listView;
ArrayList<UserProperties> userProperties = new ArrayList<UserProperties>();
customListView adapter;
SensorManager sensorManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
for (int i = 0; i<5; i++) {
userProperties.add(new UserProperties());
}
listView = (ListView) findViewById(R.id.listView);
String[] spinnerValues = new String[] {"A", "B", "C", "D", "E"};
adapter = new customListView(MyActivity.this, userProperties, spinnerValues);
listView.setAdapter(adapter);
}
public void deleteUser (int index)
{
Log.i("debug", "Removing item " + index); // the index is really true and the true node deleting from the ArrayList but somehow the latest delete from the UI
userProperties.remove(index);
adapter.notifyDataSetChanged();
}
}
When I click on the Remove button deleteUser method called with the right index. but although the right node deleting from userProperties ArrayList somehow after notiftDataSetChanged is still alive
and the latest node delete.
So, How can I delete the right node/row (from the ArrayList and UI...)
Thank you!
EDIT:
Just to be clear, i variable contain true index. The true node deleted from the ArrayList. but something append after I called notify method.
I prefer to stay with BaseAdapter and not implement ArrayAdapter. Thank you!
EDIT 2:
After more debugging I found out my question was wrong. the true row really deleted just spinner values somehow update their values. I cannot close the question because it already answered. Thanks.
((MyActivity) context).deleteUser(i);
This line will always delete the first value from the ListView
You can use CAB (contextual action bar)
See if the code helps you(it's basically a ListActivity with a custom adapter to hold the status of checked items(+ different background)):
public class CABSelection extends ListActivity {
private ArrayList<String> mItems = new ArrayList<String>();
private SelectionAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
for (int i = 0; i < 24; i++) {
mItems.add("Name" + i);
}
// R.layout.adapters_cabselection_row is a LinearLayout(with green
// background(#99cc00)) that wraps an ImageView and a TextView
mAdapter = new SelectionAdapter(this,
R.layout.adapters_cabselection_row, R.id.the_text, mItems);
setListAdapter(mAdapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() {
private int nr = 0;
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.cabselection_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
StringBuilder sb = new StringBuilder();
Set<Integer> positions = mAdapter.getCurrentCheckedPosition();
for (Integer pos : positions) {
sb.append(" " + pos + ",");
}
switch (item.getItemId()) {
case R.id.edit_entry:
Toast.makeText(CABSelection.this, "Edited entries: " + sb.toString(),
Toast.LENGTH_SHORT).show();
break;
case R.id.delete_entry:
Toast.makeText(CABSelection.this, "Deleted entries : " + sb.toString(),
Toast.LENGTH_SHORT).show();
break;
case R.id.finish_it:
nr = 0;
mAdapter.clearSelection();
Toast.makeText(CABSelection.this, "Finish the CAB!",
Toast.LENGTH_SHORT).show();
mode.finish();
}
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
nr = 0;
mAdapter.clearSelection();
}
#Override
public void onItemCheckedStateChanged(ActionMode mode,
int position, long id, boolean checked) {
if (checked) {
nr++;
mAdapter.setNewSelection(position, checked);
} else {
nr--;
mAdapter.removeSelection(position);
}
mode.setTitle(nr + " rows selected!");
}
});
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
l.setItemChecked(position, !mAdapter.isPositionChecked(position));
}
private class SelectionAdapter extends ArrayAdapter<String> {
private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
public SelectionAdapter(Context context, int resource,
int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
}
public void setNewSelection(int position, boolean value) {
mSelection.put(position, value);
notifyDataSetChanged();
}
public boolean isPositionChecked(int position) {
Boolean result = mSelection.get(position);
return result == null ? false : result;
}
public Set<Integer> getCurrentCheckedPosition() {
return mSelection.keySet();
}
public void removeSelection(int position) {
mSelection.remove(position);
notifyDataSetChanged();
}
public void clearSelection() {
mSelection = new HashMap<Integer, Boolean>();
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);//let the adapter handle setting up the row views
v.setBackgroundColor(Color.parseColor("#99cc00")); //default color
if (mSelection.get(position) != null) {
v.setBackgroundColor(Color.RED);// this is a selected position so make it red
}
return v;
}
}
}
Another way
adapter = new MyListAdapter(this);
lv = (ListView) findViewById(android.R.id.list);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> a, View v, int position, long id) {
AlertDialog.Builder adb=new AlertDialog.Builder(MyActivity.this);
adb.setTitle("Delete?");
adb.setMessage("Are you sure you want to delete " + position);
final int positionToRemove = position;
adb.setNegativeButton("Cancel", null);
adb.setPositiveButton("Ok", new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
MyDataObject.remove(positionToRemove);
adapter.notifyDataSetChanged();
}});
adb.show();
}
});
getView(final int i,
Do not make i final. You did that to use i in onClick(). But that is not possible. So remove the final. Add:
holder.btnRemove.setTag(i);
And in onClick:
int position = v.getTag();
..deleteUser(position);
Maybe you have to cast something somewhere..
Remark: You have to set the tag always. So do it just before return view;.
Please do not use an i for position.
I have a list activity, and I chose to manually add the first item which is "add new item...".
I have registered the context menu for the whole listview, using registerForContextMenu(getListView()); straight into the onCreate.
When the context menu is build, the system calls onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo). The View v is the listView, and I cannot find a way to know which item in the listview is being long-pressed.
I could create a xml layout, with a layout for the "add new item..." and add a listview after, which would be populated by the activity, and that would react to the context menu, but I'm sure there is a way to solve this problem without any xml layout.
I have tried to register each view inside my listview using registerForContextMenu, which works, however the listview doesn't respond to touch anymore.
Here is my activity code listing:
public class AMain extends ListActivity {
private List<String> pregList;
private List<Long> pregIds;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pregList = new ArrayList<String>();
pregIds = new ArrayList<Long>();
registerForContextMenu(getListView());
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
// TODO: hide the menu for the 1st item!!
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
Logger.d("id = "+info.id);
switch (item.getItemId()) {
case R.id.menu_show:
showPregnancy((int) info.id);
return true;
case R.id.menu_edit:
editPregnancy((int) info.id);
return true;
case R.id.menu_delete:
//TODO: do the deletion
return true;
default:
return super.onContextItemSelected(item);
}
}
protected void onStart() {
super.onStart();
clearPregList();
loadPregList();
getListView().setAdapter(new PregnancyListAdapter(this));
}
void clearPregList() {
pregList.clear();
pregIds.clear();
}
void loadPregList() {
PregnanciesDbAdapter db = new PregnanciesDbAdapter(this);
db.open();
Cursor c = db.getPregnancies();
if (c != null) {
do {
pregList.add(c.getString(c.getColumnIndex(PregnanciesDbAdapter.KEY_PREG_NOM)));
pregIds.add(c.getLong(c.getColumnIndex(PregnanciesDbAdapter.KEY_PREG_ROWID)));
} while (c.moveToNext());
c.close();
}
db.close();
}
private class PregnancyListAdapter extends BaseAdapter {
private Context context;
public PregnancyListAdapter(Context ctx) {
context = ctx;
}
#Override
public int getCount() {
return pregList.size()+1;
}
#Override
public Object getItem(int position) {
if (position == 0) { // add button
return getString(R.string.addPreg);
} else {
return pregList.get(position-1);
}
}
#Override
public long getItemId(int position) {
if (position == 0) {
return -1;
}
return pregIds.get(position-1);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout itemLayout;
itemLayout= (LinearLayout) LayoutInflater.from(context).inflate(R.layout.homelist_item_pregnancy, parent, false);
ImageView logo = (ImageView) itemLayout.findViewById(R.id.logo);
TextView pregName = (TextView) itemLayout.findViewById(R.id.pregName);
if (position == 0) {
itemLayout.setFocusable(false);
itemLayout.setFocusableInTouchMode(false);
pregName.setText(getString(R.string.addPreg));
} else {
logo.setVisibility(View.INVISIBLE);
pregName.setText(pregList.get(position-1));
}
itemLayout.setId(position);
return itemLayout;
}
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if (position == 0) {
startActivity(prepareIntent(AShowPregnancy.class, 0));
} else {
showPregnancy(position-1);
}
}
void showPregnancy(int pregId) {
startActivity(prepareIntent(AShowPregnancy.class, pregId));
}
void editPregnancy(int pregId) {
startActivity(prepareIntent(ANewPregnancy.class, pregId));
}
Intent prepareIntent(Class<?> className, int pregId) {
Intent i = new Intent(this, className);
if (pregId > 0) {
PregnanciesDbAdapter db = new PregnanciesDbAdapter(this);
db.open();
Pregnancy p = db.load(pregIds.get(pregId));
db.close();
i.putExtra(C.EXTRA_PREGNANCY, p);
}
return i;
}
}
Thanks for reading. Hope you can help.
Oh, god, again. I found out myself how to do it, and it was easier than easy.
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
// info.position is the position in the ListView
I hate myself :)