Custom Component shuffles listview - android

I am making bar charts in custom list view. when I scroll list, components get shuffle. How can it be stopped.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.stats_row_layout, null);
}
Stat stat = objects.get(position);
if (stat.isFlag()) {
LinearLayout linearLayout = (LinearLayout) convertView.findViewById(R.id.parentLayout);
linearLayout.setVisibility(LinearLayout.VISIBLE);
} else {
LinearLayout linearLayout = (LinearLayout) convertView.findViewById(R.id.parentLayout);
linearLayout.setVisibility(LinearLayout.GONE);
}
if (!stat.isExist()) {
stat.setExist(true);
LinearLayout linearLayout = (LinearLayout) convertView.findViewById(R.id.statGraphLayout);
linearLayout.removeAllViews();
if (stat.getmView() == null) {
ImageView mView = new StatBarChartVie(context, stat.getStatValues());
stat.setmView(mView);
}
LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, 50);
stat.getmView().setLayoutParams(params);
linearLayout.addView(stat.getmView());
}
}
return convertView;
}

Using the visible / gone flags doesn't seem right in a list view.
Because of how a list view recycles views, that is probably the problem.
You may need to be a bit smarter about how you access the array. And not include invisible items in the count.
Whenever you change the data ( possibly overriding notifyDataSetChanged() calling its super), you could create a new Index ArrayList with only the values which are visible. So you no longer need to use the invisible settings. This way you only loop through the array on data changes.

Related

Items being added to a list item multiple times. How do I fix this?

I am trying to create a listview with each list item is different and their layouts are created by code. The initial layouts look fine, but when i scroll out and in, all the layout items added programatically are added again, resulting duplicate items. How can I solve that problem?
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
MyHolder holder;
if (v == null) {
LayoutInflater li = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = li.inflate(R.layout.empty_item, null);
holder = new MyHolder(v);
v.setTag(holder);
} else {
holder = (MyHolder) v.getTag();
}
TextView textView = new TextView(activity);
textView.setText(items.get(position).getItems().get(i).getText());
textView.setLayoutParams(params);
holder.linearLayout.addView(textView);
return v;
}
class MyHolder{
public TextView tvTitle;
public LinearLayout linearLayout;
public CardView cardView;
public MyHolder(View base){
tvTitle = (TextView)base.findViewById(R.id.tvTitle);
cardView = (CardView)base.findViewById(R.id.card_view2);
linearLayout = (LinearLayout)base.findViewById(R.id.linearLayoutCard);
}
}
I'm not even sure how this code is running, because you have no return statement in your getView() method. But you need to return the convertView in getView() so that the ListView can reuse those when it needs to. Otherwise, it'll just keep asking for new views every time it needs them. So you would just put return v; at the end of getView().
Additionally, you are creating and adding new TextViews to your MyHolder objects outside of the if (v == null) block. Normally you would instantiate new views like this if the convertView is null. If it isn't, you just pass it through to the ListView or make updates to it before passing it back. So what's happening is, the convertView is available (not null), but instead of using it, you're adding a brand new TextView instead, which is why you are getting duplicates.

How can I force the position of an element in a ListView

I have an Activity, which simply consists in listing Pair<String, String> objects. I have a custom TextWithSubTextAdapter, which extends ArrayAdapter:
public View getView(int position, View convertView, ViewGroup parent)
{
View view;
if (convertView == null)
{
LayoutInflater li = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = li.inflate(R.layout.text_sub, null);
TextView tv = (TextView)view.findViewById(R.id.mainText);
tv.setText(mCategories.get(position).first);
TextView desc = (TextView)view.findViewById(R.id.subText);
desc.setText(Html.fromHtml(mCategories.get(position).second));
}
else
{
view = (View) convertView;
}
return view;
}
mCategories is an ArrayList<Pair<String, String>>
I then call lv.setAdapter(new TextSubTextAdapter(this, Common.physConstants));
As long as I have a limited set of elements, It works great, because I don't need to scroll. However, when I add enough elements, after scrolling, the items swap their positions, like this:
I suspect that this behavior is due to me calling mCategories.get(position). Because the Views are never kept in the background and Android regenerates them every time, I never get the same item, as position will rarely have the same value.
Is there a way to get a constant id, which could allow me to get items with fixed positions ? I tried to use getItemID, but I do not understand how to implement it.
Note: Every string comes from a strings.xml file. They are never compared, and instanciated once, at startup.
When you scroll your list Android dynamically reuses the Views which scroll out of the screen. These convertViews don't have the content which should be at this position yet. You have to set that manually.
View view;
if (convertView == null)
{
LayoutInflater li = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = li.inflate(R.layout.text_sub, null);
}
else
{
view = convertView;
}
TextView tv = (TextView)view.findViewById(R.id.mainText);
tv.setText(mCategories.get(position).first);
TextView desc = (TextView)view.findViewById(R.id.subText);
desc.setText(Html.fromHtml(mCategories.get(position).second));
return view;

Android: How come my ListView style gets removed when List Item is scrolled off screen

