I am developing a gallery-like Activity. Everything runs fine but there is a key functionality which is missing and I couldn't find a decent answer or explanation. What I need is to give the user the ability to select multiple items by long clicking on them.
Here is the desired result:
You can clearly see the selected pics and the options in the ActionBar.
My setup is this:
1.I have a GridView in my XML:
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:verticalSpacing="5dp"
android:horizontalSpacing="5dp"
android:stretchMode="columnWidth"
android:gravity="center"/>
2.It is attached to a class, which extends BaseAdapter and loads images using Picasso:
public class GalleryAdapter extends BaseAdapter {
Context mContext;
List<String> mDataset;
public GalleryAdapter(Context context, List<String> dataset) {
mContext = context;
mDataset = dataset;
}
#Override
public int getCount() {
return mDataset.size();
}
#Override
public Object getItem(int position) {
return mDataset.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if(convertView == null){
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(200,200));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8,8,8,8);
} else {
imageView = (ImageView) convertView;
}
//TODO: REMOVE INTEGER.VALUEOFF. IT'S MADE FOR MOCK
Picasso.with(mContext).load(Integer.valueOf(mDataset.get(position))).fit().into(imageView);
return imageView;
}
}
3.It is attached to the Activity:
//Get images paths
List<String> data = getImagesPath(this);
List<String> sortedData = new ArrayList<>();
for(String file : data){
sortedData.add(0, file);
}
GalleryAdapter adapter = new GalleryAdapter(this, sortedData);
mGallery.setAdapter(adapter);
From now on the struggle begins:
I tried making my item in the GridView to implement Checkable:
public class CheckableItem extends LinearLayout implements Checkable{
private boolean mIsChecked = false;
private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
public CheckableItem(Context context) {
super(context);
}
#Override
protected int[] onCreateDrawableState(int extraSpace) {
int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked())
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
return drawableState;
}
#Override
public void setChecked(boolean checked) {
mIsChecked = checked;
refreshDrawableState();
}
#Override
public boolean isChecked() {
return mIsChecked;
}
#Override
public void toggle() {
setChecked(!isChecked());
refreshDrawableState();
}
Then I load it in my XML and added .setChoiceMode(GridView.CHOICE_MODE_MULTIPLE) to my GridView in the Activity. Nothing Happened.
Added MultiChoiceModeListener:
class MultiChoiceListener implements GridView.MultiChoiceModeListener{
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
int selectCount = mGallery.getCheckedItemCount();
switch (selectCount) {
case 1:
mode.setSubtitle("One item selected");
break;
default:
mode.setSubtitle("" + selectCount + " items selected");
break;
}
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.setTitle("Select Items");
mode.setSubtitle("One item selected");
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
}
}
Then added it to my gridView .setMultiChoiceModeListener(newMultiChoiceListener()); but still no results.
Can someone propose a way to achieve this item selecting behavior in GridView? I'd like to use the native Android API, no 3rd party libraries.
I think Checkable and the rest that I see in your code is a bit of an overkill...When I want to implement something like that I just add another field in the class of the object that is shown in the GridView/ListView which stores the checked state of the object. example:
class Image {
Bitmap bm;
boolean isChecked=false;
public Image(Bitmap bm){
this.bm=bm;
}
public boolean isChecked(){
return isChecked;
}
public void toggleChecked(){
isChecked = !isChecked;
}
}
and feed an ArrayList to the adapter. an in the getView method of the adapter I do something like this;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(images.get(position).isChecked()){
//show the overlay view that suggests the item is selected
}
else{
//hide the overlay view
}
}
finally in the onItemClickListener of the ListView
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
images.get(position).toggleChecked();
listView.getAdapter().notifyDataSetChanged();
}
});
Related
This is the first grid where I selected
the problem is:
when I scroll down, here random images are getting selected
I used glide library for grid view. Here's the Java Code for Multiple selection:
mgridview.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode actionMode, int i, long l, boolean b) {
if (sel_tab2_images.contains(tab2_images.get(i))) {
sel_count = sel_count - 1;
actionMode.setTitle(sel_count + " images selected");
sel_tab2_images.remove(tab2_images.get(i));
viewprev = mgridview.getChildAt(i - mgridview.getFirstVisiblePosition());
viewprev.setBackgroundColor(Color.WHITE);
viewprev.setAlpha(1f);
if(Build.VERSION.SDK_INT>=23) {
viewprev.setForeground(null);
}
} else {
sel_count = sel_count + 1;
actionMode.setTitle(sel_count + " images selected");
sel_tab2_images.add(tab2_images.get(i));
viewprev = mgridview.getChildAt(i - mgridview.getFirstVisiblePosition());
if (viewprev != null) {
viewprev.setAlpha(0.5f);
//ImageView imageView=viewprev.findViewById(R.id.tick);
//Resource(R.drawable.ic_save_black_24dp);
if(Build.VERSION.SDK_INT>=23) {
viewprev.setForeground(getResources().getDrawable(R.drawable.ic_check_white_24dp));
}
}
else
Toast.makeText(getContext(), "Error Occured", Toast.LENGTH_SHORT).show();
}
}
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
MenuInflater inflater = actionMode.getMenuInflater();
inflater.inflate(R.menu.context_action_bar, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
int del_count = 0;
switch (menuItem.getItemId()) {
case R.id.delete_action_bar:
for (String sel : sel_tab2_images) {
file = new File(sel);
if (file.exists()) {
file.delete();
tab2_images.remove(sel);
if (tab1_fragment.tab1_images.contains(sel)) {
tab1_fragment.tab1_images.remove(sel);
}
if (tab3_fragment.spam_list.contains(sel)) {
tab3_fragment.spam_list.remove(sel);
}
UpdateGallery(sel);
/*
int pos_1=tab2_images.indexOf(sel);
tab2_images.remove(sel);
adapter.notifyDataSetChanged();
viewprev=mgridview.getChildAt(pos_1);
viewprev.setBackgroundColor(Color.WHITE);
*/
del_count++;
}
}
adapter = new ImageAdapterGridView(getContext());
mgridview.setAdapter(adapter);
Toast.makeText(getContext(), del_count + " images deleted", Toast.LENGTH_SHORT).show();
sel_count = 0;
sel_tab2_images.clear();
actionMode.finish();
break;
}
return true;
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
}
});
return view;
}
Below is the java code for Grid View. I also tried #overriding getItem and getItemId methods but it's not working. This is my first app and I'm still learning. Please help me to fix this!
public class ImageAdapterGridView extends BaseAdapter {
private Context mcontext;
public ImageAdapterGridView(Context c) {
mcontext = c;
}
public int getCount() {
return tab2_images.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertview, ViewGroup parent) {
ImageView imageView;
if(convertview==null){
imageView= new ImageView(mcontext);
imageView.setLayoutParams(new GridView.LayoutParams(280,320));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(16,16,16,16);
}
else{
imageView=(ImageView)convertview;
}
Glide.with(tab2_fragment.this).load("file://" + tab2_images.get(position))
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.skipMemoryCache(true)
.into(imageView);
return imageView;
}
}
#Override
public void onResume() {
super.onResume();
adapter = new ImageAdapterGridView(getContext());
mgridview.setAdapter(adapter);
}
}
You're relying on view in a list. In list views are being reused as they get off screen. So to get this done you have to declare a boolean isSelected per each item (so the best place to do this is in your item model which holds all each grid properties) and make it true as the user select your grid item and always update your view based on that boolean not the view.
Currently your model is holding just the url of your images. If you need to save the isSelected boolean there you should build your model object like:
public class ImageModel {
public String url;
public boolean isSelected;
}
And then use the field objects in your grid list:
public void onItemCheckedStateChanged(ActionMode actionMode, int i, long l, boolean b) {
ImageModel image = tab2_images.get(i);
if (image.isSelected) {
// Image is selected you need to deselect it
} else {
// Image is not selected you need to select it
}
}
In your adapter:
public View getView(int position, View convertview, ViewGroup parent) {
// Your view construction code
ImageModel image = tab2_images.get(i);
if (image.isSelected) {
// Show your check image view
} else {
// Image is not selected yet, hide your check image view
}
}
I hope this helps but grid view is considered deprecated, try to consider using RecyclerView which is more efficient and fast.
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'm trying to create ListView with installed apps. User selects apps inside wizard (basically viewpager).
My plan is to create a list of custom views (icon, name, package) that will allow to select more than one item. Unfortunatelly checkboxes won't work, because I need this place for another functionality. So, I'll change the background of the element.
So, I found a solution on stackoverflow and changed it a bit.
Firstly - main activity with this list.
public class MainActivity extends ListActivity {
private static final String TAG = MainActivity.class.getName();
private ApplicationsAdapter applicationsAdapter;
private void getAppList(){
//get apps asynch
createList(list);
}
private void createList(ArrayList<ApplicationItem> list){
applicationsAdapter = new ApplicationsAdapter(this, R.layout.application_list_item, list);
setListAdapter(applicationsAdapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
getListView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
private int nr = 0;
#Override
public boolean onCreateActionMode(android.view.ActionMode mode, Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.cabselection_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) {
return false;
}
#Override
public void onDestroyActionMode(android.view.ActionMode mode) {
nr = 0;
applicationsAdapter.clearSelection();
}
#Override
public void onItemCheckedStateChanged(android.view.ActionMode mode, int position, long id, boolean checked) {
if (checked) {
nr++;
applicationsAdapter.setNewSelection(position, checked);
L.d(TAG, applicationsAdapter.getItem(position).getAppName());
} else {
nr--;
applicationsAdapter.removeSelection(position);
}
mode.setTitle(nr + " rows selected!");
}
});
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getAppList();
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
ApplicationItem item = (ApplicationItem)l.getAdapter().getItem(position);
L.d(TAG + "onListItemClick", applicationsAdapter.getItem(position).getAppName());
l.setItemChecked(position, !applicationsAdapter.isPositionChecked(position));
}
}
In my case, normally this whole thing is inside a fragment, inside the viewpager. For the sake of clarity I changed this into typical activity.
Now, the adapter:
public class ApplicationsAdapter extends ArrayAdapter<ApplicationItem> {
// private HashMap<ApplicationItem, Boolean> objects;
private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
public ApplicationsAdapter(Context context, int textViewResourceId, ArrayList<ApplicationItem> objects) {
super(context, textViewResourceId, objects);
//this.objects = 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();
}
public ApplicationItem getItem(int position){
return super.getItem(position);
}
public View getView(int position, View convertView, ViewGroup parent){
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.application_list_item, null);
}
ApplicationItem item = super.getItem(position);
if(item != null){
TextView appName = (TextView) v.findViewById(R.id.appName);
TextView appPackage = (TextView) v.findViewById(R.id.appPackage);
ImageView appIcon = (ImageView) v.findViewById(R.id.appIcon);
if (appName != null){
appName.setText(item.getAppName());
}
if (appPackage != null){
appPackage.setText(item.getPackageName());
}
if (appIcon != null){
appIcon.setImageDrawable(item.getIcon());
}
}
v.setBackgroundColor(Color.parseColor("#00FFFFFF")); //default color
if (mSelection.get(position) != null) {
v.setBackgroundColor(Color.BLUE);// this is a selected position so make it red
}
return v;
}
}
THE PROBLEM:
ActionMode is nice, however I'm not sure how to keep selected elements after it's destroy.
Normally inside onDestroyActionMode I'm clearing the selection. Great, so I'll just delete that. Now after clicking the "tick" symbol all apps are still selected. However, getting back to them is now problematic, because ActionMode will only "fire up" when clicking on unselected element.
So - how should I handle that?
Ha, the answer was quite simple. I should have thought about it yesterday, but apparently I was a bit too exhausted.
First of all, I changed the mode of listview into
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
And deleted setMultiChoiceModeListener() and I'm only using
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
ApplicationItem item = (ApplicationItem)l.getAdapter().getItem(position);
L.d(TAG + "onListItemClick", applicationsAdapter.getItem(position).getAppName());
boolean checked = item.isSelected();
if (!checked) {
item.setSelected(true);
applicationsAdapter.setNewSelection(position, checked);
L.d(TAG, applicationsAdapter.getItem(position).getAppName());
} else {
item.setSelected(false);
applicationsAdapter.removeSelection(position);
}
}
That simple.
Apparently, ActionMode may be fun, but it wasn't the right tool for this job.
And also - adapter from first post can be used as a example of multiselect listView that changes backgrounds instead of checkboxes. Apparently I couldn't find anything simple enough like that.
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 gallery where I have implement a custom adapter extending the BaseAdapter. For some items, I want them to be disabled, and not clickable as well.
Overriding the isEnabled(int) method doesn't work. I am still able to click on the disabled items, and then, the gallery centers this item inside it.
Any ideas?
This following is the relevant source code of gallery widget
public boolean onSingleTapUp(MotionEvent e) {
if (mDownTouchPosition >= 0) {
// An item tap should make it selected, so scroll to this child.
scrollToChild(mDownTouchPosition - mFirstPosition);
// Also pass the click so the client knows, if it wants to.
if (mShouldCallbackOnUnselectedItemClick || mDownTouchPosition == mSelectedPosition) {
performItemClick(mDownTouchView, mDownTouchPosition, mAdapter
.getItemId(mDownTouchPosition));
}
return true;
}
return false;
}
As you can see, the gallery scrolls to the tapped child item before performing the click on it.
So the only way you can truly disable an item is by extending Gallery and overriding onSingleTapUp(MotionEvent e) in it.
#Override
public boolean onSingleTapUp(MotionEvent e) {
int itemPosition = pointToPosition((int) e.getX(), (int) e.getY());
if (item at itemPosition is disabled) {
// Do nothing.
return true;
}
return super.onSingleTapUp(e);
}
Try and let me know.
Try the below code where you can handle the click event for specific positions. Also you can disable the specific items.
public class SplashActivity extends Activity{
private Activity _activity;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Gallery g = new Gallery(this);
g.setAdapter(new ImageAdapter(this));
setContentView(g);
}
public class ImageAdapter extends BaseAdapter {
int mGalleryItemBackground;
private Context mContext;
private Integer[] mImageIds = {
R.drawable.menu1,
R.drawable.menu2,
R.drawable.menu3,
R.drawable.menu4,
R.drawable.menu1,
R.drawable.menu2,
R.drawable.menu3,
R.drawable.menu4
};
public ImageAdapter(Context c) {
mContext = c;
}
public int getCount() {
return mImageIds.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
ImageView i = new ImageView(mContext);
i.setImageResource(mImageIds[position]);
i.setLayoutParams(new Gallery.LayoutParams(150, 100));
i.setScaleType(ImageView.ScaleType.FIT_XY);
i.setBackgroundResource(mGalleryItemBackground);
if(position!=0){
i.setEnabled(false);
i.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(SplashActivity.this, "" + position, Toast.LENGTH_SHORT).show();
}
});
}
return i;
}
}
}