Я не могу оставлять комментарии, потому что я новый пользователь, но можете ли вы описать, ЧТО вы пытаетесь сделать, а не КАК вы пытаетесь это сделать? Часто вы обнаружите, что это проблема дизайна, а не кодирования. Особенно, если вы идете с другой платформы (например, iOS). По опыту я обнаружил, что измерение и мануалы в Android в большинстве случаев не нужны, если вы правильно планируете свой макет в свете потребностей своего бизнеса.
EDIT: Как я уже говорил, это может быть решено с использованием некоторых проектных решений. Я буду использовать пример Nodes/List (надеюсь, что это ваш фактический прецедент, но решение может быть расширено для более общей проблемы).
Так что, если мы думаем о своем заголовке как комментарий в форуме, и список в качестве ответов на ваш комментарий, мы можем сделать следующее предположение:
Один список достаточно, не два. Каждый элемент в списке может быть либо заголовком (комментарием), либо элементом списка (ответ). Каждый ответ - это комментарий, но не все комментарии являются ответами.
Для элемента n, я знаю, является ли это комментарием или ответом (т. Е. Это заголовок или элемент в вашем списке).
- Для элемента n у меня есть логический элемент isVisible (по умолчанию false; View.GONE).
Теперь вы можете использовать следующие компоненты:
- один дополнительный адаптер класса
- Два макета XMLs: Один за ваш комментарий, один для вашего ответа. У вас могут быть неограниченные комментарии, и каждый комментарий может иметь неограниченные ответы. Оба эти требования удовлетворяют вашим требованиям.
- Ваш фрагмент или класс контейнера активности, который реализует OnItemClickListener для отображения/скрыть ваш список.
Итак, давайте посмотрим на некоторый код, не так ли?
Во-первых, ваши XML файлы:
Комментарий строки (ваш заголовок)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/overall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<TextView
android:id="@+id/comment_row_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
Теперь ваш ответ строка (элемент в списке)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/overall"
android:layout_width="match_parent"
android:layout_height="wrap_content"> <!-- this is important -->
<TextView
android:id="@+id/reply_row_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/> <!-- important -->
</RelativeLayout>
Хорошо, теперь ваш адаптер класс
public class CommentsListAdapter extends BaseAdapter implements OnClickListener
{
public static String TAG = "CommentsListAdapter";
private final int NORMAL_COMMENT_TYPE = 0;
private final int REPLY_COMMENT_TYPE = 1;
private Context context = null;
private List<Comment> commentEntries = null;
private LayoutInflater inflater = null;
//All replies are comments, but not all comments are replies. The commentsList includes all your data. (Remember that the refresh method allows you to add items to the list at runtime.
public CommentsListAdapter(Context context, List<Comment> commentsList)
{
super();
this.context = context;
this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.commentEntries = commentsList;
}
//For our first XML layout file
public static class CommentViewHolder
{
public RelativeLayout overall;
public TextView label;
}
//For our second XML
public static class ReplyViewHolder
{
public RelativeView replyOverall;
public TextView replyLabel;
}
@Override
public int getViewTypeCount()
{
return 2; //Important. We have two views, Comment and reply.
}
//Change the following method to determine if the current item is a header or a list item.
@Override
public int getItemViewType(int position)
{
int type = -1;
if(commentEntries.get(position).getParentKey() == null)
type = NORMAL_COMMENT_TYPE;
else if(commentEntries.get(position).getParentKey() == 0L)
type = NORMAL_COMMENT_TYPE;
else
type = REPLY_COMMENT_TYPE;
return type;
}
@Override
public int getCount()
{
return this.commentEntries.size(); //all data
}
@Override
public Object getItem(int position)
{
return this.commentEntries.get(position);
}
@Override
public long getItemId(int position)
{
return this.commentEntries.indexOf(this.commentEntries.get(position));
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
CommentViewHolder holder = null;
ReplyViewHolder replyHolder = null;
int type = getItemViewType(position);
if(convertView == null)
{
if(type == NORMAL_COMMENT_TYPE)
{
convertView = inflater.inflate(R.layout.row_comment_entry, null);
holder = new CommentViewHolder();
holder.label =(TextView)convertView.findViewById(R.id.comment_row_label);
convertView.setTag(holder);
}
else if(type == REPLY_COMMENT_TYPE)
{
convertView = inflater.inflate(R.layout.row_comment_reply_entry, null);
replyHolder = new ReplyViewHolder();
replyHolder.replyLable = (TextView)convertView.findViewById(R.id.reply_row_label);
convertView.setTag(replyHolder);
}
}
else
{
if(type == NORMAL_COMMENT_TYPE)
{
holder = (CommentViewHolder)convertView.getTag();
}
else if(type == REPLY_COMMENT_TYPE)
{
replyHolder = (ReplyViewHolder)convertView.getTag();
}
}
//Now, set the values of your labels
if(type == NORMAL_COMMENT_TYPE)
{
holder.label.setTag((Integer)position); //Important for onClick handling
//your data model object
Comment entry = (Comment)getItem(position);
holder.label.setText(entry.getLabel());
}
else if(type == REPLY_COMMENT_TYPE)
{
replyHolder = (ReplyViewHolder)convertView.getTag(); //if you want to implement onClick for list items.
//Or another data model if you decide to use multiple Lists
Comment entry = (Comment)getItem(position);
replyHolder.replyLabel.setText(entry.getLabel()));
//This is the key
if(entry.getVisible() == true)
replyHolder.replyLabel.setVisibility(View.VISIBLE);
else
replyHolder.replyLabel.setVisibility(View.GONE);
}
return convertView;
}
//You can use this method to add items to your list. Remember that if you are using two data models, then you will have to send the correct model list here and create another refresh method for the other list.
public void refresh(List<Comment> commentsList)
{
try
{
this.commentEntries = commentsList;
notifyDataSetChanged();
}
catch(Exception e)
{
e.printStackTrace();
Log.d(TAG, "::Error refreshing comments list.");
}
}
//Utility method to show/hide your list items
public void changeVisibility(int position)
{
if(this.commentEntries == null || this.commentEntries.size() == 0)
return;
Comment parent = (Comment)getItem(position);
for(Comment entry : this.commentEntries)
{
if(entry.getParent().isEqual(parent))
entry.setVisible(!entry.getVisible()); //if it's shown, hide it. Show it otherwise.
}
notifyDataSetChanged(); //redraw
}
}
Хорошо, теперь у нас есть список заголовков со скрытыми детьми (помните, мы установили, что дети по умолчанию «ушли»). Не то, что мы хотели, поэтому давайте это исправим.
Ваш контейнер класса (фрагмент или активность) у вас будет следующее определение XML
<!-- the @null divider means transparent -->
<ListView
android:id="@+id/comments_entries_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="@null"
android:dividerHeight="5dp" />
И ваш onCreateView будет осуществлять OnItemClickListener и имеют следующие
private ListView commentsListView = null;
private List<Comment>comments = null;
private static CommentsListAdapter adapter = null;
....
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
...
//comments list can be null here, and you can use adapter.refresh(data) to set the data
adapter = new CommentsListAdapter(getActivity(), comments);
this.commentsListView.setAdapter(adapter);
this.commentsListView.setOnClickListener(this); //to show your list
}
Теперь, чтобы показать свой список, когда вам нажмите заголовок
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id)
{
adapter.changeVisibility(position);
}
Теперь, если предмет клик ked, и этот элемент имеет родительский элемент (т.е. элемент списка), он будет отображаться/скрываться в соответствии с его текущим состоянием.
Некоторые комментарии о коде:
Я написал это на WordPad, как у меня нет Dev среды под рукой. Извините за любые ошибки компиляции.
Этот код может быть оптимизирован: Если у вас очень большой набор данных, этот код будет медленным, так как вы перерисовываете весь список при каждом вызове changeVisibility(). Вы можете поддерживать два списка (один для заголовков, один для элементов списка), а в changeVisibility вы можете запрашивать только элементы списка).
Я вновь подтверждаю эту идею, что некоторые дизайнерские решения облегчат вашу жизнь. Например, если ваши элементы списка были всего лишь списком меток, тогда у вас может быть один пользовательский XML-файл (для вашего заголовка) и представление ListView в нем, которое вы можете установить в View.GONE. Это заставит все другие взгляды притворяться, что их даже нет, и ваш макет будет работать правильно.
Надеюсь, что это поможет.
Я понятия не имею, как вы подходите к этому. Лично я работал бы с «RecyclerView». Там работа по выделению детей обрабатывается специальным, подключаемым классом менеджеров. Существует более понятный API, и есть уже сторонние менеджеры, которые вы можете использовать (вместе с тремя, отправляющими в 'recyclerview-v7'), чтобы увидеть, как подойти к проблеме. – CommonsWare