Как реализовать два разных типа разделителей (т.е. заголовков) в классе адаптера ListView
Я вызываю адаптер по этому набору кодов:
mAdapter = new MyCustomAdapter(getActivity());
mAdapter.addSeparatorItem(new ContentWrapper(q.get(0).getA_name(),null));
mAdapter.addItem(new ContentWrapper(q.get(0).getAS_name(), q.get(0).getDesc_art()));
Рассмотрим этот код:
private class MyCustomAdapter extends BaseAdapter {
private static final int TYPE_ITEM = 0;
private static final int TYPE_SEPARATOR = 1;
private static final int TYPE_MAX_COUNT = TYPE_SEPARATOR + 1;
private ArrayList<ContentWrapper> mData = new ArrayList<ContentWrapper>();
private LayoutInflater mInflater;
private TreeSet<Integer> mSeparatorsSet = new TreeSet<Integer>();
public MyCustomAdapter(Context context)
{
mInflater = LayoutInflater.from(context);
}
public void addItem(ContentWrapper value) {
mData.add(value);
notifyDataSetChanged();
}
public void addSeparatorItem(ContentWrapper value) {
mData.add(value);
// save separator position
mSeparatorsSet.add(mData.size() - 1);
notifyDataSetChanged();
}
public ContentWrapper getItem(int position) {
return mData.get(position);
}
@Override
public int getItemViewType(int position) {
return mSeparatorsSet.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;
}
@Override
public int getViewTypeCount() {
return TYPE_MAX_COUNT;
}
public int getCount() {
return mData.size();
}
public long getItemId(int position) {
Log.v("getItemId Position", ""+position);
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
int type = getItemViewType(position);
if (convertView == null) {
holder = new ViewHolder();
switch (type) {
case TYPE_ITEM:
convertView = mInflater.inflate(R.layout.white, null);
holder.textView = (TextView)convertView.findViewById(R.id.text);
break;
case TYPE_SEPARATOR:
convertView = mInflater.inflate(R.layout.black, null);
holder.textView = (TextView)convertView.findViewById(R.id.textSeparator);
count++;
break;
}
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
} holder.textView.setText(mData.get(position).getItem());
if (type == TYPE_ITEM) {
holder.textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setIcon(R.drawable.ic_launcher);
final String title = mData.get(position).getItem();
builder.setTitle(title);
builder.setMessage(mData.get(position).getItemDescription());
builder.setCancelable(false);
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog alertDialog = builder.create();
alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
AlertDialog alertDialog = (AlertDialog) dialog;
ViewGroup viewGroup = (ViewGroup) alertDialog.getWindow()
.getDecorView();
TextView textView = findTextViewWithTitle(viewGroup, title);
if (textView != null) {
textView.setEllipsize(null);
textView.setMaxHeight((int) (100 * alertDialog.getContext().getResources().getDisplayMetrics().density));
textView.setMovementMethod(new ScrollingMovementMethod());
}
}
});
alertDialog.show();
}
private TextView findTextViewWithTitle(ViewGroup viewGroup, String title) {
for (int i = 0, N = viewGroup.getChildCount(); i < N; i++) {
View child = viewGroup.getChildAt(i);
if (child instanceof TextView) {
TextView textView = (TextView) child;
if (textView.getText().equals(title)) {
return textView;
}
} else if (child instanceof ViewGroup) {
ViewGroup vGroup = (ViewGroup) child;
return findTextViewWithTitle(vGroup, title);
}
}
return null;
}
});
} else {
holder.textView.setOnClickListener(null);
}
return convertView;
}
}
public static class ViewHolder {
public TextView textView;
}
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return false;
}
Этот код просто отображает описание выбранного элемента (здесь TYPE_ITEM
) в AlertDialog.
Как вы можете видеть, TYPE_SEPERATOR
отключили onClick(), и я хочу добавить еще один TYPE_SEPERATOR_GRAY
(пусть из gray.xml
), который будет разделителем другого типа с отключенным onClick()
.
Нужно ли добавить еще один метод, аналогичный addSeparatorItem(ContentWrapper value)
например addSeparatorItemGray(ContentWrapper value)
. Я знаю, что я должен добавить еще один случай в переключателе getView() для надувания grey.xml
Или что еще я должен добавить/изменить?
РЕДАКТИРОВАТЬ: ContentWrapper содержит текст элементов с его описанием. Я реализовал ContentWrapper для назначения каждого TYPE_ITEM с описанием
public class ContentWrapper {
private String mItem, mItemDescription;
public ContentWrapper(String item, String itemDescription) {
mItem = item;
mItemDescription = itemDescription;
}
public String getItem() {
return mItem;
}
public String getItemDescription() {
return mItemDescription;
}
}
mAdapter имеет тип MyCustomAdapter.
Первые 3-4 строки моего вопроса говорят, что у addSeparatorItem нет описания, поэтому во втором аргументе передается значение null, а в addItem есть текст и описание.
Я хочу добавить еще один TYPE_GRAY_SEPARATOR, в некоторые указанные позиции в списке вручную, например:
mAdapter.addSeparatorItemGray("HI after 1st view");
mAdapter.addSeparatorItemGray("HI after 23rd view");
mAdapter.addSeparatorItemGray("HI after 45 view");
Ответы
Ответ 1
Метод getViewType
должен вернуть 3 (List Item + Separator + Grey Separator). Следовательно, установите TYPE_MAX_COUNT
в 3.
private static final int TYPE_GRAY_SEPARATOR = 2;
private static final int TYPE_MAX_COUNT = TYPE_GRAY_SEPARATOR + 1;
Структура данных для размещения серого разделителя:
private TreeSet<Integer> mGraySeparatorsSet = new TreeSet<Integer>();
Метод добавления серого разделителя.
public void addGraySeparatorItem(ContentWrapper value) {
mData.add(value);
// save separator position
mGraySeparatorsSet.add(mData.size() - 1);
notifyDataSetChanged();
}
Метод getItemViewType
должен возвращать соответствующий вид, основанный на позиции.
@Override
public int getItemViewType(int position) {
int viewType = TYPE_ITEM;
if(mSeparatorSet.contains(position))
viewType = TYPE_SEPARATOR;
else if(mGraySeparatorSet.contains(position)) {
viewType = TYPE_GRAY_SEPARATOR;
}
return viewType;
}
Метод getView
должен обрабатывать TYPE_GRAY_SEPARATOR:
public View getView(final int position, View convertView, ViewGroup parent) {
// Existing code
switch(type) {
// Existing cases
case TYPE_GRAY_SEPARATOR:
// Inflate appropriate view
break;
}
// Existing code
}
Ответ 2
Подумайте о дополнительном разделителе как другом виде.
Поэтому, чтобы соответствовать вашему стилю кода, вам нужно добавить еще один Collection
для этих разделителей и добавить необходимые методы:
private static final int TYPE_GRAY_SEPARATOR = 2;
private TreeSet<Integer> mGraySeparatorsSet = new TreeSet<Integer>();
Также обновите свой метод getViewTypeCount()
, так как теперь у вас есть еще один вид.
Наконец, добавьте еще один тег if else
в свой метод getView
, проверяя этот новый вид.
В качестве альтернативы ознакомьтесь с библиотекой StickyListHeaders, которая обрабатывает для вас много этой логики.
Ответ 3
Сначала добавьте еще один тип в getViewTypeCount и getItemViewType, как и другие.
Однако вы ошибаетесь. Вам не нужно делать элементы списка доступными! Это задача ListView для обнаружения кликов и запуска OnItemClickListener при нажатии элемента. Таким образом, вы можете удалить все вызовы setOnClickListener.
Чтобы сделать разделители в ListView, вам нужно сделать несколько элементов отключено. Для этой цели существуют следующие функции:
- BaseAdapter.areAllItemsEnabled() - вы возвращаете false
- isEnabled (int position) - возвращает false для элементов, которые являются разделителями
Также нет необходимости использовать Set < > для обозначения разделителей. Просто найдите исходный список записей с позицией и верните, что разделители отключены, нормальные элементы включены.