带有分隔符和复杂列表项的Android ListView。奇怪地滚动并且奇怪地画画

时间:2012-11-09 22:01:10

标签: android listview layout convertview

此问题已经第二次编辑:要查看原始问题,请向下滚动到“原始问题”的位置 - 对于之后的任何修改 - 请向下滚动到“编辑#”部分

编辑二:

此编辑响应Luksprog的请求,以查看我在getView()中设置所需元素的位置 - 检查convertView是否为null。

注意:请理解此代码是半模块化的。

CODE:

使用的持有人模式:

public static class HeaderHolder
{
    public TextView textView;
}
public static class CommandHolder
{
    public TextView textView;
    public Button[] buttonHolder;
    public OnClickListener[] clickHolder;
}

getView()方法 - 设置的位置:

    switch(type)
    {
        case 0: // Is a header
            String temp = commandLabel.replace("Section:", "");
            headerHolder.textView.setText(temp);
            break;
        case 1:// Is a command
            commandHolder.textView.setText(commandLabel);
            ArrayList<String[]> commands = commandCreator.getCommands();

            // Initially set the visibility of buttons to GONE
            for (int i = 0; i <commandHolder.buttonHolder.length; i++)
            {
                commandHolder.buttonHolder[i].setVisibility(View.GONE);
            }
            // Only show buttons based on how many commands there are
            for (int i = 0; i < commands.size(); i++)
            {
                pos = i;
                commandHolder.buttonHolder[i].setVisibility(View.VISIBLE);

                drawable_normal = commands.get(i)[1];
                drawable_pressed = commands.get(i)[1] + "_pressed";

                buttonStates = new StateListDrawable();
                buttonStates.addState(new int[]{statePressed}, ApplicationConstants.moduleImageLoader.findImageByName(drawable_pressed));
                buttonStates.addState(new int[]{-statePressed}, ApplicationConstants.moduleImageLoader.findImageByName(drawable_normal));
                buttonStates.addState(new int[]{}, ApplicationConstants.moduleImageLoader.findImageByName(drawable_normal));
                commandHolder.buttonHolder[i].setBackgroundDrawable(buttonStates);

                // Retrieve the intent and parameter from the current command
                String parameter = commands.get(i)[2];
                String intentName = commands.get(i)[0];

                if(intentName.contains("Call Phone"))
                {
                    commandHolder.clickHolder[i] = new OnClickListener()
                    {
                        public void onClick(View arg0)
                        {
                            //con.startActivity(call_phone);
                        }
                    };
                }
                else if(intentName.contains("Cell"))
                {
                    commandHolder.clickHolder[i] = new OnClickListener()
                    {
                        public void onClick(View arg0)
                        {
                            //con.startActivity(call_cell);
                        }
                    };
                }
                else if(intentName.contains("Map"))
                {
                    commandHolder.clickHolder[i] = new OnClickListener()
                    {
                        public void onClick(View arg0)
                        {
                            //con.startActivity(load_map);
                        }
                    };
                }
                else if(intentName.contains("Email"))
                {
                    commandHolder.clickHolder[i] = new OnClickListener()
                    {
                        public void onClick(View arg0)
                        {
                            //con.startActivity(send_email); 
                        }};
                }
                commandHolder.buttonHolder[i].setOnClickListener(commandHolder.clickHolder[i]);
            }
            convertView.setOnClickListener(new OnClickListener()
            {
                public void onClick(View arg0)
                {
                    Dialog dialog = new Dialog(ApplicationConstants.ref_currentActivity);
                    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
                    LinearLayout listDialogBoxlayout = new ListDialogBox(con, commandType, commandLabel, commandInfo);
                    dialog.setContentView(listDialogBoxlayout);
                    dialog.setCancelable(true);
                    dialog.show();
                }
            });
            break;
    }
    return convertView;

问题:看到问题在视觉上发生。请向下滚动到EDIT ONE并查看屏幕截图。

如果有任何问题或需要澄清,请发表评论,我会尽快回复。

编辑一个: 做出改变,但仍然是相同的行为

这是使用getItemViewType()的getView()方法的新实现: 我做了以下检查:

if(convertView == null)
{
   switch type
      case header:
        convertView = inflate a header
        headerHolder.textView = convertView.findViewById(headerTextId);
        convertView.setTag(headerHolder);
      break;
      case command:
        convertView = inflate a command
        // Use CommandHolder to initialize all the necessary elements   
        commandHolder.textView = convertView.findViewById(commandLabel);
        . 
        .
        convertView.setTag(commandHolder);
      break;
}
else
{
   switch(type)
      case header : 
         headerHolder = convertView.getTag(); 
      break;
      case command : 
         commandHolder = convertView.getTag();
         break;

}
// set the actual elements
switch(type)
   case:header
      //set all elements in header
   break;
   case: command
      //set all elements in command
   break;
 return convertView;

发生了什么:

我是一个视觉人,所以我认为这会有所帮助: 这是一些屏幕截图: 没有滚动 - 一切看起来都很棒

enter image description here

使用鼠标滚动滚动,一切看起来都很棒

enter image description here

通过单击列表并向下拖动来滚动 - 注意canam现在位于底部,Linda应该在哪里?

enter image description here

通过单击列表并向上拖动来滚动 - 请注意peter应该位于哪个顶部?

