Hello I have a problwm witch Listview.
I use listview for show items in list.
I have activity where is Listview. And If I longpress on row in listview open popup (dialog) where I can edit word in row.
If edit finish I Call this
AddItemInPacage.obnovitem=true;
AddItemInPacage.indexitem=poz;
AddItemInPacage.novyitem=novypacage;
Boolean is for Timer if is true Start This method
public void ZmenItem(int indexzmeny,String nove) {
ListAdapter.clear();
for (int i=1;i<prvy.getPacageItem2(indexpacage)+1;i++) {
ListAdapter.add(String.valueOf(prvy.citajItem(indexpacage,i)));
}
ListAdapter.set(indexzmeny,nove);
Toast.makeText(this, "citam "+ ListAdapter.get(indexzmeny), Toast.LENGTH_SHORT).show();
thadapter = new MyThumbnailAdapter(getApplication(), R.layout.list_row, ListAdapter);
List.setAdapter(thadapter);
thadapter.notifyDataSetChanged();
}
Everything is OK when I while I not open the same row. If edited row for some times in row Program not work good.
Everything is good while this line List.setAdapter(thadapter); after thise line is Variables good too, but listview in display not rewrite.
Why?
I have three times this List.setAdapter(thadapter); on program but on OnCreate method and when Put new row in listview... So when Edited row I call only thise method ↑↑ which sometimes rewrite good and sometimes not.
Because Thise program isn't it 100% good :(
ListView List;
MyThumbnailAdapter thadapter = null;
ArrayList<String> ListAdapter = new ArrayList<String>();
This is my Adapter
public class MyThumbnailAdapter extends ArrayAdapter<String> {
ArrayList<String> arr;
private TextView text;
public MyThumbnailAdapter(Context context, int textViewResourceId, ArrayList<String> objects) {
super(context, textViewResourceId, objects);
this.arr = objects;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = null;
LayoutInflater inflater = getLayoutInflater();
view = inflater.inflate(R.layout.list_row, parent, false);
TextView textnumber = (TextView) view.findViewById(R.id.text);
ImageView delButton = (ImageView) view.findViewById(R.id.btn_del);
Typeface robtoLight = Typeface.createFromAsset(getContext().getAssets(), "fonts/Roboto-Light.ttf");
textnumber.setTypeface(robtoLight);
delButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
arr.remove(position);
thadapter.notifyDataSetChanged();
Toast.makeText(getContext(), "Item deleted", Toast.LENGTH_SHORT).show();
}
});
textnumber.setText(arr.get(position));
textnumber.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
for (int i=ListAdapter.size()-1;i>=0;i--) {
// for (int i = 0; i < ListAdapter.size() ; i++) {
try {
prvy.pridajItemRemove(ListAdapter.get(i), indexpacage, i+1);
} catch(IndexOutOfBoundsException e) {
prvy.Nulak(indexpacage,i);
}
}
prvy.setPacageItem2(ListAdapter.size(),indexpacage);
prvy.setPocItem(ListAdapter.size());
for (int i=ListAdapter.size();i<99;i++) {
prvy.Nulak(indexpacage,i+1);
}
Serializuj(prvy,nazovtripu);
EditItemDialog cdd=new EditItemDialog(AddItemInPacage.this,nazovtripu,position,indexpacage);
cdd.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
cdd.show();
return true;
}
});
return view;
}
}
I put picture
Sometimes if I edit row Toas read good string, but Listview no rewrite.
This may help you
ListAdapter.notifyDataSetChanged()
Hoping ListAdapter is name of your adapter
I need synchronized confirm edit in Dialog with medhod which rewrite Listview.
Or switch sequence from
AddItemInPacage.obnovitem=true;
AddItemInPacage.indexitem=poz;
AddItemInPacage.novyitem=novypacage;
to
AddItemInPacage.indexitem=poz;
AddItemInPacage.novyitem=novypacage;
AddItemInPacage.obnovitem=true;
Because If AddItemInPacage.obnovitem=true; first Activity work with old information in variable novypacage. And when variable novypacage is full from dialog. Listview finish work with old information in this variable.
Related
I am developing an app which has a text message interface (something like Facebook Messenger, Whatsapp, etc). I want to be able to change the background color of all the chat bubbles (a ListView of TextViews) sent by the user when they pick a new color (in a NavigationView).
However, with the current code that I have, I only am able to change the color after the EditText used to compose the message is clicked again. Or I am able to only edit the first bubble sent, but as soon as the color is changed.
Here's what I tried :
ItemColor1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
Toast.makeText(activity, "Couleur mise à jour", Toast.LENGTH_SHORT).show();
currentTheme = position;
SharedPreferences.Editor editor = pref.edit();
editor.putInt("indexColorSelected",currentTheme);
editor.apply();
chatAdapter.notifyDataSetChanged();
//the following changes only the first message sent
for(int i=0; i<chatAdapter.getCount(); i++){
ChatData message = chatMessageList.get(position);
TextView msg = activity.findViewById(R.id.text);
msg.setText(message.body);
msg.setBackgroundResource(R.drawable.user_color1);
}
}
});
ChatData is a custom Class that I created which looks like this :
public class ChatAdapter extends BaseAdapter {
private static LayoutInflater inflater = null;
private ArrayList<ChatData> chatMessageList;
private Context mContext;
ChatAdapter(Activity activity, ArrayList<ChatData> list) {
mContext = activity;
chatMessageList = list;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
...
}
Color drawable:
<corners
android:bottomRightRadius="5dp"
android:radius="40dp"/>
<gradient
android:angle="45"
android:endColor="#01f1fa"
android:startColor="#0189ff"
android:type="linear" />
</shape>
getView() method of the Adapter:
public View getView(int position, View convertView, ViewGroup parent) {
ChatData message = chatMessageList.get(position);
View vi = convertView;
if (convertView == null)
vi = inflater.inflate(R.layout.msglist, parent, false);
TextView msg = vi.findViewById(R.id.text);
msg.setText(message.body);
LinearLayout layout = vi.findViewById(R.id.message_layout);
LinearLayout parent_layout = vi.findViewById(R.id.message_layout_parent);
inflater = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// if message is mine then align to right
if (message.isMine) {
layout.setGravity(Gravity.RIGHT);
int couleurBubble = getCouleurSelectionnee();
switch(couleurBubble){
case R.color.c1: msg.setBackgroundResource(R.drawable.user_color1); break;
case R.color.c2: msg.setBackgroundResource(R.drawable.user_color2); break;
case R.color.c3: msg.setBackgroundResource(R.drawable.user_color3); break;
case R.color.c4: msg.setBackgroundResource(R.drawable.user_color4); break;
case R.color.c5: msg.setBackgroundResource(R.drawable.user_color5); break;
case R.color.c6: msg.setBackgroundResource(R.drawable.user_color6); break;
case R.color.c7: msg.setBackgroundResource(R.drawable.user_color7); break;
case R.color.c8: msg.setBackgroundResource(R.drawable.user_color8); break;
default: break;
}
parent_layout.setGravity(Gravity.RIGHT);
}
// If not mine then align to left
else {
layout.setGravity(Gravity.LEFT);
msg.setBackgroundResource(R.drawable.bot_chat);
parent_layout.setGravity(Gravity.LEFT);
}
return vi;
}
I don't really know where to go from here so any kind of help would be appreciated. If you want me to provide more code, let me know and I will.
Thank you.
I'm sharing how I would do it. Maybe, this can help you.
There's some strange issue because you are calling notifyDataSetChanged(). This would be enough to re-draw all message bubbles.
My ideia is:
Add a int variable to the adapter class (mColorResource). This variable will point to the proper drawable that should be used (like R.drawable.user_color1).
public class ChatAdapter extends BaseAdapter {
int mColorResource;
ChatAdapter(Activity activity, ArrayList<ChatData> list, int initialColorResource) {
mContext = activity;
chatMessageList = list;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// You must receive the color on the construtor
mColorResource = initialColor;
}
// Use this method to update the color (when user select a new color)
public void setColor(int newColorResource) {
mColorResource = newColorResource;
}
public View getView(int position, View convertView, ViewGroup parent) {
...
// Note how this if-else is cleaner now
if (message.isMine) {
layout.setGravity(Gravity.RIGHT);
msg.setBackgroundResource(mColorResource);
parent_layout.setGravity(Gravity.RIGHT);
} else {
layout.setGravity(Gravity.LEFT);
msg.setBackgroundResource(R.drawable.bot_chat);
parent_layout.setGravity(Gravity.LEFT);
}
...
}
}
Then, when a color is selected, find the proper drawable based on the view clicked and pass it to the adapter:
ItemColor1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
Toast.makeText(activity, "Couleur mise à jour", Toast.LENGTH_SHORT).show();
currentTheme = position;
SharedPreferences.Editor editor = pref.edit();
editor.putInt("indexColorSelected", currentTheme);
editor.apply();
// Here, you send the proper drawable...
// I'm not sure how you convert color selected to the drawable
// So, add your logic to convert the button clicked to a drawable here
// like R.drawable.user_color1
chatAdapter.setColor(R.drawable.NAME_OF_THE_COLOR);
// Request to re-draw all items from the list (all bubbles)
chatAdapter.notifyDataSetChanged();
}
});
Also, on your activity, you create the adapter with the last used color. Something like:
#Override
protected void onCreate(#Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
// Set a default color (if user is open you app for the first time)
int chatColor = R.drawable.user_color1;
// Add your logic to read the shared preference and convert that last color used to a valid drawable.
// Like chatColor = pref.getInt(indexColorSelected, R.drawable.user_color1) etc....
// Set the color in the adapter.
chatAdapter = newAdapter(this, mChatDataList, chatColor);
}
I am working on a project where I have a let's say 5x5 grid of TextViews and I want to check if an entire row or column has equal elements. I am using an Adapter class to inflate my gridview with simply one textview element. Here is the code that I have tried but I cannot seem to make it work:
final int size = gridView.getCount(); //25
int temp = 0;
for (int i = 0; i < size; i++) {
ViewGroup gridChild = (ViewGroup) gridView.getChildAt(i);
childSize = gridChild.getChildCount();
for (int j = 0; j < childSize; j++) {
if (gridChild.getChildAt(j) instanceof TextView &&
((TextView) gridChild.getChildAt(j)).getText().toString().equals("x")) {
temp++;
}
The thing is when i tried to debug, debugger showed null values for childSize variable and could not properly get the value from getChildAt. Basically, what I am trying to do is get inside the if statement. Also this is the first time I am working with ViewGroup calss, and the methods that I call. Any help would be appreciated.
Edit:I am looking for a way to do this outside the getView method in the adapter class and not in a onClick method as well. (Code sample answers would be highly appreciated). Also, the getChildAt method call returns null so the code I have shown would not work because I am assigning a null value to the gridChild.
This is the onClick that I use for the TextViews:
`
public void numberFill(View view) {
if (((TextView) view).getText().toString().isEmpty()) {
((TextView) view).setText(String.valueOf(numbCounter + 1));
numbCounter++;
}
else if (!((TextView) view).getText().toString().isEmpty() && numbCounter >= 16) {
((TextView) view).setText("x");
}
}
This is my adapter class:
public class GridAdapter extends BaseAdapter {
private final Context mContext;
private String[] numbers;
public GridAdapter(Context context, String[] numbers) {
this.mContext = context;
this.numbers = numbers;
}
#Override
public int getCount() {
return numbers.length;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public Object getItem(int position) {
return numbers[position];
//return null;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater)
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = new View(mContext);
gridView = inflater.inflate(R.layout.textview_layout, null);
TextView textView = (TextView) gridView.findViewById(R.id.cell);
textView.setText(numbers[position]);
} else {
gridView = (View) convertView;
}
return gridView;
}
}
numberFill reworked:
public void numberFill(View view) {
int index = (Integer) view.getTag();
if (numbers[index].toString().isEmpty()) {
numbers[index] = String.valueOf(numbCounter + 1);
numbCounter++;
}
else if (!numbers[index].toString().isEmpty() && numbCounter >= 25) {
numbers[index] = "x";
}
gridAdapter.notifyDataSetChanged();
}
`
When using an AdapterView – such as your GridView – you generally don't want to directly access and manipulate its child Views outside of its Adapter. Instead, the dataset backing the Adapter should be updated, and the GridView then refreshed.
In your case, you presumably have a setup similar to this in your Activity:
private GridAdapter gridAdapter;
private String[] numbers;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
numbers = new String[25];
gridAdapter = new GridAdapter(this, numbers);
}
Here, the numbers array is what you want to directly modify, rather than the text on the GridView's child TextViews. That array is then easily iterated over to do your row and column value checks.
Since the array will be modified in the Activity, we need a way to pass the clicked TextView's position in the Adapter to the Activity's click method, as we'll need it to access the correct array element. For this, we can utilize the tag property available on all View's, via the setTag() and getTag() methods. For example, in GridAdapter's getView() method:
...
TextView textView = (TextView) gridView.findViewById(R.id.cell);
textView.setText(numbers[position]);
textView.setTag(position);
...
In the click method, the position can be easily retrieved with getTag(), and used as the index to get the clicked TextView's text from the numbers array. You can then do the necessary processing or calculation with that text, set the modified value back to the array element, and trigger a refresh on the Adapter.
public void numberFill(View view) {
int index = (Integer) view.getTag();
// Do your processing with numbers[index]
numbers[index] = "new value";
gridAdapter.notifyDataSetChanged();
}
The notifyDataSetChanged() call will cause the GridView to update its children, and your new value will be set in the appropriate TextView. The numbers array now also has the current values, and is readily available in the Activity to perform the necessary checks there.
am trying to update my adapter after adding some data in it but its not updating , when i switch through other activities and come back the adapter got updated this time my code :
void updateAdapter(){
adapter.setData(getData());
adapter.notifyDataSetChanged();
Log.d("TAG"," DATA SIZE AFTER UPDATE : "+getData().size() +" items : "+adapter.getItemCount());
}
my adapter :
private void createAdapter(final RecyclerView recyclerView , final List<Information> data) {
List<Information> content = new ArrayList<>();
Log.d("TAG","createAdapter Called");
final int[] currentRowPosition = {0};
content = data;
final List<Information> finalContent = content;
adapter = new ParallaxRecyclerAdapter<Information>(finalContent) {
/// my onBindViewHolder
#Override
public void onBindViewHolderImpl(final RecyclerView.ViewHolder viewHolder, final ParallaxRecyclerAdapter<Information> adapter, final int i) {
currentRowPosition[0] = i;
if ( i <= finalContent.size() -1 ){
((ViewHolder) viewHolder).linearLayout.setVisibility(View.GONE);
final Information current = finalContent.get(i);
((ViewHolder) viewHolder).DESCRIPTION.setText(current.description);
}else {
// this is my loadMore button which stays at the last row of recyclerView
((ViewHolder) viewHolder).setIsRecyclable(false);
((ViewHolder) viewHolder).linearLayout.setVisibility(View.VISIBLE);
((ViewHolder) viewHolder).itemView.getLayoutParams().height = 100;
((ViewHolder) viewHolder).LOADMORE.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fetchNext();
}
});
}
}
//my on create View Holder
#Override
public RecyclerView.ViewHolder onCreateViewHolderImpl(ViewGroup viewGroup, final ParallaxRecyclerAdapter<Information> adapter, int i) {
return new ViewHolder(getActivity().getLayoutInflater().inflate(R.layout.custom_row, viewGroup, false));
}
#Override
public int getItemCountImpl(ParallaxRecyclerAdapter<Information> adapter) {
return finalContent.size()+1;
}
});
// adding header to recyclerView
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
View header = getActivity().getLayoutInflater().inflate(R.layout.header, recyclerView, false);
headerImageView = (ImageView) header.findViewById(R.id.headerImageView);
//setting CoverImage
adapter.setParallaxHeader(header, recyclerView);
adapter.setData(content);
recyclerView.setAdapter(adapter);
}
any idea how can i add new items with realtime updation on my RecyclerView ?? any guidance will be so helpful for me
I am assuming that when you run the Activity (which has RecyclerView) for the first time it loads everything from the adapter properly.
But when you change to other activities which would change items to your adapter and come back to your Activity which has RecyclerView in it can't get the proper updated information as adapter is not updated.
This may be because you are not refreshing your adapter when your activity resumes in onResume(), something like this. you may have to make other changes to your onResume method as required,
onResume(){
if(adapter != null){
adapter.notifyDataSetChanged();
}
}
Kindly check the lifecycle of an Activity
Example:
This does not directly addresses your issue but help you understand as you come back to activity you should refresh the adapter.
There is a NoteListActivity, with ListView in it, you may Add or edit items to the Adapter in it in NoteEditActivity and as soon as you come back you have to refresh the adapter in the activity where you have your listview
Adapter.class
public void add(List<Information> informations){
try{
finalContent.addAll(informations);
}catch(Exception e){
e.printstacktrace();
}
notifyDataSetChanged();
}
well i ended up with this :
int offset = adapter.getItemCount();
for(int l=0; l<= 4 ; l++){
Log.d("TAG","getData : "+getData().size());
if ((offset - 2) + l < getData().size()){
adapter.addItem(getData().get((offset - 2 ) + l) , adapter.getItemCount() - 2);
adapter.notifyDataSetChanged();
}
}
what i needed was adapter.addItem(item , position) and adapter.notifyDataSetChanged(); the above example is loading 5 images at a time
In my main activity I display a ListView which uses a custom BaseAdapter (ThoughtListAdapter).
listView = (ListView) findViewById(R.id.list);
adapter = new ThoughtListAdapter(this, resultingThoughts);
listView.setAdapter(adapter);
Every item in the ListView has a custom layout containing a TextView and two Button.
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.list_item_thought, null);
}
thoughtText = (TextView) convertView.findViewById(R.id.thought_text_view);
likeButton = (Button) convertView.findViewById(R.id.thought_like_button);
dislikeButton = (Button) convertView.findViewById(R.id.thought_dislike_button);
When a Button is clicked an AsyncTask (AsyncPost) is called which connects to my database and makes some changes.
likeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
System.out.println("LIKE CLICKED");
Thought t = thoughtItems.get(position);
thoughtId = t.getId();
opinion = 1;
AsyncPost asyncPost = new AsyncPost(activity,ThoughtListAdapter.this);
asyncPost.execute(SHARE_THOUGHT_URL,
TAG_PERSON_EMAIL, "m#b.it",
TAG_THOUGHT_ID, thoughtId.toString(),
TAG_OPINION, opinion.toString());
}
});
What I need is making both Button-s of a list item disappear after the AsyncTask is done with a successful outcome. I have a method onComplete(JSONObject json) which elaborates the JSONObject returned by the AsyncTask. I try to make the buttons non visible inside the onComplete method, but this doesn't work because onComplete() doesn't know which exact button has been clicked.
How can I pass an instance of the exact clicked button inside onComplete() and make disappear only the Like and Dislike buttons of the concerned list item?
AsyncPost is a global AsyncTask used by all my other activities. I would strongly prefer to leave it alone. The onComplete() method functions as the onPostExecute() method of the AsyncTask.
Here are the getView() and onComplete() methods inside my BaseAdapter, which contain all the code shown above.
Thank you.
public View getView(final int position, View convertView, ViewGroup parent) {
if (layoutInflater == null) {
layoutInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.list_item_thought, null);
}
thoughtText = (TextView) convertView.findViewById(R.id.thought_text_view);
likeButton = (Button) convertView.findViewById(R.id.thought_like_button);
dislikeButton = (Button) convertView.findViewById(R.id.thought_dislike_button);
//thoughtItems is a list of custom ojbects (Thought)
Thought t = thoughtItems.get(position);
//Here i set the content of the current TextView
thoughtText.setText(t.getText());
//the two buttons do basically the same thing when get clicked
likeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Thought t = thoughtItems.get(position);
thoughtId = t.getId();
opinion = 1;
AsyncPost asyncPost = new AsyncPost(activity,ThoughtListAdapter.this);
asyncPost.execute(SHARE_THOUGHT_URL,
TAG_PERSON_EMAIL, "m#b.it",
TAG_THOUGHT_ID, thoughtId.toString(),
TAG_OPINION, opinion.toString());
}
});
dislikeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Thought t = thoughtItems.get(position);
thoughtId = t.getId();
opinion = 0;
AsyncPost asyncPost = new AsyncPost(activity,ThoughtListAdapter.this);
asyncPost.execute(SHARE_THOUGHT_URL,
TAG_PERSON_EMAIL, "m#b.it",
TAG_THOUGHT_ID, thoughtId.toString(),
TAG_OPINION, opinion.toString());
}
});
return convertView;
}
#Override
public void onComplete(JSONObject json) {
if (json != null) {
try {
if (json.getInt(TAG_SUCCESS) == 0) {
Toast.makeText(activity, "Operazione non riuscita.", Toast.LENGTH_LONG).show();
} else {
//if everything is good i try to make the buttons of that particular list item disappear
likeButton.setVisibility(View.GONE);
dislikeButton.setVisibility(View.GONE);
}
}
catch (JSONException e) {
Log.e(TAG_LOG, "JSONException", e);
}
}
else Toast.makeText(activity, "Errore connessione!", Toast.LENGTH_LONG).show();
}
One solution to this would be to have something on your Thought object to indicate whether or not to show the buttons.
So in your getView() method you check this
likeButton = (Button) convertView.findViewById(R.id.thought_like_button);
dislikeButton = (Button) convertView.findViewById(R.id.thought_dislike_button);
Thought t = thoughtItems.get(position);
if (t.hideButtons()) {
likeButton.setVisibility(View.GONE);
dislikeButton.setVisibility(View.GONE);
}
else {
likeButton.setVisibility(View.VISIBLE);
dislikeButton.setVisibility(View.VISIBLE);
}
Then you would need to have your onComplete method return the id of the Thought object that it related to. Then inside your onComplete you could do
int id = //get your id from your JSON response
for(Thought t : thoughtItems) {
if (t.getId() == id) {
t.setHideButtons(true);
notifyDataSetChanged();
break;
}
}
By calling notifyDataSetChanged() it will redraw your list and when it does the check for whether it should show the buttons or not it will not show them because it was set on that thought item
So I had my listview working perfectly then I decided to add a context menu. As soon as I did that whenever I normal clicked an item in my listview, the entire list gets inverted on the first click. Subsequent clicks do nothing to the order, but when the first item is de-selected again the list returns to normal. When I take out the context menu logic that I added, the list view problem does not go away.
I've attached a debugger and the elements in my list adapter are never reordered, and the ListView itself is never set to reverse with .setStackFromBottom()
Here is my onClick listener registered to handle the click events of the list view items:
public void onClick(View v) {
ViewHolder holder = (ViewHolder) v.getTag();
CheckBox b = holder.box;
Boolean check = b.isChecked();
b.setChecked(!check);
if (!check) {
mChecked.add(holder.fu);
if (mChecked.size() == 1) {
buttonLayout.setVisibility(View.VISIBLE);
}
} else {
mChecked.remove(holder.fu);
if (mChecked.size() == 0) {
buttonLayout.setVisibility(View.GONE);
}
}
}
The viewholder class just holds references to objects I use in the listview for optimizations. I cannot figure out why this is causing my list to invert when displayed, I've tried moving the listener to a different view in the layout, I've tried re-writing the listener, nothing seems to work! Any advice would be appreciated.
Edit: here is the code for the view holder
/** Class to provide a holder for ListViews. Used for optimization */
private class ViewHolder {
TextView date;
TextView gallons;
TextView cost;
TextView cpg;
TextView mpg;
CheckBox box;
FillUp fu;
}
as well as the adapter:
public class FillUpAdapter extends BaseAdapter {
ArrayList<FillUp> mElements;
ArrayList<FillUp> mChecked;
Context mContext;
public FillUpAdapter(Context c, ArrayList<FillUp> data) {
mContext = c;
mElements = data;
mChecked = new ArrayList<FillUp>();
}
public void clearChecked() {
mChecked.clear();
}
public ArrayList<FillUp> getChecked() {
return mChecked;
}
public boolean remove(FillUp f) {
mChecked.remove(f);
return mElements.remove(f);
}
#Override
public int getCount() {
return mElements.size();
}
#Override
public Object getItem(int arg0) {
return mElements.get(arg0);
}
#Override
public long getItemId(int arg0) {
return mElements.get(arg0).getId();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout layout;
ViewHolder holder;
if (convertView != null) {
layout = (LinearLayout) convertView;
holder = (ViewHolder) layout.getTag();
} else {
layout = (LinearLayout) LayoutInflater.from(mContext).inflate(
R.layout.fillup_list_item, parent, false);
holder = new ViewHolder();
holder.cost = (TextView) layout
.findViewById(R.id.fillUpListTotalValue);
holder.cpg = (TextView) layout
.findViewById(R.id.fillUpListCostPerGal);
holder.gallons = (TextView) layout
.findViewById(R.id.fillUpListGalValue);
holder.mpg = (TextView) layout
.findViewById(R.id.fillUpMPGText);
holder.date = (TextView) layout
.findViewById(R.id.fillUpListDate);
holder.box = (CheckBox) layout
.findViewById(R.id.fillUpListCheckBox);
holder.fu = (FillUp) getItem(position);
layout.setTag(holder);
}
holder.date.setText(holder.fu.getDate());
holder.gallons.setText(holder.fu.getGallonsText());
holder.cpg.setText(holder.fu.getCostText());
holder.cost.setText(holder.fu.getTotalText());
holder.mpg.setText(String.format("%03.1f MPG",holder.fu.getMPG()));
if (convertView != null) {
holder.box.setChecked(mChecked.contains(holder.fu));
}
layout.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ViewHolder holder = (ViewHolder) v.getTag();
CheckBox b = holder.box;
Boolean check = b.isChecked();
b.setChecked(!check);
if (!check) {
mChecked.add(holder.fu);
if (mChecked.size() == 1) {
buttonLayout.setVisibility(View.VISIBLE);
}
} else {
mChecked.remove(holder.fu);
if (mChecked.size() == 0) {
buttonLayout.setVisibility(View.GONE);
}
}
}
});
return layout;
}
}
UPDATE:
Ok, so I've narrowed it down to the visibility change on the buttonLayout view, which is a linear layout of buttons on the bottom of the Activity's layout, underneath the ListView. Whenever I change that view's visibility to View.VISIBLE (which happens when the first item is checked) the list's order is reversed. The order is restored when the view's visibility is set to View.GONE
I have no idea what would cause that though :(
After narrowing the scope a bit more, I discovered the problem was not the changing of the visibility of my button bar, but actually the passing around of FillUp objects in holder.fu of my ViewHolder class. By changing that to instead reference the adapter's getItem(position) method, everything seemed to work out. Quite an odd bug, since the adapter itself was not having the order of the elements changed, but passing around a reference to the object made it very unhappy.
If your listview background color changes when you click on it, I think it is about your theme. Just play with the cache color parameters of your listview, here is an example:
<ListView
android:layout_width="fill_parent"
android:id="#android:id/list"
android:scrollingCache="true"
android:persistentDrawingCache="all"
android:cacheColorHint="#0000"
android:layout_height="wrap_content"
android:fastScrollEnabled="true"
android:stackFromBottom="true"
android:smoothScrollbar="true"
android:paddingTop="115dip">
</ListView>