0

This question has been edited for the second time: To view the original question, please Scroll down to where it says "ORIGINAL QUESTION" - for any edits after that - Please scroll down to an "EDIT #" section.

EDIT TWO:

This edit is in reponse to Luksprog's request to see where I set elements required in getView() - After checks for convertView being null or not.

Note : Please understand that this code is semi-modular.

CODE:

Holder Patterns Used:

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

getView() Method - Where the setting takes place:

    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;

Question : To see the problem occurring visually. Please scroll down to EDIT ONE and look at the screen shots.

If anyone has any questions, or needs clarification, please leave a comment and I will get back to you.

EDIT ONE: Made Changes , but still the same behaviour

Here's the new implementation of the getView() method using getItemViewType(): I do the following checks:

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;

What's happening:

I'm a visual person, so I thought this would help: Here's some screen shots: No scrolling - Everything looks great

enter image description here

Scrolling with mouse scroll, everything still looks great

enter image description here

Scrolling by clicking on the list and dragging it down - Notice how canam is now at the bottom, where Linda should be?

enter image description here

Scrolling by clicking on the list and dragging it up - Notice how peter is at the top where canam should be?

enter image description here

List of what should be there:

  1. Address Header
  2. Canam
  3. Employees Header
  4. Dave
  5. Brent
  6. Stephen
  7. Moacir
  8. Peter
  9. Linda

Even though the views get messed up - clicking the views shows the correct dialog box pop up- As you can see above.

Here's whats not happening:

  1. No repeating views
  2. No section headers being drawn in the wrong places
  3. No section headers being drawn as commands(which can be addresses or contacts).

I feel like I'm right there guys.. What could I have missed?


Original Question:

This is currently what I am doing: I've simplified the situation to really just ask my question with convertView and not possibly confuse people with the rest of my ViewCreators.

Methods that my ListViewAdapter has:

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;
 }

}

Question: How should I use getItemViewType and getViewTypeCount? and How do I use Viewgroups, and my current holders? Would the following work?

  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?
  }

Here are my Handlers now:

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

Thank you for all your help in advance! and I will answer any questions you may have.

shecodesthings
  • 1,218
  • 2
  • 15
  • 33
  • I almost missed your questions inside the pseudocode, could you post only the code from the `Actually set all the HeaderHolder Stuff` section? I find it easier to describe with code rather than words or pseudocode. – Sam Nov 09 '12 at 22:21
  • You've already got the idea right. If you reach `case: header`, you KNOW what type of view has been retrieved (i.e. it is whatever you inflated originally under `case: header` when convertView was null) -- it's been recycled) so you can handle it for whatever that layout is. – Kevin Coppock Nov 09 '12 at 22:30
  • Hi sam, I added the header holder stuff you asked for. – shecodesthings Nov 11 '12 at 15:59
  • Hi kcoppock, once I'm done setting the view- case:header or case:item, do I just return "view"? Where would I be using setTag and getTag? That's what's confusing me. – shecodesthings Nov 11 '12 at 15:59
  • I have implemented what I asked in my original question - but still having the same problem. Please take a look at it when you can guys - I have tried to be as clear as possible. – shecodesthings Nov 11 '12 at 18:32

2 Answers2

1

About those two methods:

  • getViewTypeCount() return the number of types of layouts, 2 in your case

  • getItemViewType() based on the int parameter supplied you either return 0(for the header layout for example) or 1(for the normal row layout). This really depends on your data and how you setup the headers and normal rows in the list.

Regarding your last edit, you probably don't set the data on the row layout like you should, especially as you have references to those OnClickListeners. You should post the full code from this block:

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

Here is a sample code I wrote with an example implementing multiple ViewHolders and different row layouts types(if you have problems regarding this aspect of the adapters).

user
  • 86,916
  • 18
  • 197
  • 190
  • Hi Luksprog, Thank you for your comment and answer. I have posted more or less the full code from the block you request in the EDIT TWO: section of my question. I am looking at your sample code right now. – shecodesthings Nov 12 '12 at 14:50
  • @AminaKhalique What is that `commandLabel` text that you use in both situation, header and normal row? – user Nov 13 '12 at 10:27
  • The list is populated based on a list of CommandCreator Items. CommandCreator is a class that holds information about commands. So you can pass it something like "Contact", "John|Phone|Cell|Email|" and it will return a list of commands. Where each command in the list would be an array of command information like Phone Data, Phone Image, Phone intentName etc. commandLabel for this command would simply be "John". – shecodesthings Nov 17 '12 at 07:48
  • @AminaKhalique I don't know what's happening in your code so I'm guessing some stuff. Where did you declare the `commandLabel` String? Are you by any chance setting it only when the `convertView` is `null`? Are you sure your views aren't switching? From your pictures I see `canam` having that pointer as an image initially, but when "peter" is in its position the image changes to an envelope. Shouldn't those remain constant for that position? – user Nov 17 '12 at 16:28
  • No commandLabel is set independent of convert view. As its a part of the ArrayList commands list, that is used to populate the list itself. I really am not quite whats happening. My views do look like they are switching. Atleast what's being drawn. And yes its true, canam initially has a "map-pin" and then changes to a email - which is what peter has as a contact method - only email. It's literally drawing the view in the wrong spot, but when clicked the info thats supposed to be there is shown. Going to eyeball it again and get back to you! – shecodesthings Nov 19 '12 at 13:57
  • ALSO Very important - Scrolling with the mouse(emulator) - doesn't mess up the list at all. Only dragging the list up and down(like a user would, touching the screen and dragging down and letting go) - thats when the list messes up. – shecodesthings Nov 19 '12 at 14:12
  • Hi I'm selecting your answer and the reference to your sample code as the answer to this. I managed to make it work. Originally I had 2 holder patterns - I changed it to one like in your code - so I'm using a ViewHolder pattern as well. In your sample code you set convertView.setTag(viewHolder) - which is what I changed it to and I scrapped my use of view groups and just inflate and assign to the convertView instead and return that at the end of the method. Thanks for all your help LuksProg, there is no doubt you have helped me in the past too! – shecodesthings Nov 20 '12 at 14:21
1

try this code may this will help you...

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;
Animesh Sinha
  • 1,045
  • 9
  • 16