Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/230.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 在自定义AdapterView中实现onMeasure()和onLayout()的正确方法_Android_Android Layout_Android Custom View_Android Adapterview - Fatal编程技术网

Android 在自定义AdapterView中实现onMeasure()和onLayout()的正确方法

Android 在自定义AdapterView中实现onMeasure()和onLayout()的正确方法,android,android-layout,android-custom-view,android-adapterview,Android,Android Layout,Android Custom View,Android Adapterview,我知道我应该在onMeasure()中测量子对象,并在onLayout()中布局它们。问题是,我应该添加/回收哪些视图,以便能够测量所有子项,并观察它们之间的相互位置(即网格、列表或其他) 我的第一种方法是在onLayout()中添加/循环视图,但从那时起,我无法测量我的孩子,因为他们还没有添加到AdapterView中,getChildCount()在onMeasure()中返回0。如果孩子们没有被布置好,我无法测量AdapterView本身,因为这实际上取决于他们的相互位置,对吗 在Adap

我知道我应该在
onMeasure()
中测量子对象,并在
onLayout()中布局它们。问题是,我应该添加/回收哪些视图,以便能够测量所有子项,并观察它们之间的相互位置(即网格、列表或其他)

我的第一种方法是在
onLayout()
中添加/循环视图,但从那时起,我无法测量我的孩子,因为他们还没有添加到AdapterView中,
getChildCount()
onMeasure()中返回
0
。如果孩子们没有被布置好,我无法测量AdapterView本身,因为这实际上取决于他们的相互位置,对吗


在AdapterView中,当动态添加/删除孩子时,我真的对android布局过程感到困惑。

我不能发表评论,因为我是一个新用户,但你能描述一下你正在尝试做什么,而不是如何做吗?通常,您会发现这是一个设计问题,而不是编码问题。特别是如果您来自不同的平台(例如,iOS)。根据经验,我发现,如果您根据业务需要正确设计布局,那么在Android中测量和手动布局基本上是不必要的

编辑: 正如我提到的,这可以通过一些设计决策来解决。我将使用您的节点/列表示例(希望这是您的实际用例,但解决方案可以扩展为更一般的问题)

因此,如果我们认为你的标题是论坛中的评论,而列表是对你评论的回复,我们可以做出以下假设:

  • 一张清单就够了,不是两张。列表中的每个项目可以是标题(注释)或列表项目(回复)。每个回复都是一条评论,但并非所有评论都是回复

  • 对于项目n,我知道它是评论还是回复(即,它是标题还是列表中的项目)

  • 对于项n,我有一个布尔成员isVisible(默认为false;View.GONE)
  • 现在,您可以使用以下组件:

  • 一个扩展适配器类
  • 两个布局XML:一个用于评论,一个用于回复。您可以有无限的评论,每个评论可以有无限的回复。这两个都满足你的要求
  • 您的片段或活动容器类,它实现了用于显示/隐藏列表的McClickListener
  • 让我们看一些代码,好吗

    首先,您的XML文件:

    注释行(您的标题)

    
    
    现在是回复行(列表中的一个元素)

    
    
    好的,现在是适配器类

    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
    }
    
    }
    
    公共类CommentsListAdapter扩展BaseAdapter实现OnClickListener
    {
    公共静态字符串TAG=“CommentsListAdapter”;
    私有最终整数正常注释类型=0;
    私人最终int回复\注释\类型=1;
    私有上下文=null;
    私有列表条目=null;
    专用充气机=空;
    //所有回复都是评论,但并非所有评论都是回复。commentsList包含您的所有数据。(请记住,refresh方法允许您在运行时将项目添加到列表中。)。
    公共CommentsListAdapter(上下文上下文,列表commentsList)
    {
    超级();
    this.context=上下文;
    this.inflater=(LayoutInflater)context.getSystemService(context.LAYOUT\u inflater\u SERVICE);
    this.commentries=commentsList;
    }
    //对于我们的第一个XML布局文件
    公共静态类CommentViewHolder
    {
    公共相对性全面提升;
    公共文本视图标签;
    }
    //对于我们的第二个XML
    公共静态类ReplyViewHolder
    {
    公众相关评论回复总体;
    公共文本视图replyLabel;
    }
    @凌驾
    public int getViewTypeCount()
    {
    return 2;//重要。我们有两种观点,评论和回复。
    }
    //更改以下方法以确定当前项是标题还是列表项。
    @凌驾
    public int getItemViewType(int位置)
    {
    int type=-1;
    if(commentEntries.get(position).getParentKey()==null)
    类型=正常注释类型;
    else if(commentries.get(position.getParentKey()==0L)
    类型=正常注释类型;
    其他的
    类型=回复\注释\类型;
    返回类型;
    }
    @凌驾
    public int getCount()
    {
    返回此.commentries.size();//所有数据
    }
    @凌驾
    公共对象getItem(int位置)
    {
    返回this.commentries.get(位置);
    }
    @凌驾
    公共长getItemId(int位置)
    {
    返回this.commentries.indexOf(this.commentEntries.get(position));
    }
    @凌驾
    公共视图getView(int位置、视图转换视图、视图组父视图)
    {
    CommentViewHolder=null;
    ReplyViewHolder replyHolder=null;
    int type=getItemViewType(位置);
    if(convertView==null)
    {
    如果(类型==正常注释类型)
    {
    convertView=充气机。充气(R.layout.row\u comment\u条目,空);
    holder=新的CommentViewHolder();
    holder.label=(TextView)convertView.findViewById(R.id.comment\u row\u label);
    convertView.setTag(支架);
    }
    else if(type==回复\注释\类型)
    {
    convertView=充气机。充气(R.layout.row\u comment\u reply\u entry,null);
    replyHolder=新的ReplyViewHolder();
    replyHolder.replyLable=(TextView)convertView.findViewById(R.id.reply\u row\u label);
    setTag(replyHolder);
    }
    }
    其他的
    {
    如果(类型==正常注释类型)
    {
    holder=(CommentViewHolder)convertView.getTag();
    }
    else if(type==回复\注释\类型)
    {
    replyHolder=(ReplyViewHolder)convertView.getTag();
    }
    }
    //现在,设置标签的值
    如果(类型==正常注释类型)
    {
    holder.label.setTag((整数)位置);//对于onClick处理很重要
    //您的数据模型对象
    注释条目=(注释)getItem(位置);
    holder.label.setText(entry.get
    
    <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
    }
    
    }
    
    <!-- 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" />
    
    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);
    
    }