enter image description here

应该在哪里列出:

  1. 地址标题
  2. 的CanAm
  3. 员工标题
  4. 戴夫
  5. 布伦特
  6. 斯蒂芬
  7. 莫阿西尔
  8. 彼得
  9. 琳达
  10. 即使视图搞砸了 - 单击视图会弹出正确的对话框 - 如上所示。

    以下是没有发生的事情:

    1. 没有重复的观点
    2. 没有在错误的地方绘制部分标题
    3. 没有将节目标题绘制为命令(可以是地址或联系人)。
    4. 我觉得我就在那里.. 我可以错过什么?


      原始问题:

      这正是我正在做的事情:我已经简化了这种情况,只是用convertView问我的问题,而不是把人与其余的ViewCreator混淆。

      我的ListViewAdapter具有的方法:

      getItemViewType(...)
      
      getViewTypeCount(...)
      
      getView(int position, View convertView, ViewGroup parent)
      {
          int type = getItemViewType(position);
          if(listItem is section)
          {    
                if(convertView == null)
                {  
                    ViewGroup viewGroup = inflate a view
                    Holder.textView = textview;
                    viewgroup.setTag(holder);
                    view = viewGroup;
                }
                else
                {
                    holder = (HeaderHolder) convertView.getTag();
                    view = convertView;
                }
           }
           else 
           // different layout. Complicated list item in the form: 
           //|TextView  Button1 Button2 Button3| , where buttons only appear based on 
           //a CommandCreator. If john(TextView) has a phone and email - it displays:
           // |John PhoneButton EmailButton| 
           {
                 if(convertView == null)
                 {
                     // inflate view
                     // make buttons 
                     // make onclicks null
                     // set different holder
                     viewgroup.setTag(holder)
                     view = viewgroup;
                 }
                 else
                 {
                     view = convertView;
                     holder = (CommandHolder) convertView.getTag(); 
                 }
                 // set the buttons to show based on commands
                 // set the onclick listeners to the buttons to call certain intents based on  the command
           }
           return view;
       }
      

      }

      问题: 我应该如何使用getItemViewType和getViewTypeCount?以及如何使用Viewgroups和我目前的持有者?以下是否有效?

        getView
        {
             type = getItemViewType;
             if(convertView == null)
             {
                 switch(type)
                    case: header
                        convertView = inflate header view
                        intialize HeaderHolder
                        break;
                    case: command
                        convertView = inflate command view
                        initialize CommandHolder
                        break;
             }
             else
             {
                  switch(type)
                      case: header
                             //Actually set all the HeaderHolder Stuff
                         String temp = commandLabel.replace("Section:", "");
                         holder.textView.setText(temp);
                         LinearLayout.LayoutParams textViewParams = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT);
                         holder.textView.setLayoutParams(textViewParams);
                         return view;
                                     QUESTION : But how do I use Viewgroups, and my holder. and what am I returning?
                            break;
                      case: command
                           Actually set all the commandHolder stuff
                           QUESTION : Same as above.
                           break;
              }
              return convertView?
        }
      

      以下是我的处理程序:

      public static class HeaderHolder
      {
          public TextView textView;
      }
      public static class CommandHolder
      {
          public TextView textView;
          public Button[] buttonHolder;
          public OnClickListener[] clickHolder;
      }
      

      提前感谢您的帮助!我会回答你的任何问题。

2 个答案:

答案 0 :(得分:1)

关于这两种方法:

  • getViewTypeCount()返回布局类型的数量,在您的情况下为2

  • getItemViewType()根据您提供的int参数返回0(例如标题布局)或1(对于正常的行布局)。这实际上取决于您的数据以及如何在列表中设置标题和正常行。

关于上次编辑,您可能不会像应该那样在行布局上设置数据,尤其是当您引用这些OnClickListeners时。您应该发布此块中的完整代码:

// set the actual elements
switch(type)
   case:header
      //set all elements in header
   break;
   case: command
      //set all elements in command
   break;

Here是我编写的示例代码,其中包含一个实现多个ViewHolders和不同行布局类型的示例(如果您在适配器的这方面遇到问题)。

答案 1 :(得分:1)

尝试此代码可能会对您有所帮助......

if(convertView == null)
{
   switch type
      case header:
        convertView = inflate a header
        headerHolder.textView = convertView.findViewById(headerTextId);
        convertView.setTag(headerHolder);
      break;
      case command:
        convertView = inflate a command
        // Use CommandHolder to initialize all the necessary elements   
        commandHolder.textView = convertView.findViewById(commandLabel);
        . 
        .
        convertView.setTag(commandHolder);
      break;
}
else
{
   switch(type)
      case header : {
         if(convertView.getTag() instanceOf HeaderHolder){
             headerHolder = convertView.getTag(); 
         } else {
             headerHolder = inflate a header
             convertView.setTag(headerHolder);
         }
      }
      break;
      case command : {
         commandHolder = convertView.getTag();
         if(convertView.getTag() instanceOf CommandHolder){
             commandHolder = convertView.getTag(); 
         } else {
             commandHolder = inflate a command
             convertView.setTag(commandHolder );
         }
      }
      break;

}
// set the actual elements
switch(type)
   case:header
      //set all elements in header
   break;
   case: command
      //set all elements in command
   break;
 return convertView;