I have a problem. What I can remove item after click image on ListView? Every item on list has an icon to remove.
Part of fragment:
ListView listView;
.....
View view = inflater.inflate(R.layout.basic_list, container, false);
listView = (ListView) view.findViewById(R.id.list_view);
.....
listView.setAdapter(adapter);
Part of basic_list:
<ListView
android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Part of ClassAdapter extends BaseAdapter:
public class ClassAdapter extends BaseAdapter {
...
public ClassAdapter(Context context) {
inflater = LayoutInflater.from(context);
cContext = context;
}
....
convertView = inflater.inflate(R.layout.list_adapter, null);
.....
holder.removeIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//????????????
}
Part of list_adapter.xml
<ImageView
android:id="#+id/icon"
android:layout_alignParentLeft="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/box_icon"/>
Below is a sample.
holder.removeIcon.setTag(position);//save index
holder.removeIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Integer position= (Integer) view.getTag(); //get index
dataList.remove(position); //remove the item from data source
notifyDataSetChanged(); //notify to refresh
}
});
Use these code
holder.removeIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ARRAYLIST.remove(position);///position of the getview method
notifyDataSetChanged(); //notify to refresh
}
}
You should remove the clicked item from your data list which should be located in your adapter class.
You probably didnt post the entire code of your adapter class, but your adapter probably a List of the data set that is shown in your listview based on positions?
In your adapters getView method you have a parameter "position", and you can use it to remove the item at that position from your data list and then just call notifyDataSetChanged so the ListView gets updated.
Related
I have a custom adapter for ListView using custom adapter which extends BaseAdapter. In this custom adapter I have a view holder that holds the items shown in every list item.
Can I get a click callback of certain list item child View IN the Activity where I create and fill my ListView?
In your adapter class:
private ViewClickListener mViewClickListener;
public interface ViewClickListener {
void onImageClicked(int position);
}
public void setViewClickListener (ViewClickListener viewClickListener) {
mViewClickListener = viewClickListener;
}
You let your Activity implement ViewClickListener interface. Remember to call myAdapter.setViewClickListener(this); in the Activity
In the getView method:
imageView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mViewClickListener.onImageClicked(position);
}
});
(Android API version 9)I created a spinner with a custom adapter and overrided getView() to inflate it with my xml file which has a text view. But now, my spinner is not closing the dropdown list after user selects an item. Is there anyway to close the spinner dropdown upon selecting an item?
Code
//Code in onCreate function
Spinner list = (Spinner) findViewById(R.id.spn_purchaseList);
listAdapter = new ItemListAdapter(this, new MyItemList());
list.setAdapter(listAdapter);
listAdapter.item_list.addItem(new MyItem("Test", "Test Item"));
listAdapter.notifyDataSetChanged();
//onCreate end
//the class below is inside "MainActivity extends Activity"
class ItemListAdapter extends BaseAdapter
{
Context context;
MyItemList item_list;
MyItem selectedItem;
ItemListAdapter(Context con,MyItemList k)
{
super();
this.context=con;
this.item_list=k;
selectedItem=null;
}
#Override
public int getCount() {
return item_list.getCount();
}
#Override
public MyItem getItem(int arg0) {
return this.item_list.getList().get(arg0);
}
#Override
public long getItemId(int arg0) {
return this.item_list.getPosition(this.item_list.getList().get(arg0));
}
#Override
public View getView(int position, View arg1, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View spinner_item = inflater.inflate(R.layout.spinner_layout, parent, false);
TextView tx = (TextView)spinner_item.findViewById(R.id.txt_spinner);
tx.setId((int) item_list.getPosition(item_list.getList().get(position)));
tx.setText(this.item_list.getList().get(position).name.toString());
tx.setBackgroundResource(R.drawable.spinner_item);
tx.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedItem = item_list.getItem(v.getId());
list.setSelection(v.getId());
}
});
return spinner_item;
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent)
{
return getView(position,convertView,parent);
}
}
Calling setVisibility(View.GONE) works to hide the dropdown but it seems to cause issues with the Spinner state, i.e. you will be unable to reopen the dropdown after it has been closed.
The preferred way is to get a handle to the Spinner and call its onDetachedFromWindow() from your onClick() listener.
#Override
public void onClick(View v) {
// code here to get selected item and do something with it
// hide the spinner dropdown
Spinner spinner = (Spinner) findViewById(R.id.mySpinner);
if (spinner != null) {
try {
Method method = Spinner.class.getDeclaredMethod("onDetachedFromWindow");
method.setAccessible(true);
method.invoke(spinner);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Too late, but for my case I had a custom layout for spinner items. The clickable="true" or adding onClickListeners, onItemSelectedListeners didn't work because I was adding them to root layout.
When I changed my code as following, I added android:background="?attr/selectableItemBackground" to child of parent layout, and set OnItemSelectedListener() on Spinner, and it worked. Spinner dialog or dropdown hides when item is tapped.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground">
<!-- your custom spinner item view -->
</LinearLayout>
</LinearLayout>
just call spinner.dismissDropDown() method of spinner, inside on item click of spinner. Your problem will be solved.
I am implementing ListView in my code. But When I click on the items, it does not respond respond to the click in any way. Could someone help me please? Thanks in advance .
Here is the code .
public class ListaActivity extends Activity {
public final static String EXTRA_MESSAGE = "com.example.provacomunicazione.MESSAGE";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lsta);
Resources res = getResources();
String[] Authors = res.getStringArray(R.array.Lista_Nomi_E_Cognomi_Autori);
ArrayList<String> Autori = new ArrayList<String>();
for (String temp:Authors) {
Autori.add(temp);
}
Collections.sort(Autori);
ArrayList<String> AutoriLetteraSelezionata = new ArrayList<String>();
for (String temp:Autori) {
if (temp.charAt(0)=='A') {
AutoriLetteraSelezionata.add(temp);
}
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.textviewitem, AutoriLetteraSelezionata);
ListView listView = (ListView) findViewById(R.id.listView1);
listView.setAdapter(adapter);
listView.setClickable(true);
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
CharSequence autore = "("+((TextView)view).getText()+")";
Intent i = new Intent(ListaActivity.this, SecondaryActivity.class);
i.putExtra(EXTRA_MESSAGE, autore);
startActivity(i);
});
}
}
You should define on all of the child objects in the item listview (TextView, ImageView etc.):
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
And for the root item RelativeLayout / LinearLayout and so, define:
android:clickable="false"
android:descendantFocusability="blocksDescendants"
android:focusable="false"
android:focusableInTouchMode="false"
If you won't define those, they will "catch" the click event.
And if you have a Custom listView adapter, just check that you override:
#Override
public boolean isEnabled(int position)
{
return true;
}
In my case a problem was in fact that a ListView contained HorizontalScrollViews.
HSV consumes clicks over items and doesn't return OnItemClick to the ListView.
I solved the problem when wrote an OnClickListener inside an adapter that returns a callback to the ListView. See here: https://stackoverflow.com/a/43653085/2914140.
In the customer Item,
set every element
android:clickable="true"
android:focusable="false"
works for me
My ListFragment code
public class ItemFragment extends ListFragment {
private DatabaseHandler dbHelper;
private static final String TITLE = "Items";
private static final String LOG_TAG = "debugger";
private ItemAdapter adapter;
private List<Item> items;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.item_fragment_list, container, false);
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.setHasOptionsMenu(true);
super.onCreate(savedInstanceState);
getActivity().setTitle(TITLE);
dbHelper = new DatabaseHandler(getActivity());
items = dbHelper.getItems();
adapter = new ItemAdapter(getActivity().getApplicationContext(), items);
this.setListAdapter(adapter);
}
#Override
public void onResume() {
super.onResume();
items.clear();
items = dbHelper.getItems(); //reload the items from database
adapter.notifyDataSetChanged();
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if(dbHelper != null) { //item is edited
Item item = (Item) this.getListAdapter().getItem(position);
Intent intent = new Intent(getActivity(), AddItemActivity.class);
intent.putExtra(IntentConstants.ITEM, item);
startActivity(intent);
}
}
}
My ListView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
But this does not refresh the ListView. Even after restarting app the updated items are not shown. My ItemAdapter extends BaseAdapter
public class ItemAdapter extends BaseAdapter{
private LayoutInflater inflater;
private List<Item> items;
private Context context;
public ProjectListItemAdapter(Context context, List<Item> items) {
super();
inflater = LayoutInflater.from(context);
this.context = context;
this.items = items;
}
#Override
public int getCount() {
return items.size();
}
#Override
public Object getItem(int position) {
return items.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ItemViewHolder holder = null;
if(convertView == null) {
holder = new ItemViewHolder();
convertView = inflater.inflate(R.layout.list_item, parent,false);
holder.itemName = (TextView) convertView.findViewById(R.id.topText);
holder.itemLocation = (TextView) convertView.findViewById(R.id.bottomText);
convertView.setTag(holder);
} else {
holder = (ItemViewHolder) convertView.getTag();
}
holder.itemName.setText("Name: " + items.get(position).getName());
holder.itemLocation.setText("Location: " + items.get(position).getLocation());
if(position % 2 == 0) {
convertView.setBackgroundColor(context.getResources().getColor(R.color.evenRowColor));
} else {
convertView.setBackgroundColor(context.getResources().getColor(R.color.oddRowColor));
}
return convertView;
}
private static class ItemViewHolder {
TextView itemName;
TextView itemLocation;
}
}
Can someone help please?
Look at your onResume method in ItemFragment:
#Override
public void onResume() {
super.onResume();
items.clear();
items = dbHelper.getItems(); // reload the items from database
adapter.notifyDataSetChanged();
}
what you just have updated before calling notifyDataSetChanged() is not the adapter's field private List<Item> items; but the identically declared field of the fragment. The adapter still stores a reference to list of items you passed when you created the adapter (e.g. in fragment's onCreate).
The shortest (in sense of number of changes) but not elegant way to make your code behave as you expect is simply to replace the line:
items = dbHelper.getItems(); // reload the items from database
with
items.addAll(dbHelper.getItems()); // reload the items from database
A more elegant solution:
1) remove items private List<Item> items; from ItemFragment - we need to keep reference to them only in adapter
2) change onCreate to :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setHasOptionsMenu(true);
getActivity().setTitle(TITLE);
dbHelper = new DatabaseHandler(getActivity());
adapter = new ItemAdapter(getActivity(), dbHelper.getItems());
setListAdapter(adapter);
}
3) add method in ItemAdapter:
public void swapItems(List<Item> items) {
this.items = items;
notifyDataSetChanged();
}
4) change your onResume to:
#Override
public void onResume() {
super.onResume();
adapter.swapItems(dbHelper.getItems());
}
You are assigning reloaded items to global variable items in onResume(), but this will not reflect in ItemAdapter class, because it has its own instance variable called 'items'.
For refreshing ListView, add a refresh() in ItemAdapter class which accepts list data i.e items
class ItemAdapter
{
.....
public void refresh(List<Item> items)
{
this.items = items;
notifyDataSetChanged();
}
}
update onResume() with following code
#Override
public void onResume()
{
super.onResume();
items.clear();
items = dbHelper.getItems(); //reload the items from database
**adapter.refresh(items);**
}
In onResume() change this line
items = dbHelper.getItems(); //reload the items from database
to
items.addAll(dbHelper.getItems()); //reload the items from database
The problem is that you're never telling your adapter about the new items list. If you don't want to pass a new list to your adapter (as it seems you don't), then just use items.addAll after your clear(). This will ensure you are modifying the same list that the adapter has a reference to.
If the adapter is already set, setting it again will not refresh the listview. Instead first check if the listview has a adapter and then call the appropriate method.
I think its not a very good idea to create a new instance of the adapter while setting the list view. Instead, create an object.
BuildingAdapter adapter = new BuildingAdapter(context);
if(getListView().getAdapter() == null){ //Adapter not set yet.
setListAdapter(adapter);
}
else{ //Already has an adapter
adapter.notifyDataSetChanged();
}
Also you might try to run the refresh list on UI Thread:
activity.runOnUiThread(new Runnable() {
public void run() {
//do your modifications here
// for example
adapter.add(new Object());
adapter.notifyDataSetChanged()
}
});
If you want to update your listview doesn't matter if you want to do that on onResume(), onCreate() or in some other function, first thing that you have to realize is that you won't need to create a new instance of the adapter, just populate the arrays with your data again.
The idea is something similar to this :
private ArrayList<String> titles;
private MyListAdapter adapter;
private ListView myListView;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
myListView = (ListView) findViewById(R.id.my_list);
titles = new ArrayList<String>()
for(int i =0; i<20;i++){
titles.add("Title "+i);
}
adapter = new MyListAdapter(this, titles);
myListView.setAdapter(adapter);
}
#Override
public void onResume(){
super.onResume();
// first clear the items and populate the new items
titles.clear();
for(int i =0; i<20;i++){
titles.add("New Title "+i);
}
adapter.notifySetDataChanged();
}
So depending on that answer you should use the same List<Item> in your Fragment. In your first adapter initialization you fill your list with the items and set adapter to your listview. After that in every change in your items you have to clear the values from the main List<Item> items and than populate it again with your new items and call notifySetDataChanged();.
That's how it works : ).
An answer from AlexGo did the trick for me:
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
messages.add(m);
adapter.notifyDataSetChanged();
getListView().setSelection(messages.size()-1);
}
});
List Update worked for me before when the update was triggered from a GUI event, thus being in the UI thread.
However, when I update the list from another event/thread - i.e. a call from outside the app, the update would not be in the UI thread and it ignored the call to getListView. Calling the update with runOnUiThread as above did the trick for me. Thanks!!
Try this
#Override
public void onResume() {
super.onResume();
items.clear();
items = dbHelper.getItems(); //reload the items from database
adapter = new ItemAdapter(getActivity(), items);//reload the items from database
adapter.notifyDataSetChanged();
}
adpter.notifyDataSetInvalidated();
Try this in onPause() method of Activity class.
If your list is contained in the Adapter itself, calling the function that updates the list should also call notifyDataSetChanged().
Running this function from the UI Thread did the trick for me:
The refresh() function inside the Adapter
public void refresh(){
//manipulate list
notifyDataSetChanged();
}
Then in turn run this function from the UI Thread
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
adapter.refresh()
}
});
Try like this:
this.notifyDataSetChanged();
instead of:
adapter.notifyDataSetChanged();
You have to notifyDataSetChanged() to the ListView not to the adapter class.
adapter.setNotifyDataChanged()
should do the trick.
I have a list item which contains a CheckBox, and I want to be able to click on the CheckBox and on the list item itself. Unfortunately, there seems to be some sort of conflict between the two, as I can only click on the item when I comment out the CheckBox. It seems like I recall there was a way to fix this, but I can't find it at the moment. Thanks
EDIT: This is with a ListFragment, so there's no need to call setOnItemClickListener.
OK, here's the XML for the list item. The problem is the CheckBox, but I figured might as well copy everything.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/list_item_survey"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="#style/SimpleListItem">
<TextView
android:id="#+id/survey_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="#style/ListItemTitle" />
<TextView
android:id="#+id/survey_date"
android:layout_below="#id/survey_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="#style/ListItemSubtitle" />
<TextView
android:id="#+id/survey_completed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#id/survey_title"
android:textColor="#color/accent_1"
android:text="#string/survey_completed"
style="#style/ListItemSubtitle" />
<CheckBox
android:id="#+id/survey_did_not_attend"
android:layout_below="#id/survey_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/survey_did_not_attend"
android:focusable="false"
style="#style/ListItemSubtitle" />
</RelativeLayout>
You need to add this to your custom adapter xml file android:descendantFocusability="blocksDescendants"
insert this into the root element of the item row xml file
android:descendantFocusability="blocksDescendants"
As described here and here, this is either a known problem or works as designed. If you have any clickable or focusable items in a list item, the list item itself cannot be clickable. Romain Guy says "This is working as intended to support trackball/dpad navigation."
This did the work for me
<CheckBox
...
android:focusable="false"
android:clickable="false"
android:focusableInTouchMode="false" />
I solved the problem this way. I implemented OnClickListener inside the Adapter and not in the Fragment/Activity and it works well. Now I can use ListView with checkboxes and can click on both. Here is my code:
public class MyFragment extends Fragment
{
...
private void setView()
{
ListView listView = (ListView) mRootView.findViewById(R.id.listview);
mItems = DatabaseManager.getManager().getItems();
// create adapter
if(listView.getAdapter()==null)
{
MyAdapter adapter = new MyAdapter(this, mItems);
try
{
listView.setAdapter(adapter);
}
catch(Exception e)
{
e.printStackTrace();
return;
}
}
else
{
try
{
((MyAdapter) listView.getAdapter()).refill(mItems);
BaseAdapter adapter = (BaseAdapter) listView.getAdapter();
listView.requestLayout();
adapter.notifyDataSetChanged();
}
catch(Exception e)
{
e.printStackTrace();
return;
}
}
// handle listview item click
listView.setClickable(true);
// listView.setOnItemClickListener(...); // this method does not work in our case, so we can handle that in adapter
}
...
}
public class MyAdapter extends BaseAdapter
{
...
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
View view = convertView;
if (view == null)
{
LayoutInflater inflater = (LayoutInflater) mFragment.getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.listview_item, null);
}
...
// handle listview item click
// this method works pretty well also with checkboxes
view.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
// do something here
// for communication with Fragment/Activity, you can use your own listener
}
});
return view;
}
...
}
Have you tried setting
android:focusable="false"
android:focusableInTouchMode="false"
?
It worked for me.
by using
android:descendantFocusability="blocksDescendants"
its working fine
ok.. Make a CheckBox instance Like
CheckBox check;
check = (CheckBox) myView.findViewById(R.id.check);
check.setOnClickListener(new CheckBoxSelect(position));
put above code in onItemClickListener or in Adapter you are using. now make a class like
below
private class CheckBoxSelect implements OnClickListener
{
int pos;
String str;
public CheckBoxSelect(int position)
{
pos = position;
}
public void onClick(View v)
{
}
}
perform any functionality in onClick .
Late, but nevertheless a solution for all those who still need it.
It is true that the built-in mechanism using:
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
getActivity(),
android.R.layout.simple_list_item_multiple_choice, lst);
does not allow both, ie click on the checkbox AND click on the list item. Wherever one clicks, the checkbox catches the event.
However, if you create your own ArrayAdapter with getView like this, then it works fine:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.list_item_ecu_fehler, null);
}
v.setFocusable(true);
v.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (DEBUG)
Log.i(this.getClass().getSimpleName(),
" ->>"
+ Thread.currentThread().getStackTrace()[2]
.getMethodName());
}
});
CheckBox selectedForClearingCB = (CheckBox) v
.findViewById(R.id.checkBox);
if (selectedForClearingCB != null) {
selectedForClearingCB.setTag(position); //so we know position in the list selectedForClearingCB.setChecked(true);
selectedForClearingCB.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (((CheckBox) v).isChecked()) {
if (DEBUG)
Log.i(this.getClass().getSimpleName(),
" -> CB checked: "
+ Integer.toString((Integer) v
.getTag()));
}
}
});
}
}
return v;
}
}