Currently, I have a custom list adapter that has some logic that hide/show a certain ImageView in a row depending on a variable.
Initially, the logic works when the app first launches. (ImageView is hidden/shown accordingly).
But once I scroll the screen up and down, eventually, all the row's ImageView is hidden forever.
Does anyone know how to solve this problem?
here is my adapter:
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
PostHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new PostHolder();
holder.postThumb = (ImageView)row.findViewById(R.id.post_Thumb);
holder.postComments = (TextView)row.findViewById(R.id.post_comments);
holder.postInfo = (TextView)row.findViewById(R.id.item_subtitle);
holder.postScore = (TextView)row.findViewById(R.id.post_score);
holder.postTitle = (TextView)row.findViewById(R.id.item_title);
holder.postThumbHolder = (LinearLayout)row.findViewById(R.id.post_Thumb_holder);
row.setTag(holder);
}
else
{
holder = (PostHolder)row.getTag();
}
HashMap<String, String> post = data.get(position);
if(post.get("thumbnail").equals("default") || post.get("thumbnail").equals("self")){
holder.postThumbHolder.setVisibility(View.GONE);
}
holder.postComments.setText(post.get("comments"));
holder.postInfo.setText(post.get("info"));
holder.postScore.setText(post.get("score"));
holder.postTitle.setText(post.get("title"));
return row;
}
static class PostHolder
{
LinearLayout postThumbHolder;
ImageView postThumb;
TextView postComments;
TextView postScore;
TextView postTitle;
TextView postInfo;
}
It has to do with how android makes the background of the list items into bitmaps as soon as you start scrolling. To make sure your image views are visible after scrolling you must also set that property everytime the adapters getView is called do this in the else part of your variable check
if(post.get("thumbnail").equals("default") || post.get("thumbnail").equals("self")){
holder.postThumbHolder.setVisibility(View.GONE);
} else {
holder.postThumbHolder.setVisibility(View.VISIBLE);
}
Set visibility View.VISIBLE to postThumbHolder somewhere. In the else block of your
if (post.get...
clause.

ListView is not showing correct values after scrolling

In my application I am using a CustomListView with an ArrayAdapter to show different countries time. But after 6 to 7 rows(depending on the phone screen size) the time values are repeating.
According to some previous post I have written the following code snippet to get the solution. But the problem is still there.
Following is the code I have written:
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
Order o = items.get(position);
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout ll = (LinearLayout) vi.inflate(R.layout.row, null);
CustomDigitalClock customDC = new CustomDigitalClock(CityList.this, o.getOrderTime());
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.FILL_PARENT);
customDC.setTextColor(Color.WHITE);
customDC.setTextSize(13);
LayoutParams param=new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
ll.addView(customDC, 2);
v = ll;
}
if (o != null) {
TextView tt = (TextView) v.findViewById(R.id.toptext);
TextView bt = (TextView) v.findViewById(R.id.bottomtext);
if (tt != null) {
tt.setText("" + o.getOrderName());
}
if (bt != null) {
bt.setText("" + o.getOrderStatus());
}
v.setOnCreateContextMenuListener(this);
}
return v;
}
Can anybody help me?
ListViews recycle views, which means at first a base set of list entries is inflated from XML. When you scroll down now, one list entry gets hidden at the top, and a new one gets shown at the bottom. At this moment getView() is called with a non-null argument convertView, because an already inflated view is reused.
In your case that means that the whole layout inflation/setup is skipped (the if (v == null) tree). Which is fine, basically all you have to do is update the timestamp in the second if section (o != null).
It should contain something similar to this, like you did with the textviews too:
CustomAnalogClock customAC = (CustomAnalogClock) v.findViewById(R.id.yourclockid);
customAC.setTime(o.getOrderTime());
This means that you have to assign an ID (by using setId()) to your view while adding it to the layout, and also have to have a setTime() method ready.

Checkboxes in ListActivity seem to be linked; why? How do I fix it?

I have an activity which inherits ListActivity, and shows a list populate via an XML layout and a custom adapter class. It all renders fine, and as expected. The row XML includes in it a checkbox.
Now, what's weird is that the checkboxes seem to be linked every so many rows. That is, if I check the checkbox in row 0, then it also checks the checkboxes in rows 8, 18, 28, 38, 48, etc.
Why would this be, and how can I fix it?
If it is pertinent, i am reusing the view passed into my adapter when it is available. It does also seem that when I scroll one of the checked ones to the top of the screen, the next one to be checked is the second one off the bottom of the screen.
Below is my getView code:
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.contacts_row, null);
}
cb.GroupMembership.moveToPosition(position);
long cid = cb.GroupMembership.getLong(0);
String clk = cb.GroupMembership.getString(1);
String cnm = cb.GroupMembership.getString(2);
long pid = cb.GroupMembership.getLong(3);
ImageView bdg = (ImageView) v.findViewById(R.id.contactBadge);
Uri pic = GroupsLib.getContactPhotoUri(pid);
if (pic == null) {
bdg.setImageResource(R.drawable.contactg);
} else {
bdg.setImageURI(pic);
}
((TextView) v.findViewById(R.id.contactName)).setText(cnm);
return v;
}
When you reuse your view you should actually set the state of all controls in it (so basically clean-up). Precisely because it is reused.
Usually it would look like (in adapter):
public View getView (int position, View convertView, ViewGroup parent) {
SomeObject obj = getDataFromYourModel(position);
if (convertView == null) {
convertView = ....; //inflate view here
}
setMyViewParameters(obj,convertView);
}
public void setMyViewParameters(SomeObject obj, View view) {
CheckBox cb = (CheckBox) view.findViewById(R.id.checkbox_id);
cb.setChecked(obj.isChecked);
//other initialisation
}
This way, you always reset the values when the view is reused.

Categories

Resources