1

I have an activity which contains a ListView of Checkable items. Every item is a custom view name CheckableContact which implements Checkable. Everything is working fine except when I scroll down the items inside the ListView move with different speeds and out of place. Check out the screenshots below.
Something to bear in mind is that the ListView gets updated using sociket.io upon reaching the scroll end.

ListView distorted ListView distorted

Here is the Complete source of my classes.

CheckableContact.java

public class CheckableContact extends LinearLayout implements Checkable {
    private final View v;
    private ImageView imageView;
    private TextView name;

    public int getProfileID() {
        return profileID;
    }

    public void setProfileID(int profileID) {
        this.profileID = profileID;
    }

    private int profileID;

    public TextView getDesc() {
        return desc;
    }

    public TextView getName() {
        return name;
    }

    public ImageView getImageView() {
        return imageView;
    }

    private TextView desc;
    boolean checked = false;

    public CheckableContact(Context context) {
        super(context);
        LayoutInflater inflater = LayoutInflater.from(context);
        v = inflater.inflate(R.layout.contact_item_check, this, true);
        CheckBox cb = (CheckBox) v.findViewById(R.id.select_contact);
        cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                setChecked(b);
            }
        });

        imageView = (ImageView) v.findViewById(R.id.avatar);
        name = (TextView) v.findViewById(R.id.contact_title);
        desc = (TextView) v.findViewById(R.id.contact_desc);
    }


    @Override
    public void setChecked(boolean b) {
        Log.d("Checkable", "Checking: " + profileID);
        this.checked = b;
    }

    @Override
    public boolean isChecked() {
        return checked;
    }

    @Override
    public void toggle() {
        checked = !checked;
    }
}

CheckParticipantsAdapter.java

public class CheckParticipantsAdapter extends ArrayAdapter<Profile> {
    LayoutInflater inflater;
    ArrayList<Profile> myProfiles;
    AQuery aq;
    private Context context;
    int contactLayout = R.layout.conversation_item;
    Map<Integer, CheckableContact> checks = new HashMap<>();

    public CheckParticipantsAdapter(Context context, ArrayList<Profile> myProfiles) {
        super(context, R.layout.friend_list, myProfiles);
        this.myProfiles = myProfiles;
        this.context = context;
        aq = new AQuery(context);

    }

    public void setContactLayout(int layoutID) {
        contactLayout = layoutID;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;
        Profile profile = myProfiles.get(position);
        if (row == null) {
            row = new CheckableContact(context);

            ((CheckableContact) row).getName().setText(profile.getFullName());

            ((CheckableContact) row).setProfileID(profile.getProfileID());
            if (checks.containsKey(profile.getProfileID())) {
                ((CheckableContact) row).setChecked(checks.get(profile.getProfileID()).isChecked());
            } else {
                checks.put(profile.getProfileID(), (CheckableContact) row);
            }
        } else {
            row = checks.get(profile.getProfileID());
        }


//        TextView username = (TextView) row.findViewById(R.id.conversation_name);

//        if (!profile.getPhotoPath().equals("")) {
        String path = Util.URL_USERS_PHOTOS + profile.getPhotoPath();
        aq.id(((CheckableContact) row).getImageView()).image(path, true, true, 100, R.drawable.avatar);
//        }

        return row;
    }

    public ArrayList<Integer> getCheckIds() {
        ArrayList<Integer> ids = new ArrayList<>();
        Iterator it = checks.keySet().iterator();
        while (it.hasNext()) {
            CheckableContact c = (CheckableContact) it.next();
            if (c.isChecked()) {
                ids.add(c.getProfileID());
            }
        }
        return ids;
    }
}
2hamed
  • 8,719
  • 13
  • 69
  • 112
  • did your code works fine ? because you initialize your view in `if (row == null)` and i think if you scroll your listView names must be repeat, – Shayan Pourvatan Dec 25 '14 at 09:09
  • Yes, as you can see in the screenshots it works fine other than the scrolling problem. – 2hamed Dec 25 '14 at 09:11
  • 2
    oh , i realize you code now and this code is not good, you must use viewHolder and save that instead of saving all view, define one class and initialize all view in that then use `row.setTag(holder)` and in else part use holder = (ViewHolder) row.getTag(); then initialize data of your view after else part – Shayan Pourvatan Dec 25 '14 at 09:17
  • for more info see http://developer.android.com/training/improving-layouts/smooth-scrolling.html and http://stackoverflow.com/questions/3123193/listview-with-arrayadapter-and-viewholder-adding-icons-to-the-wrong-item – Shayan Pourvatan Dec 25 '14 at 09:20
  • @shayanpourvatan Thanks rafigh! ;) I could do it using view holders. If you put your suggestion in an answer I would check it as accepted. – 2hamed Dec 25 '14 at 12:11

1 Answers1

1

as you use custom view in your list item i think your view don't know own height so while scrolling you see different height for your view because you create new view all times, so you must use ViewHolder for better performance and fixing your problem.

you can see following link to better understand my word , i put some sample code for you too.

ListView with ArrayAdapter and ViewHolder

Android Developer

all step is:

1- init your view when convertView is null

2- use setTag method to store this info in view

3- if your convertView is not null get that info with getTag

4- init data of your view after else part.

if (convertView == null)
{
   ViewHolder holder = new ViewHolder();
   .....  // init holder


   convertView.setTag(holder);

}

else
{
   holder = (ViewHolder)convertView.getTag();
} 

 // init data with holder object
Community
  • 1
  • 1
Shayan Pourvatan
  • 11,898
  • 4
  • 42
  • 63