Сделать так, чтобы первый элемент ListView отображался в другом макете

Я пытаюсь создать ListView с первым элементом, отображаемым в другом макете, а остальные — в общем макете. Оба макета имеют одинаковые элементы, которые попарно имеют одинаковые имена. Когда я делаю так:

public View getView(int position, View convertView, ViewGroup parent) {        
    if(convertView == null) {
        if(position == 0){
            convertView = inflater.inflate(R.layout.article_list_top_item, parent, false);
            Log.d("ALA", "pos = " + position + ", inflated top");
        }
        else {
            convertView = inflater.inflate(R.layout.article_list_item, parent, false);
            Log.d("ALA", "pos = " + position + ", inflated normal");
        }
    }
    // setText, setBitmap etc here
    return convertView;
}

это не сработало. Из журнала я могу сказать, что inflater.inflate сработало 6 раз, inflated top 1 раз и inflated normal 5 раз.

Отображено следующее: статья[0] была в макете article_list_top_item, а статья[1] ~ статья[5] была в article_list_item.

До сих пор все было в порядке, но шаблон повторялся, что означает, что статья [6], статья [12], [18],... все были в макете article_list_top_item, а это не то, что мне нужно.

Что я могу сделать, чтобы ТОЛЬКО первая статья появилась в article_list_top_item??

P.S. Я пробовал переименовывать элементы в article_list_top_item.xml и разветвлял процесс setText setImage, не помогло.

Я попытался добавить else return convertView; перед //setText строками, и получился беспорядок.

Я думал сделать отдельный элемент макета только для первого элемента, но это не то, что мне нужно, потому что весь список находится под SwipeRefreshLayout

Пожалуйста помоги.


person Mr. Kro    schedule 22.07.2015    source источник
comment
посмотрите здесь: stackoverflow.com/questions/17566512/   -  person Blackbelt    schedule 22.07.2015
comment
Спасибо @Blackbelt, это решило проблему. Не то чтобы я не искал, прежде чем опубликовать, но я был слишком отвлечен всеми этими сообщениями о ViewHolders.   -  person Mr. Kro    schedule 22.07.2015


Ответы (3)


Вы должны использовать другой тип представления. Ваш адаптер повторно использует уже надутый вид, поэтому, если вы хотите другой вид, вы должны сказать ему:

Создайте держатель для каждого из ваших типов просмотра

private class FirstHolder {
    //add a field for each subview in view type 1
}
private class SecondHolder {
    //add a field for each subview in view type 2
}

Переопределить метод getViewTypeCount()

@Override
public int getViewTypeCount() {
    return 2;
}

Переопределите метод getItemViewType(int position). Этот метод сообщает, какой тип представления используется для каждой позиции.

@Override
public int getItemViewType(int position) {
    if (position == 0) {
        return 0;
    } else {
        return 1;
    }
}

Создайте и настройте представление:

public View getView(int position, View convertView, ViewGroup parent) {
    if (position == 0) {
        FirstHolder holder;
        if (convertView == null) {
            holder = new FirstHolder();
            convertView = inflater.inflate(R.layout.whatever_firstlayout, parent, false);
            //for each field of holder find the subview
            convertView.setTag(holder);
        } else {
            holder = (FirstHolder) convertView.getTag();
        }
        //set the data in subview with holder fields
    } else {
        SecondHolder holder;
        if (convertView == null) {
            holder = new SecondHolder();
            convertView = inflater.inflate(R.layout.whatever_secondlayout, parent, false);
            //for each field of holder find the subview
            convertView.setTag(holder);
        } else {
            holder = (SecondHolder) convertView.getTag();
        }
        //set the data in subview with holder fields
    }
    return convertView;
}
person sonic    schedule 22.07.2015
comment
Отличный ответ с одним дополнением: пожалуйста, реализуйте шаблон ViewHolder. ListViews НЕ должны даже существовать без него. - person DDsix; 22.07.2015
comment
В случае наличия нескольких типов представлений можно сделать одинаковое количество классов модели ViewHolder. - person DDsix; 22.07.2015
comment
Спасибо, но я не вижу смысла держать здесь держатель. Это помогает только присваивать данные элементам макета, а это не то, с чем у меня возникают проблемы. У меня все еще есть правильные данные, назначенные правильному элементу в моем макете, просто мне нужно, чтобы только первый элемент отображался по-другому. - person Mr. Kro; 22.07.2015
comment
Спасибо @sonic, я переопределил только getViewTypeCount - person Mr. Kro; 22.07.2015

Вы можете использовать addHeaderView. Например;

LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View head = inflater.inflate(R.layout.headerlayout, listview, false);
listview.addHeaderView(head);
person Selim YILDIZ    schedule 22.07.2015
comment
Я решил проблему, прежде чем пытаться это сделать, но позже это может стать отличным справочником. Спасибо. - person Mr. Kro; 22.07.2015

Я нашел проблему. Точно так же, как сказал @sonic, я хочу использовать разные виды представлений для одного и того же ListView, поэтому я должен сказать ему об этом, переопределив getViewTypeCount() и getItemViewType(int position). Рабочий код:

@Override
public int getViewTypeCount(){
    return 2;
}

@Override
public int getItemViewType(int pos){
    return pos > 0 ? 1 : 0;
}

public View getView(int position, View listItem, ViewGroup parent) {
    if(listItem == null) 
        listItem = inflater.inflate(getItemViewType(position) == 0 ?
                   R.layout.article_list_top_item : R.layout.article_list_item
                   , parent, false);
    // setText setBitmap etc. here
}

Комментарии: Это работает, даже если я нигде не использую getViewTypeCount() и getItemViewType(int position), но их переопределение имеет значение. Сомневаясь, что getItemViewType(int position) что-то сделает, я попытался не переопределять его - и в результате мне пришлось переопределить оба, чтобы заставить его работать.

Я удивляюсь, как. Может быть, каждый раз, когда представление заполняется макетом, который никогда раньше не использовался, система присваивает этому макету номер от 0 до getViewTypeCount() - 1? В противном случае, где он использовался (в коде родительских классов), чтобы он имел значение?

Я оставлю это здесь, чтобы подумать позже.

person Mr. Kro    schedule 22.07.2015