I have a ListView dynamically inflated with custom layout that has different text views and a button. On button click, a user specifies options in a dialog window and the data returned to the selected item in the list view.
I expect the data to get inserted in text views of the corresponding item in the list view. However, when the list has fewer item that are not scrollable, no data gets inserted at all when dialog is closed and when it has enough items to be scrollable, the data gets inserted into text views of wrong item in the list. I don't know what I am doing wrong, here is my code:
public double COST_EM = 0.00, COST = 0.00, NUM_CO = 0.00;
private Spinner mPSpinner, mMediSpinner;
private ArrayAdapter<String> pmedi, numCo;
private TextView mPTv, mCoTv, mSubMain, mSubTv;
#Override
public View getView(final int position, View convertView,
ViewGroup parent) {
View view = null;
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.item_custom_layout, parent, false);
// Display image in the ImageView widget
TempP tphoto = tempPList.get(position);
mPTv = (TextView) view.findViewById(R.id.p_tv_po);
mCoTv = (TextView) view.findViewById(R.id.co_tv_po);
mSubMain = (TextView) view.findViewById(R.id.sub_list);
mModify = (Button) view.findViewById(R.id.modify_btn_po);
mModify.setOnClickListener(new View.OnClickListener() {
// calculate the order cost
protected void calculateCost() {
mSub = ((COST_EM + COST) * NUM_CO);
mSubtv.setText("" + Double.toString(mSub));
}
#Override
public void onClick(View v) {
mDialog = new Dialog(PCustom.this);
mDialog.setContentView(R.layout.item_custom_dialog);
mDialog.setTitle("Modify specifications");
mPSpinner = (Spinner) mDialog.findViewById(R.id.ces_sp_dialog);
mSubTv = (TextView) mDialog.findViewById(R.id.sub_der_dialog);
// set spinner adapters (code truncated for brevity)
pmedi = new ArrayAdapter<String>(MyApplication
.getContext(), R.layout.spinner_style, pmedi);
mPSpinner.setAdapter(pmedi);
mPSpinner
.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> arg0,
View arg1, int pos, long arg3) {
if (mPSpinner.getSelectedItem() == "Glossy") {
COST = 2000.00;
} else if (mPSpinner
.getSelectedItem() == "Standard") {
COST = 1500.00;
} else if (mPSpinner
.getSelectedItem() == "Other") {
COST = 1000.00;
}
// calculate the cost
calculateCost();
}
public void onNothingSelected(
AdapterView<?> arg0) {
}
});
Button save = (Button) mDialog
.findViewById(R.id.save_btn_po_dialog);
Button cancel = (Button) mDialog
.findViewById(R.id.cancel_btn_po_dialog);
save.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// String newnumber =
// mobileNumber.getText().toString();
mPTv.setText("" + mPSpinner
.getSelectedItem());
mCoTv.setText((String) mNCoSpinner
.getSelectedItem());
mSubMain.setText(Double.toString(mSub));
mDialog.dismiss();
}
});
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mDialog.dismiss();
}
});
mDialog.show();
}
});
return view;
}
The method getView() return one item View each time ListView call it with a specific "position" parameter, so the times it is called is no less than the number of items it has. So, your member variables mPTv, mCoTv and mSubMain will be reassigned many times and finally have their values in the final calling of getView().That's why you meet that problem.
To solve your problem, you need to have the correct TextViews when the "save Button" is clicked.Here is how to find those correct TextViews:
In the OnClickListener of mModify Button, the "v" parameter in the method onClick(View v) is the same instance of mModify itself. So, you can use it to find those correct TextViews. Perhaps you can set the item root View as its tag and get the root View in onClick(View v) and then use it to find all those correct TextViews. Here is how to change your code:
mModify = (Button) view.findViewById(R.id.modify_btn_po);
// set the root view as the tag of "modify button".
mModify.setTag(view);
mModify.setOnClickListener(new View.OnClickListener() {
// calculate the order cost
protected void calculateCost() {
mSub = ((COST_EM + COST) * NUM_CO);
mSubtv.setText("" + Double.toString(mSub));
}
#Override
public void onClick(View v) {
// retrieve the root view here, it's the root view of the item on which you
// clicked the "modify button".
View view = (View)v.getTag();
// find the correct TextViews here.
mPTv = (TextView) view.findViewById(R.id.p_tv_po);
mCoTv = (TextView) view.findViewById(R.id.co_tv_po);
mSubMain = (TextView) view.findViewById(R.id.sub_list);
BTW, you didn't optimize your ListView, so it may not scroll smoothly, but this is not what caused your problem.You can refer to this:
How to optimize Android ListView?
Related
The View for a ListView two buttons (for example to perform: call, send SMS). I want to set up a listeners for clicks on the buttons. It is my understanding that if I set up a OnItemSelectedListener, I won't know which of the two buttons was clicked.
When I set up listeners for a button, when I click on it, I get the listener of the corresponding button that is in the last item in the list (not the one I clicked on) (which makes sense programmatically) but this is not what I want. I can tell because it always calls the number that belongs to the last item in the list.
Any tips on how set up OnClick for multiple views in each item ?
#NonNull
#Override
public View getView(final int position, #Nullable final View convertView, #NonNull ViewGroup parent) {
LayoutInflater inf = ((Activity)context).getLayoutInflater();
View view = inf.inflate(R.layout.place , parent , false);
name = view.findViewById(R.id.name);
type = view.findViewById(R.id.type);
minAge = view.findViewById(R.id.minAge);
open = view.findViewById(R.id.open);
close = view.findViewById(R.id.close);
distance = view.findViewById(R.id.distance);
phone = view.findViewById(R.id.phone);
picture = view.findViewById(R.id.picture);
btnCall = view.findViewById(R.id.btnCall);
final Place place = placeList.get(position);
// btnCall.setOnClickListener(this);
// I tried both setups with the same result.
// the button is always the one belonging to the last item in the list.
btnCall.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String s = btnPhone.getText().toString();
}
});
// another button would have its own OnClick
name.setText(place.getName());
type.setText(place.getType());
minAge.setText(Integer.toString(place.getMinAge()));
open.setText(Integer.toString(place.getOpen()));
close.setText(Integer.toString(place.getClose()));
distance.setText(Integer.toString(place.getDistance()));
phone.setText(place.getPhone());
int id = context.getResources().getIdentifier("place"+position,"drawable" ,
((Activity)context).getPackageName());
//row_pic.setImageResource(id);
return view;
}
#Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + phone.getText()));
if (intent.resolveActivity(context.getPackageManager()) != null) {
context.startActivity(intent);
}
if (intent.resolveActivity(context.getPackageManager()) != null)
{
context.startActivity(intent);
}
}
I found the solution just after posting the question.
USE TAGS to pass data.
'''
phone.setText(place.getPhone());
btnCall.setTag(phone.getText().toString());
btnCall.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String s = (String) ((Button) view).getTag().toString();
// now I can call the correct number
}
});
'''
I am trying to convert my app to android version, and I am a bit new in android. I have a list view in which the items include buttons. It is a user list and you can follow each user, when the button is clicked, only in the item including the button, the button text should turn in to "followed". Retrieving the list works fine, but with my below code the button text is not changing. How can I make this happen? Thank you very much.
private class MyListAdapter extends ArrayAdapter<String> {
public MyListAdapter() {
super(getActivity().getApplicationContext(), R.layout.fragment_users_cell, myItemList);
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View cellView = convertView;
if (cellView == null){
cellView = getActivity().getLayoutInflater().inflate(R.layout.fragment_users_cell, parent, false);
}
profileBtn = (Button) cellView.findViewById(R.id.fragment_users_cell_profileBtn);
followBtn = (Button) cellView.findViewById(R.id.fragment_users_cell_followBtn);
profileBtn.setText(myItemList.get(position));
profileBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println(myItemList.get(position));
System.out.println(position);
}
});
followBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println(myItemList.get(position));
profileBtn.setText("followed");
}
});
return cellView;
}
}
You have to update your dataset and refersh the list after you make changes so that it reflects the latest changes. In your case the text changes.
followBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
profileBtn.setText("followed");
myItemList.add(position, "followed");//Change your dataset
notifyDataSetChanged(); //And refresh the adapter
}
});
you need to change the value in myItemList so that next time when view load, the value from list set as text on profile button comes which ix followed
i.e. you need to update the list on click of follow button and notify the ListView.
followBtn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
System.out.println(myItemList.get(position));
myItemList.get(position).set("followed");
profileBtn.setText("followed");
}
});
I have an ArrayAdapter which shows some posts using a fragment. In this fragment I have some buttons. So all of the posts shown have these buttons.
The problem is, when I click a button of a post to setText to a field of this post; instead of changing text of post that I clicked, it changes text of newly scrolled item.
For example if I scroll down the ListView a new item comes. Then regardless of which post I clicked it changes text of this new post.
How can I prevent this to happen? I take current post using
getItem(position)
By scroolling I mean new element of the list are loaded and shown.
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.comment_small,parent,false);
TextView tvOwner = (TextView) v.findViewById(R.id.tvCommentSmallOwner);
TextView tvCreationDate = (TextView) v.findViewById(R.id.tvCommentSmallCreationDate);
TextView tvCreationDateValue = (TextView) v.findViewById(R.id.tvCommentSmallCreationDate);
TextView tvContent = (TextView) v.findViewById(R.id.tvCommentSmallContent);
tvVoteCount = (TextView) v.findViewById(R.id.tvCommentVoteCount);
c = getItem(position);
tvOwner.setText(context.getResources().getString(R.string.generic_by) + " " + c.getOwnerId());
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
String s =c.getPostDate();
System.out.println(s);
tvCreationDateValue.setText(s);
tvContent.setText(c.getContent());
btnDownVote = (ImageButton) v.findViewById(R.id.btnCommentDownVote);
btnUpVote = (ImageButton) v.findViewById(R.id.btnCommentUpVote);
tvVoteCount.setText("" + c.getNetCount());
btnUpVote.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
c=getItem(position);
ServerRequests sr = new ServerRequests(getContext());
MemberLocalStore memberLocalStore = new MemberLocalStore(getContext());
Member m = memberLocalStore.getLoggedInMember();
sr.voteComment(c, true, m.getId(), new Consumer<String>() {
#Override
public void accept(String vote) {
tvVoteCount.setText("" + vote);
}
});
}
});
btnDownVote.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
c=getItem(position);
ServerRequests sr = new ServerRequests(getContext());
MemberLocalStore memberLocalStore = new MemberLocalStore(getContext());
Member m = memberLocalStore.getLoggedInMember();
sr.voteComment(c, false, m.getId(), new Consumer<String>() {
#Override
public void accept(String vote) {
tvVoteCount.setText("" + vote);
}
});
}
});
return v;
}
I want to vote (like,dislike) some posts but when I click upvote button that marked as 1, overall vote of the post that marked as 2 changes.
I have used popup listview to work like spinner .I want it to pop upwards like spinner does when its at the bottom of the screen .
I have tried :
popupWindowDogs.showAsDropDown(buttonShowDropDown,5,0);
ALSO,
popupWindowDogs.showAsDropDown(buttonShowDropDown, (int)(Math.round(buttonShowDropDown.getX())),-(totallinear_layouts+buttonShowDropDown.getHeight()));
totallinearlayouts = sum of all heights of linear layouts till the button.
This works properly on a few devices but not like Spinner. How can I make it to work like Spinner? I mean to inflate exactly as the size of the device and the list height. I really appreciate any help. Thanks in Advance.
Reference:https://www.codeofaninja.com/2013/04/show-listview-as-drop-down-android.html
MainActivity.java
public class MainActivity extends Activity {
String TAG = "MainActivity.java";
String popUpContents[];
PopupWindow popupWindowDogs;
Button buttonShowDropDown;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// initialize pop up window items list
// add items on the array dynamically
// format is DogName::DogID
List<String> dogsList = new ArrayList<String>();
dogsList.add("Akita Inu::1");
dogsList.add("Alaskan Klee Kai::2");
dogsList.add("Papillon::3");
dogsList.add("Tibetan Spaniel::4");
// convert to simple array
popUpContents = new String[dogsList.size()];
dogsList.toArray(popUpContents);
// initialize pop up window
popupWindowDogs = popupWindowDogs();
// button on click listener
View.OnClickListener handler = new View.OnClickListener() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.buttonShowDropDown:
// show the list view as dropdown
popupWindowDogs.showAsDropDown(v, -5, 0);
break;
}
}
};
// our button
buttonShowDropDown = (Button) findViewById(R.id.buttonShowDropDown);
buttonShowDropDown.setOnClickListener(handler);
}
public PopupWindow popupWindowDogs() {
// initialize a pop up window type
PopupWindow popupWindow = new PopupWindow(this);
// the drop down list is a list view
ListView listViewDogs = new ListView(this);
// set our adapter and pass our pop up window contents
listViewDogs.setAdapter(dogsAdapter(popUpContents));
// set the item click listener
listViewDogs.setOnItemClickListener(new DogsDropdownOnItemClickListener());
// some other visual settings
popupWindow.setFocusable(true);
popupWindow.setWidth(250);
popupWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
// set the list view as pop up window content
popupWindow.setContentView(listViewDogs);
return popupWindow;
}
/*
* adapter where the list values will be set
*/
private ArrayAdapter<String> dogsAdapter(String dogsArray[]) {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, dogsArray) {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// setting the ID and text for every items in the list
String item = getItem(position);
String[] itemArr = item.split("::");
String text = itemArr[0];
String id = itemArr[1];
// visual settings for the list item
TextView listItem = new TextView(MainActivity.this);
listItem.setText(text);
listItem.setTag(id);
listItem.setTextSize(22);
listItem.setPadding(10, 10, 10, 10);
listItem.setTextColor(Color.WHITE);
return listItem;
}
};
return adapter;
}
}
DogsDropdownOnItemClickListener.java
public class DogsDropdownOnItemClickListener implements OnItemClickListener {
String TAG = "DogsDropdownOnItemClickListener.java";
#Override
public void onItemClick(AdapterView<?> arg0, View v, int arg2, long arg3) {
// get the context and main activity to access variables
Context mContext = v.getContext();
MainActivity mainActivity = ((MainActivity) mContext);
// add some animation when a list item was clicked
Animation fadeInAnimation = AnimationUtils.loadAnimation(v.getContext(), android.R.anim.fade_in);
fadeInAnimation.setDuration(10);
v.startAnimation(fadeInAnimation);
// dismiss the pop up
mainActivity.popupWindowDogs.dismiss();
// get the text and set it as the button text
String selectedItemText = ((TextView) v).getText().toString();
mainActivity.buttonShowDropDown.setText(selectedItemText);
// get the id
String selectedItemTag = ((TextView) v).getTag().toString();
Toast.makeText(mContext, "Dog ID is: " + selectedItemTag, Toast.LENGTH_SHORT).show();
}
}
Practicing on the ListView, I thought of adding buttons as well to it, rather than showing only content. But in my implementation, the button does not do anything at all.
Plus I was confused whether I could get the position of the button clicked. For now I am just sending the toSend declared inside the OnItemClick in an intent.
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// TODO Auto-generated method stub
final int toSend = position;
TextView refId = (TextView)view.findViewById(R.id.list_id);
TextView refName = (TextView)view.findViewById(R.id.list_name);
TextView refAdd = (TextView)view.findViewById(R.id.list_address);
Button edit = (Button)view.findViewById(R.id.edit);
edit.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
// TODO Auto-generated method stub
Intent i = new Intent(ListActivity.this, EditLayout.class);
i.putExtra("position", toSend);
startActivity(i);
}
});
String sd_id = refId.getText().toString();
String sd_name = refName.getText().toString();
String sd_add = refAdd.getText().toString();
buildAlert(sd_id, sd_name, sd_add);
}
});
You're pretty close. The "inside" setOnClickListener needs to happen when you create the list row view (the view containing id, name, address, edit).
You can do that during getView(). But where to send the clicks? Instead of creating a new onClickListener, use "this" (your activity). Put an onClick() handler in the activity.
Then, when you get a click, the onClick method will execute. Next problem: how do you know which row clicked? The easiest way that comes to mind is to give the button a different id for e ach row - use the row index (you might need to start at 1 rather than 0 - be warned).
Finally, given the row id, it's easy to start your "nested" activity.
Hope this helps.
(added later)
I do it like this; you'll need to define a layout for your row view:
class MyActivity extends Activity implements View.OnClickListener
{
public void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView (R.layout.my_page);
ListView list = (ListView)findViewById (android.R.id.list);
MyArrayAdapter adapter = new MyArrayAdapter (this, <your array of data>);
list.setAdapter (adapter);
}
#Override
public void onClick(View v)
{
int buttonId = v.getId();
if (buttonId is within range)
... do what you need to do with the click ...
}
private class MyArrayAdapter extends ArrayAdapter<MyData>
{
private Activity act;
//-----------------------------------------------------------------------------
public MyArrayAdapter (Activity act, MyData array)
{
super (act, R.layout.list_row, array);
this.act = act;
}
//-----------------------------------------------------------------------------
#Override
public View getView (int position, View convertView, ViewGroup parent)
{
ViewGroup rowView = (ViewGroup)convertView;
if (rowView == null)
{
LayoutInflater inflater = act.getLayoutInflater();
rowView = (ViewGroup) inflater.inflate (R.layout.list_row,
parent, false);
}
Button button = (Button)rowView.findViewById (R.id.is_member);
button.setId (position+1); // add one to avoid 0 as an id.
button.setOnClickListener (act);
// set field values here -- not shown
return rowView;
}
}
}