Names appearing twice in list view items

510 views Asked by At

I'm trying to set up a 2-line list view but each string seems to copy itself within the item rather than showing it once. How can I prevent this from happening? i.e. I need the data to appear like this: for Item 1 - America, America Description rather than America, America; for Item 2 - Europe, Europe Description rather than Europe, Europe. See screenshot for evidence of the undesired result.

ListData.java

public class ListData {

    public static final int[][] items = {
            {R.string.america,R.string.america_description},
            {R.string.europe, R.string.europe_description}
    };

}

ListViewAdapter

public class ItemListAdapter extends BaseAdapter implements Filterable {

    private List<String> mData;
    private List<String> mFilteredData;
    private LayoutInflater mInflater;
    private ItemFilter mFilter;

    public ItemListAdapter (List<String> data, Context context) {
        mData = data;
        mFilteredData = data;
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getCount() {
        return mFilteredData.size();
    }

    @Override
    public String getItem(int position) {
        return mFilteredData.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        String strItem = mFilteredData.get(position);
        ViewHolder holder;
        if (convertView == null) {
           convertView = mInflater.inflate(R.layout.item_row, parent, false);

            holder = new ViewHolder();
            holder.mTitle = (TextView) convertView.findViewById(R.id.item_title);
            holder.mDescription = (TextView) convertView.findViewById(R.id.item_description);

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

        holder.mTitle.setText(strItem);
        holder.mDescription.setText(strItem);

        return convertView;
    }

    @Override
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ItemFilter();
        }
        return mFilter;
    }

    /**
     * View holder
     */
    static class ViewHolder {
        private TextView mTitle;
        private TextView mDescription;
    } 
}

item_row.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:paddingRight="?android:attr/scrollbarSize"
    android:baselineAligned="false">

    <RelativeLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <TextView android:id="@+id/item_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:ellipsize="marquee"
            android:textColor="?android:attr/textColorPrimary" />

        <TextView android:id="@+id/item_description"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/item_title"
            android:layout_alignLeft="@id/item_title"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:textColor="?android:attr/textColorSecondary" />

    </RelativeLayout>

</LinearLayout>

ItemListadapter.java

public class ItemListAdapter extends BaseAdapter implements Filterable {

    private List<String> mData;
    private List<String> mFilteredData;
    private LayoutInflater mInflater;
    private ItemFilter mFilter;

    public ItemListAdapter (List<String> data, Context context) {
        mData = data;
        mFilteredData = data;
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getCount() {
        return mFilteredData.size();
    }

    @Override
    public String getItem(int position) {
        return mFilteredData.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        String strItem = mFilteredData.get(position);
        ViewHolder holder;
        if (convertView == null) {
           convertView = mInflater.inflate(R.layout.item_row, parent, false);
            holder = new ViewHolder();

            holder.mTitle = (TextView) convertView.findViewById(R.id.item_title);
            holder.mDescription = (TextView) convertView.findViewById(R.id.item_description);

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

        holder.mTitle.setText(strItem);
        holder.mDescription.setText(strItem);

        return convertView;
    }

    @Override
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ItemFilter();
        }
        return mFilter;
    }

    /**
     * View holder
     */
    static class ViewHolder {
        private TextView mTitle;
        private TextView mDescription;
    }

    /**
     * Filter for filtering list items
     */
    private class ItemFilter extends Filter {

        /**
         * Invoked on a background thread.  This is where all the filter logic should go
         * @param constraint the constraint to filter on
         * @return the resulting list after applying the constraint
         */
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {

            FilterResults results = new FilterResults();

            if (TextUtils.isEmpty(constraint)) {
                results.count = mData.size();
                results.values = mData;
            } else {
                //Create a new list to filter on
                List<String> resultList = new ArrayList<>();
                for (String str : mData) {
                    if (str.toLowerCase().contains(constraint.toString().toLowerCase())) {
                        resultList.add(str);
                    }
                }
                results.count = resultList.size();
                results.values = resultList;
            }
            return results;
        }

        /**
         * Runs on ui thread
         * @param constraint the constraint used for the result
         * @param results the results to display
         */
        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {

            if (results.count == 0) {
                notifyDataSetInvalidated();
            } else {
                mFilteredData = (ArrayList<String>)results.values;
                notifyDataSetChanged();
            }
        }
    }
}

enter image description here

1

There are 1 answers

3
Giorgio Antonioli On BEST ANSWER

The name is shown two times in ListView because you are passing in both TextView the same item:

String strItem = mFilteredData.get(position);

To avoid this and use two separate fields you need to pass to your adapter a model with two field:

public class CustomListItem {
    private String title;
    private String description;

    //get method

    public CustomListItem(String title, String description){
        this.title = title;
        this.description = description;
    }
}

Then you have to add them to create a new List<CustomListItem> in your activity/fragment that use the adapter and pass to the adapter this list:

public class ItemListAdapter extends ArrayAdapter<CustomListItem>{
    private Context context;
    private List<CustomListItem> data;

    public ItemListAdapter(Context context, List<CustomListItem> data){
        this.context = context;
        this.data = data;
    }
}