我不能发表评论,因为我是新用户,但你能描述一下你想做什么,而不是你想怎么做吗?通常,您会发现这是一个设计问题,而不是编码问题。特别是如果您来自不同的平台(例如,iOS)。根据经验,我发现如果您根据业务需求正确设计布局,则在 Android 中测量和手动布局几乎是不必要的。
编辑:
正如我所提到的,这可以通过一些设计决策来解决。我将使用您的节点/列表示例(希望这是您的实际用例,但可以针对更一般的问题扩展解决方案)。
因此,如果我们将您的 Header 视为论坛中的评论,而将 List 视为对您评论的回复,我们可以做出以下假设:
一个列表就足够了,而不是两个。列表中的每一项都可以是标题(评论)或列表项(回复)。每条回复都是评论,但并非所有 cmets 都是回复。
对于第 n 项,我知道它是评论还是回复(即,它是标题还是列表中的项目)。
- 对于项目 n,我有一个布尔成员 isVisible(默认为 false;View.GONE)。
现在,您可以使用以下组件:
- 一个扩展的适配器类
- 两个布局 XML:一个用于您的评论,一个用于您的回复。您可以拥有无限的 cmets,并且每条评论都可以拥有无限的回复。两者都满足您的要求。
- 实现 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);
}
现在,如果单击一个项目并且该项目具有父项(即列表项),它将根据其当前状态显示/隐藏。
关于代码的一些cmets:
我在写字板上写了这篇文章,因为我手头没有开发环境。对于任何编译错误,我们深表歉意。
此代码可以优化:如果您有一个非常大的数据集,此代码会很慢,因为您在每次调用 changeVisibility() 时都重新绘制整个列表。您可以维护两个列表(一个用于标题,一个用于列表项),并且在 changeVisibility 中您只能查询列表项。
我再次强调,一些设计决策会让你的生活变得更轻松。例如,如果您的列表项实际上只是一个标签列表,那么您可以有一个自定义 XML 文件(用于您的标题)和一个 ListView 视图,您可以将其设置为 View.GONE。这将使所有其他视图假装它甚至不存在,并且您的布局将正常工作。
希望这会有所帮助。