One of my activities requires a list view with custom number pickers in each row.
I created the number picker as suggested here. When I click on the buttons, however, the counter doesn't increment or decrement at all.
The following is the code found at my Custom ListView Adapter.
public class MaterialListViewAdapter extends BaseAdapter
{
ViewHolder holder;
int counter = 0;
private ArrayList<MaterialClass> data;
public static LayoutInflater inflater = null;
public static Dialog dialog;
String materialName;
public MaterialListViewAdapter(Context applicationContext,
int materialdialogcontent, ArrayList<MaterialClass> materials)
{
this.data = materials;
inflater = (LayoutInflater)applicationContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount()
{
return data.size();
}
#Override
public Object getItem(int position)
{
return position;
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View vi = convertView;
//ViewHolder holder = new ViewHolder();
if(vi == null)
{
holder = new ViewHolder();
vi = inflater.inflate(R.layout.materialdialogcontent, null);
//Initialize Buttons and TextViews.
holder.num.setText("0");
holder.add.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
counter++;
holder.num.setText("" + counter);
}
});
holder.sub.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
counter--;
holder.sub.setText("" + counter);
}
});
//holder.pk = (NumberPicker)vi.findViewById(R.id.npMaterialAmount);
vi.setTag(holder);
}
else
{
holder = (ViewHolder)vi.getTag();
}
holder.txt.setText(data.get(position).getName());
//holder.pk.setMaxValue(20);
//holder.pk.setMinValue(0);
return vi;
}
private class ViewHolder
{
TextView txt;
Button add;
Button sub;
TextView num;
//NumberPicker pk;
}
}
When I try debugging to see what's going on, counter doesn't even initialize with '0'.
I tried initializing the counter in the getView() method, however in order to do so I need to set the counter to final, and then another error shows up saying
The final local variable counter cannot be assigned, since it is defined in an enclosing type.
Any suggestions?
Updated for additional code:
public class Material extends Activity
{
ArrayList<String> materialList;
ListView lv;
Button btnConfirm;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main_material);
lv = (ListView)findViewById(R.id.list);
btnConfirm = (Button)findViewById(R.id.btnConfirm);
materialList = new ArrayList<String>();
Intent i = getIntent();
materialList = i.getStringArrayListExtra("materialList");
if(materialList != null)
{
Toast t = Toast.makeText(getApplicationContext(), materialList.get(0).toString(), Toast.LENGTH_LONG);
t.show();
}
else
{
//FILL HERE LATER
}
ArrayList<MaterialClass> materials = new ArrayList<MaterialClass>();
for(String temp : materialList)
{
MaterialClass m = new MaterialClass();
m.setName(temp);
materials.add(m);
}
MaterialListViewAdapter adapter = new MaterialListViewAdapter(getApplicationContext(), R.layout.materialdialogcontent, materials);
lv.setAdapter(adapter);
}
}
You should implement the onItemClickListener for your listView . You are using listener in adapter class but practically those numbers are nothing but items of that listView, so that to operate on those buttons (listView's items) you've not defined onItemClickListener. So after setting adapter write
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listView, View item, int position, long id) {
// here you are getting position of clicked item
}
}
UPDATE:
I've gone through your code again and I found these:
1.you are writing this line:
MaterialListViewAdapter adapter = new MaterialListViewAdapter(getApplicationContext(), R.layout.materialdialogcontent, materials);
but I didn't see any constructor in your Adapter.
2.As you are extending BaseAdapter, you must override getCount() , getItem(int position) and getItemId(int position) method as like getView() . There you are getting issue.
Try this :
public class MaterialListViewAdapter extends BaseAdapter
{
ViewHolder holder;
int counter = 0;
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View vi = convertView;
//ViewHolder holder = new ViewHolder();
if(vi == null)
{
holder = new ViewHolder();
vi = inflater.inflate(R.layout.materialdialogcontent, null);
//Initialize Buttons and TextViews.
//holder.pk = (NumberPicker)vi.findViewById(R.id.npMaterialAmount);
vi.setTag(holder);
}
else
{
holder = (ViewHolder)vi.getTag();
}
holder.txt.setText(data.get(position).getName());
//holder.pk.setMaxValue(20);
//holder.pk.setMinValue(0);
holder.add.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
counter++;
holder.num.setText("" + counter);
}
});
holder.sub.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
counter--;
holder.num.setText("" + counter);
}
});
return vi;
}
private class ViewHolder
{
TextView txt;
Button add;
Button sub;
TextView num;
//NumberPicker pk;
}
}
Related
I have created a ListView for My Model class and displayed it successfully.
I have successfully done removing value/raw from my ListView onItemClickListener of ListView.
It's Ok, But, my ListView also contains an ImageView and I have to delete a row on click of that ImageView.
So, I have taken a BaseAdapter and handle click of my that ImageView inside my BaseAdapter as below :
My Adapter class is as below :
public class MyAdapter extends BaseAdapter {
private ArrayList<ModelClass> mArrayListModel;
private LayoutInflater mInflator;
private Context mContext;
public MyAdapter(Context mContext, ArrayList<ModelClass> mArrayListModel) {
this.mContext = mContext;
this.mArrayListModel = mArrayListModel;
}
#Override
public int getCount() {
return mArrayListModel.size();
}
#Override
public Object getItem(int position) {
return mArrayListModel.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder view = null;
if (convertView == null) {
view = new ViewHolder();
mInflator = LayoutInflater.from(mContext);
convertView = mInflator.inflate(R.layout.custom_layout, parent, false);
view.textName = (TextView) convertView.findViewById(R.id.txtName);
view.textAddress = (TextView) convertView.findViewById(R.id.txtAddress);
// view.btnShow = (Button) convertView.findViewById(R.id.btnShow);
view.imgDelete=(ImageView) convertView.findViewById(R.id.imgDelete);
view.textName.setText("" + mArrayListModel.get(position).getStrName());
view.textAddress.setText("" + mArrayListModel.get(position).getStrAddress());
convertView.setTag(view);
view.imgDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext, ""+mArrayListModel.get(position).getStrName(), Toast.LENGTH_SHORT).show();
mArrayListModel.remove(position);
notifyDataSetChanged();
}
});
} else {
view = (ViewHolder) convertView.getTag();
}
return convertView;
}
class ViewHolder {
TextView textName, textAddress;
//Button btnShow;
ImageView imgDelete;
}
}
I am deleting as below :
view.imgDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext, ""+mArrayListModel.get(position).getStrName(), Toast.LENGTH_SHORT).show();
mArrayListModel.remove(position);
notifyDataSetChanged();
}
});
The Problem is with deleting item, When I click on ImageView it deletes only last value.. last position from listview. I think its issue with my position.
Will you pls. check it and let me know what might be the issue ?
Thanks.
I am learning about getTag and setTag. I need explanation about these methods and want to know how they work.
I have made a simple CustomListView having two buttons and one textview.
Buttons are add and subtract which increment or decrements the value of counter but the problem is that only the last item value is changing. Please give me a solution as well as a good explanation
Thanks .
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_items, null);
add = (Button) convertView.findViewById(R.id.add);
sub = (Button) convertView.findViewById(R.id.sub);
textView = (TextView) convertView.findViewById(R.id.numberTV);
convertView.setTag(new ViewHolder(add, sub, textView , count));
}
holder = (ViewHolder) convertView.getTag();
textView = holder.textView;
count = holder.counter;
add = holder.add;
sub = holder.sub;
add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
count +=1;
textView.setText(String.valueOf(count));
}
});
sub.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
count -=1;
textView.setText(String.valueOf(count));
}
});
return convertView;
}
}
class ViewHolder {
Button add, sub;
TextView textView;
int counter = 0;
public ViewHolder(Button add, Button sub, TextView textView , int counter) {
this.add = add;
this.sub = sub;
this.counter = counter;
this.textView = textView;
}
}
In your custom listview adapter what you are trying to implement is recycling of the single item (list_items) showed in the Listview. and because of which you require to use the getTag and setTag methods to that View.
So why do you require these method in the first place...
You are trying to recycle the list_items and view's inside it, to do that you are making the ViewHolder which will hold the inner references of views inside the list_items.
You don't want to call inflater and referencing on Views every-time getView is called so you save the ViewHolder's instance to the View, which will be used again without re-inflating the list_items and references inside it.
By setTag() you can attach as Object to the View
By getTag() you can get back the Object attached to the View
So this way you are recycling the same initialization of your list_items every time getView() is called
Seems like a lot of work, Use RecyclerView.
your solution for the code... you may check the code on gitHub
public class ListViewTestFiveActivity extends AppCompatActivity{
private ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view_test_five);
initializeUI();
}
private void initializeUI() {
listView = (ListView)findViewById(R.id.ListViewTestFiveActivity_listView);
ArrayList<Item> items = new ArrayList<>();
for (int i = 0; i < 15; i++) {
Item item = new Item();
item.setCount(i);
items.add(item);
}
MyAdapter adapter = new MyAdapter(getApplicationContext(), R.layout.single_item_listview_five, items);
listView.setAdapter(adapter);
}
private class MyAdapter extends ArrayAdapter{
private ArrayList<Item> items;
private Context a_context;
private LayoutInflater a_layoutInflater;
public MyAdapter(Context context, int resource, ArrayList<Item> items) {
super(context, resource, items);
this.a_context = context;
this.items = items;
a_layoutInflater = LayoutInflater.from(this.a_context);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ViewHolder holder = null;
if (row == null) {
row = a_layoutInflater.inflate(R.layout.single_item_listview_five, parent, false);
holder = new ViewHolder();
holder.plus = (Button) row.findViewById(R.id.ListViewTestFiveActivity_plus_button);
holder.textView = (TextView) row.findViewById(R.id.ListViewTestFiveActivity_count_textView4);
holder.minus = (Button) row.findViewById(R.id.ListViewTestFiveActivity_minus_button);
row.setTag(holder);
} else {
holder = (ViewHolder) row.getTag();
}
final Item item = items.get(position);
holder.textView.setText("" + item.getCount());
holder.plus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int increase_count =item.getCount();
item.setCount(++increase_count);
notifyDataSetChanged();
}
});
holder.minus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int decrease_count =item.getCount();
item.setCount(--decrease_count );
notifyDataSetChanged();
}
});
return row;
}
private class ViewHolder{
Button plus;
TextView textView;
TextView minus;
}
}
private class Item {
int count;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
}
Output
I have a GridView which is created via a custom GridViewAdapter which extends a BaseAdapter to create its view. Each cell in the GridView is represented by a button.
Inside of the View getView method, I use a ViewHolder to cache the button.
holder.gridPanel.setText(panel.getNumberPanel());
Then I tried to apply an OnClickListener to this button however the text of the button does not seem to change even though the Toast notification returns the correct value to set the new text of the button to.
holder.gridPanel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, panel.getAlphabetPanel(), Toast.LENGTH_SHORT).show();
holder.gridPanel.setText(panel.getAlphabetPanel());
}
});
What is the correct way of changing the text of a button which has been stored inside of a ViewHolder?
Code:
static class ViewHolder {
Button gridPanel;
}
public class GridViewAdapter extends BaseAdapter {
private Context context;
ArrayList<Panel> panelList;
Panel panel;
public GridViewAdapter(Context context, ArrayList<Panel> panelList){
this.context = context;
this.panelList = panelList;
}
#Override
public int getCount() {
return panelList.size();
}
#Override
public Object getItem(int position) {
return panelList.get(position);
}
#Override
public long getItemId(int position) {
return panelList.indexOf(getItem(position));
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.game_grid_item_layout, parent, false);
holder = new ViewHolder();
holder.gridPanel = (Button) convertView.findViewById(R.id.grid_AlphabetPanel);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
panel = panelList.get(position);
holder.gridPanel.setText(panel.getNumberPanel());
holder.gridPanel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, panel.getAlphabetPanel(), Toast.LENGTH_SHORT).show();
holder.gridPanel.setText(panel.getAlphabetPanel());
}
});
return convertView;
}
// below methods are in a different activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
ArrayList<Panel> panelList = new ArrayList<>();
ArrayList<String> alphaList = new ArrayList<>();
ArrayList<String> numberList = new ArrayList<>();
alphaList.add("A");
alphaList.add("B");
alphaList.add("C");
alphaList.add("D");
alphaList.add("E");
numberList.add(Integer.toString(1));
numberList.add(Integer.toString(2));
numberList.add(Integer.toString(3));
numberList.add(Integer.toString(4));
numberList.add(Integer.toString(5));
for(int i = 0; i < 5; i++){
String alp = alphaList.get(i);
String numb = numberList.get(i);
Panel panelObject = new Panel(alp, numb);
panelList.add(panelObject);
}
GridView panelGrid = (GridView) findViewById(R.id.gridView_Panel);
GridViewAdapter gridViewAdapter = new GridViewAdapter(this, panelList);
panelGrid.setAdapter(gridViewAdapter);
}
So I came to an answer if anyone was wondering.
Calling the setOnClickListener when the ViewHolder is being initialised works whereas doing it outside of the loop will not allow the data to be changed.
In code:
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.game_grid_item_layout, parent, false);
holder = new ViewHolder();
holder.gridPanel = (Button) convertView.findViewById(R.id.grid_AlphabetPanel);
holder.gridPanel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.gridPanel.setText(panel.getAlphabetPanel());
}
});
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
I don't know why but my onItemClickmethod is not even calling. Well, it was working fine before adding the button(add button see adapter) on each row.
Please help me to find the bug,thanks
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Init();
//People list click
chatPeoples.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.i("click", "Clicking ");
PeopleObject p = peopleObjList.get(position);
String chattingToName = p.getPersonName();
String chattingToDeviceID = p.getRegId();
Intent intent = new Intent(getActivity(), ChatActivityNew.class);
intent.putExtra("chattingFrom",MyUsername);
intent.putExtra("chattingToName", chattingToName);
intent.putExtra("chattingToDeviceID", chattingToDeviceID);
startActivity(intent);
}
});
searchIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (eSearch.getVisibility() == View.INVISIBLE) {
eSearch.setVisibility(View.VISIBLE);
}
}
});
// setMyUsername();
//getPeopleList();
}
Adapter Class
public class ChatAdapter extends BaseAdapter {
private Activity context;
private ArrayList<PeopleObject> chatPeoplesUsername;
public ChatAdapter(Activity cont, ArrayList<PeopleObject> cUsername ){
this.context = cont;
this.chatPeoplesUsername = cUsername;
}
static class ViewHolder {
protected TextView txUsername;
protected Button addFriend;
}
#Override
public int getCount() {
return chatPeoplesUsername.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
convertView = inflator.inflate(R.layout.chat_people_row, null);
viewHolder = new ViewHolder();
viewHolder.txUsername = (TextView) convertView
.findViewById(R.id.person_username);
viewHolder.addFriend = (Button)convertView.findViewById(R.id.btn_add_friend);
viewHolder.addFriend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "hm ..", Toast.LENGTH_SHORT).show();
}
});
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
if (chatPeoplesUsername != null) {
PeopleObject h = chatPeoplesUsername.get(position);
viewHolder.txUsername.setText(h.getPersonName());
}
return convertView;
}
}
You have added button on you every listItem right?
then just put this line in you button's xml file and all will work fine
android:focusable="false"
so button's xml should be like this
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false" />
Reason behind this is button will take focus of all things when you click on listItem so there method will be called not list's click.
Move your click listner to getView() method
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("click", "Clicking ");
//remaining code
}
});
You can not use clickable components like button and OnClickListener together.in such case your OnClickListener wont get called.
Firstly, sorry for my english, I am french.
So, I have a CustomArrayAdapter (ReservationAdapter), and I would remove an item from this class. I have tried many things, but they didn't work.
public class ReservationAdapter extends ArrayAdapter<Reservation> {
public ReservationAdapter(Context context, ArrayList<Reservation> reservations) {
super(context, 0, reservations);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
Reservation reservation = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
ReservationHolder holder;
if (convertView == null) {
holder = new ReservationHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.reservation_fragment, parent, false);
holder.date = (EditText) convertView.findViewById(R.id.dateReserv);
holder.imgDelete = (ImageButton) convertView.findViewById(R.id.less);
convertView.setTag(holder);
} else {
holder = (ReservationHolder) convertView.getTag();
}
// Populate the data into the template view using the data object
holder.date.setText(reservation.date);
holder.imgDelete.setOnClickListener(deleteReservListener);
// Return the completed view to render on screen
return convertView;
}
private View.OnClickListener deleteReservListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
//Where I try to remove an item
notifyDataSetChanged();
}
};
public static class ReservationHolder {
private EditText date;
private ImageButton imgDelete;
}
You have to remove the item from reservations and then call notifyDataChanged().
Before of all you have to implement a OnItemClickListener on your ListView (outside of your adapter, of course):
AdapterView.OnItemClickListener itemCLickListener = new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
reservations.remove(i);
((ReservationAdapter)listView.getAdapter()).notifyDataChanged();
}
}
e voilĂ
It works, merci !
Meanwhile, I'm still looking for a solution, and have find this :
holder.date.setText(reservation.date);
holder.imgDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
remove(reservation);
notifyDataSetChanged();
}
});
I just put the OnClickListener into the GetView method.
Thanks again ! :)
Add position vatiable in your ReservationHolder, and also construcror as:
public ReservationHolder(int position)
{
this.position = position;
}
public int getCurrentPosition()
{
return position;
}
and in getView(): ReservationHolder holder = new ReservationHolder(position);
Change your method:
private View.OnClickListener deleteReservListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
//Where I try to remove an item
notifyDataSetChanged();
}
};
to:
private View.OnClickListener deleteReservListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
//Where I try to remove an item
ReservationHolder holder = (ReservationHolder)v.getTag();
reservations.remove(holder.getCurrentPosition());
notifyDataSetChanged();
}
};