My code involves showing data retrieved from a parse backend using a parsequeryadapter. Based on the text retrieved, my code displays some images in the listview which are basically buttons with custom backgrounds and some text.
The problem is that the onListItemClick method does not seem to be called at all. (It might work if it is called)
Construct of code is like so:
NavActivity contains a fragment which contains a child listfragment defined in the XML.
This is the getItemView method in my ParseQueryAdapter
#Override
public View getItemView(ParseObject object, View v, ViewGroup parent) {
if (v == null) {
v = View.inflate(context, R.layout.post_item, null);
}
super.getItemView(object, v, parent);
//find the elements here and set the value from the ParseObject returned
TextView1 = (TextView) v.findViewById(R.id.NumberTxtView);
Holder = (LinearLayout) v.findViewById(R.id.feloniesList);
if (object != null) {
Holder.removeAllViewsInLayout();
TextView1.setText(object.getString("comment"));
JSONArray jsonArray = object.getJSONArray("incident");
for (int i = 0; i < jsonArray.length(); i++) {
//Create a new button
Button button = new Button(getContext());
String btnText = null;
int resId = 0;
try {
//Get the string from the JSON Array
String item = jsonArray.getString(i);
button.setFocusable(false);
button.setText(item);
} catch (JSONException e) {
e.printStackTrace();
}
Holder.addView(button, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
}
return v;
}
ListItemClick method
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
feedObject = feedAdapter.getItem(position);
mListener.onListItemClicked(feedObject.getObjectId());
}
I read here that making other components as non focusable, will solve the problem, but it is not helping. Any help would be appreciated
I found the answer, it seems focusable is not only true for buttons / checkboxes, but also elements like HorizontalScrollViewer. I had my linearlayout in which I was adding the buttons, enclosed in a horizontalscrollviewer. After I removed said element, click functions are working fine.
Related
Hello am implementing a listView which contains the An Imageview, when the user clicks on the image the text changes to let say 1, and the colour changes to red and vice-versa but when the user scroll down or up it goes back to the original Text and original imageview colour which loaded first with the listview, I tried using
notifyDataSetChanged();
but this does not work
code for OnClicks:
holder.ImageLike.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
resultp = data.get(position);
if(holder.ImageLike.getDrawable().getConstantState().equals(context.getResources().getDrawable(R.drawable.ic_favorite_white_24dp).getConstantState())){
resultp = data.get(position);
new Like().execute();
String number = holder.likesCountTV.getText().toString();
int num = Integer.parseInt(number);
int nene = num + 1;
String str = String.valueOf(nene);
holder.likesCountTV.setText(str);
holder.ImageLike.setImageResource(R.drawable.ic__red_24dp);
}
else{
new UnLike().execute();
String number = holder.likesCountTV.getText().toString();
int num = Integer.parseInt(number);
int nene = num - 1;
String str = String.valueOf(nene);
holder.likesCountTV.setText(str);
holder.ImageLike.setImageResource(R.drawable.ic_favorite_white_24dp);
}
}
ListView recycles the items in the list. Only the visible elements are retained.
You need to load the items in your Adapter when "getView(...)" is called
Something like:
#Override
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
view = inflater.inflate(listItemLayout, null);
}
populateView(getItem(position), view);
return view;
}
Hope this helps.
Besides updating the TextView, update also your dataset inside the onClick method.
So instead of only: holder.likesCountTV.setText(str); you also do:
holder.likesCountTV.setText(str);
resulp.something(str);
You don't and you shouldn't call notifyDataSetChanged() unless your whole dataset is changed.
I've a problem with my simple application. It uses a listview that has to:
- open a new Activity when pressed and it's on view mode
- highlight the selected item when it's on edit mode
I'm doing the following:
ListView lv = (ListView)findViewById(R.id.categoryListView);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String entry = (String) parent.getItemAtPosition(position);
if (_editMode)
view.setBackgroundColor(Color.parseColor("#5B5B5B"));
else
{
Intent intent = new Intent(MainActivity.this, CategoryActivity.class);
intent.putExtra("CATEGORY", entry);
startActivity(intent);
}
}
});
Then I want that when I turn to view mode, all items must be deselected, and I do this:
for (int i = 0; i < lv.getAdapter().getCount(); i++)
{
lv.getChildAt(i).setBackgroundColor(Color.parseColor("#FFFFFF"));
}
But this is working fine only if all the items in listview are visible.
I've tried implementing this on the adapter without success...
Any suggestion?
Thanks!
EDIT
Ok after Jawad answer I just figured out how does "getView" method work. So this is the solution I've used:
I declared an arraylist containing selected items:
ArrayList<String> itemSelected = new ArrayList<String>();
This is the ListView onItemClick listener (where you can select and deselect items):
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String entry = (String) parent.getItemAtPosition(position);
if (itemSelected.contains(entry))
{
itemSelected.remove(entry);
}
else
{
itemSelected.add(entry);
}
((ArrayAdapter<String>)lv.getAdapter()).notifyDataSetChanged();
}
});
This is the ovverride of getView method:
itmList.setAdapter(new ArrayAdapter<String>(this,R.layout.list_black_text,R.id.list_content, itmStrList){
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
if (convertView != null)
{
if (itemSelected.contains(itmList.getAdapter().getItem(position))) {
convertView.setBackgroundColor(Color.RED);
} else {
convertView.setBackgroundColor(Color.parseColor("#5B5B5B"));
}
}
return super.getView(position, convertView, parent);
}
});
And this is how to deselect all items:
itemSelected.clear();
((ArrayAdapter<String>)lv.getAdapter()).notifyDataSetChanged();
Thank you man :)
I think your problem is your are not paying attention to view recycling. When you are changing the color of a view's background, the view can be recycled and you will have something not desired. Check this link for details.
You should have a, lets say boolean variable, in your underlyning data called something like isSelected. And add this code in your getView() method.
if(item.isSelected()){
setBackgroundColor(Color.parseColor("#5B5B5B"));
}
else{
setBackgroundColor(Color.parseColor("#FFFFFF"));
}
Then in your onItemClick add replace view.setback... by
lv.getAdapter().getItem(position).setSelected(true);
lv.getAdapter().notifyDataSetChanged();
You may need a cast.
Finally change this
for (int i = 0; i < lv.getAdapter().getCount(); i++)
{
lv.getChildAt(i).setBackgroundColor(Color.parseColor("#FFFFFF"));
}
to this:
for (int i = 0; i < lv.getAdapter().getCount(); i++)
{
lv.getAdapter().getItem(i).setSelected(false);
}
lv.getAdapter().notifyDataSetChanged();
The reason why your portion of code works only if all the items are visible is view recycling. Moreover lv.getChildAt() gives you only the views that are visible. Your code may then crash because adapter.getcount maybe bigger then the number of listview childs.
Hope it helps.
I have a Listview that gets fed questions and their corresponding choices as such:
The following constructor gets all the necessary information to feed the Listview. All string values are in Arraylists.
public BaseQuestionAdapter(Activity a, ArrayList<String> b, ArrayList<String> c, ArrayList<String> d, ArrayList<String> e) {
activity = a;
this.questionTitleArray = b;
this.choicesArray = c;
this.questionIdArray = d;
this.userIdArray = e;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
Each row will hold a single question title and a variable number of choices. Dynamically created buttons will instantiate the choices and on each question title position the buttons will start generating. Like so, the following is the getView method in the BaseAdapter:
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
vi = inflater.inflate(R.layout.question_layout, null);
LinearLayout questionContainer = (LinearLayout) vi.findViewById(R.id.question_container);
LinearLayout choicesContainer = (LinearLayout) vi.findViewById(R.id.choices_container);
ViewGroup answersContainerParent = (ViewGroup) choicesContainer.getParent();
if (answersContainerParent != null)
answersContainerParent.removeView(choicesContainer);
JSONArray choicesJSONArray = new JSONArray(choicesArray);
try {
String bhb = choicesJSONArray.get(position).toString();
jsnArray = new JSONArray(bhb);
} catch (JSONException e) {
e.printStackTrace();
}
for (int answersArrayIterator = 0; answersArrayIterator < jsnArray.length(); answersArrayIterator++) {
try {
final Button choiceButton = new Button(activity);
choiceButton.setId(buttonId);
String questionId = questionIdArray.get(position).toString();
choiceButton.setTag(questionId);
choiceButton.setTag(position);
ViewGroup layout = (ViewGroup) choiceButton.getParent();
if (layout != null)
layout.removeView(choiceButton);
choiceButton.setText(jsnArray.get(answersArrayIterator).toString());
choiceButton.setTextSize(16);
choiceButton.setBackgroundResource(R.drawable.question_button_template_style);
choiceButton.setGravity(Gravity.CENTER);
choiceButton.setWidth(270);
choiceButton.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
String choiceString = choiceButton.getText().toString();
Object questionId = choiceButton.getTag();
setDataToBeSent(userId, questionId, choiceString);
Integer index = (Integer) v.getTag();
System.out.println("SATURN ASCENDS: " + index);
choicesArray.remove(index);
notifyDataSetChanged();
new HttpAsyncTask2().execute();
return false;
}
});
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(10, 10, 10, 10);
choiceButton.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
choiceButton.setLayoutParams(params);
buttonId++;
choicesContainer.addView(choiceButton);
} catch (JSONException e) {
e.printStackTrace();
}
}
TextView questionTitleET = (TextView) vi.findViewById(R.id.question_title);
String questionTitle = questionTitleArray.get(position).toString();
questionTitleET.setText(questionTitle);
ViewGroup questionTitleETParent = (ViewGroup) questionTitleET.getParent();
if (questionTitleETParent != null)
questionTitleETParent.removeView(questionTitleET);
questionContainer.addView(questionTitleET);
questionContainer.addView(choicesContainer);
return vi;
}
What I'm trying to achieve is to remove the parent Listview row whenever a button is LonClicked. I'm trying to achieve this by setting an OnLongClickListener on every button created. Like so:
choiceButton.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Integer index = (Integer) v.getTag();
System.out.println("SATURN ASCENDS: " + index);
choicesArray.remove(index);
notifyDataSetChanged();
return false;
}
});
Problem is that I don't know what to reference precisely in order for that to happen. Don't know whether its the choicesArray or any of the other resources I'm receiving. Currently when I long click on a button nothing happens. Any clue as to where I'm going wrong? Thank you.
As Luksprog said on the comment, you need to remove the items from the container which is referenced in the getCount(). However I would also like to offer an improvement. Instead of using four different lists of Strings, use an Object which holds each of those string.
Eg.
public class MyClass {
public String questionTitle;
public String choice;
public String questionId;
public String userId;
}
After you have this class you can use a single list, which contains your object. This way you won't be confused as to which list items should be removed in order for the list to change.
I have a ListView backed by SimpleCursorAdapter and custom ViewBinder. I want to make items in this listview change their color on clicking. If I do that in the OnClickListener - it works paritally, changing the color of the item clicked, and of the items down the list, each 7th (I guess, the period depends on on the viewable area of the listview).
Can anyone suggest how to deal with this? Or, maybe point to a more elegant way of making items in the listView selectable?
Thank you.
UPD: (sorry for bad formatting - this is the first time I post a question):
Below is how I try to make an item in the ListView "selected":
private void setupListView(final ListView lv) {
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> adapterView, View view, int position, final long id) {
RelativeLayout layout = (RelativeLayout) view;
int color;
if (conditionMet) {
color = R.color.gray;
} else {
color = R.color.red;
}
for(int i = 0; i < layout.getChildCount(); i++) {
((TextView)layout.getChildAt(i)).setTextColor(getResources().getColor(color));
}
return;
}}
This is how I init the adapter:
final SimpleCursorAdapter adapter =
new SimpleCursorAdapter(
this,
itemId,
cursor,
from,
to
);
adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
final TextView textView = (TextView) view;
// do necessary conversions
return true;
}
});
listView.setAdapter(adapter);
You can use the property android:listSelector to set the theme or any drawable or color of the currently selected item in a list.
Since no other answer, and, I think, I had some troubles with the suggestion below, I post how I did it:
I store ids of the items clicked in a special map
in the listview onclick I check whether the id of the just clicked item is in the map: if yes, I remove it and make the item and its children color A, otherwise I add the id to the map and set the color to B
public void onItemClick(AdapterView<?> adapterView, View view, int position, final long id) {
Context ctx = MainActivity.this;
RelativeLayout layout = (RelativeLayout) view;
try {
int color;
if (items.containsKey(id)) {
items.remove(id);
color = R.color.gray;
tempIds.remove(id);
} else {
items.put(id, sum);
color = R.color.red;
tempIds.add(id);
}
for (int i = 0; i < layout.getChildCount(); i++) {
final TextView textView = (TextView) layout.getChildAt(i);
textView.setTextColor(getResources().getColor(color));
}
} catch (ParseException e) {
Log.e(MainActivity.class.toString(), "Exception parsing", e);
}
return;
}
}
I have a collection of items in an ArrayList. I add them to a customer adapter as follows:
this.m_adapter = new MyAdapter(this, R.layout.myitem,
itemCart.m_items);
I have a delete button for each of these items in my list, but I am not sure how to connect the delete button's onClick() with the original item in the ArrayList. Can someone please explain how to do this or point me to a tutorial where I can read up on this? Non-sarcastic/non-condescending responses are greatly appreciated.
You can call the remove() method on your ArrayList
itemCart.m_items.remove(<index of element to remove>);
this.m_adapter.notifyDataSetChanged();
And then you need to call notifyDataSetChanged(); on your adapter to update the ListView
You can get the index of the element by simply noticed that a list view is a collection of child views (the rows of the list).
You can do something like this in your code:
(inside the getView() method, for example)
row.setOnLongClickListener(new OnLongClickListener()
{
#Override
public boolean onLongClick(View view) {
remove(listView.indexOfChild(view));
return true;
}
}
That is, the solution is simply use indexOfChild(View) method to get index of child view that user (long) pressed.
Here's my solution so far:
In the getView() method I do something like this:
deleteButton.setTag(position);
It looks like getTag() returns an Object. So I converted the position int into an Integer object first. It appears to be working.
In the OnClickListener() I do the following:
items.remove(index.intValue());
So far, so good.
Following works for me:
/* Read values from resource into an array */
String[] strColorValues = getResources().getStringArray(R.array.colors);
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < strColorValues.length; i++) {
list.add(strColorValues[i]);
}
ArrayAdapter adapterColors = new ArrayAdapter(getActivity(), android.R.layout.simple_spinner_item, list);
adapterColors.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerColors.setAdapter(adapterPermissionLevels);
spinnerColors.setOnItemSelectedListener(this);
/* Remove first element from the adapter and notify dataset changed. */
String item = spinnerColors.getItemAtPosition(0).toString();
adapterColors.remove(item);
adapterColors.notifyDataSetChanged();
Here's my Code.
transfer.setItemPosition(position, items.get(position).getAddMode());
the transfer here is the instance of the main class. everytime i click the deletebutton, it then pass the position of the that item on the list in this line.
public View getView(final int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
final Context context = getContext();
LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.listviewitem_layout, null);
}
ItemEntry item = items.get(position);
if (item != null) {
TextView textViewName = (TextView) v.findViewById(R.id.textViewItemName);
ImageView imageViewDelete = (ImageView) v.findViewById(R.id.imageViewDeleteIcon);
imageViewDelete.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
transfer.showDialog(4);
transfer.setItemPosition(position, items.get(position).getAddMode());
}
});
if (textViewName != null) {
textViewName.setText(item.getItemName());
}
if(imageViewDelete != null) {
imageViewDelete.setImageResource(R.drawable.delete);
}
}
return v;
}
}
Remove by position:
mainAdapter.remove(mainAdapter.getItem(position));
Such as the last one:
mainAdapter.remove(mainAdapter.getItem(mainAdapter.getCount() - 1));
Try these codes of lines it was very helpful for me
holder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
list.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, list.size());
}
});
If you use context menu, then you can get
AdapterContextMenuInfo and this structure gives index and id of clicked element.
It seems that you can get the index (or position) of a clicked item in the ListView as follows:
listview.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
listview.remove(listview.getItem(position).toString());
}
}
So you need to listen for clicks on Views and then take the index from that.