Forum Xamarin Xamarin.Android

ExpandableListView - Switching between different layouts/always inflate view?

I'm new to developing on android but I have managed to implemented my own ExpandableListViewAdapter and all that, which works fine. My child items are shown as they should etc. The problem is that each child element is unique, i.e. it uses its own element in the .xml. So I need to switch between xml elements depending on what type the child is. In this particular case all the children items are EditText items, but with different attribute settings. For instance:

Firstname: InputType = "text"
Phonenumber: InputType = "number"

They are both editable text, but they have their own xml-file with respective settings. Switching between layouts works fine, I got that to work. But here comes the problem...The ExpandableListViewAdapter reuses the view if possible, which means that the view is not always showing the correct data since it will only recreate the view if it can't use the previous one. I found one way around this and it was to simply remove the check if the view is null and always inflate it depending on the child type. How will this affect my application when it comes to optimization? Since I now destroy and recreate objects each time instead of reusing the same objects...


public override View GetChildView(int _groupIndex, int _childIndex, bool _isLastchild, View _view, ViewGroup _viewGroup)
{
mCurrentChild = new ExpandListChild ();
mCurrentChild = (ExpandListChild)GetChild (_groupIndex, _childIndex);
EditText mEditText = null;
// if (_view == null)
//{
LayoutInflater tempInflater = (LayoutInflater)this.mContext.GetSystemService (Context.LayoutInflaterService);

            ChildType currentType = mCurrentChild.GetChildType ();
            switch(currentType)
            {
            case ChildType.SimpleText:
                _view = tempInflater.Inflate (Resource.Layout.ProfileSimpleText, null);
                break;
            case ChildType.NumbersOnly:
                _view = tempInflater.Inflate (Resource.Layout.ProfileNumbersOnly, null);
                break;
            case ChildType.LongTextField:
                _view = tempInflater.Inflate (Resource.Layout.ProfileTextBox, null);

                break;
            }
        //}

}

Thanks in advance :)!

Best Answer

Answers

  • ClockWiseClockWise USMember

    Thank you for your reply, confirming that I'm not far off when it comes to usage of ExpandableListViews. The problem is that I have different .axml-files for different types of children, which means that I have to inflate the correct axml-file depending on which child is being created etc. But since the views are reused I will somehow get the children ordered differently. It works fine the first time, but as soon as I close one list and opens another and then opens the first one again it's all ordered differently. I will investigate thoroughly on Monday when I'm at work, but I have yet found a solution for this other than recreating the view each time.

    At least this was the problem a few days ago, now I've been trying a lot of different stuff so not really sure what the problem is since I haven't worked on this part of the software for 2 days ^^! But I will get back with reply and solution if I find one.

  • ClockWiseClockWise USMember
    edited September 2014

    @AndrewWay‌ A few different things have changed since I did this post, but I still have the same issue. It seems that the groupIndex och childIndex are not the correct ones for the view. Right now I have a listener on editText.TextChange which triggers when the user changes the text in the editText object. But when this event is trigger it does not correspond to the correct child index :/

    Here's the updated code:

    public override View GetChildView(int _groupIndex, int _childIndex, bool _isLastchild, View _view, ViewGroup _viewGroup)
    {
    ExpandListProfileChild tempCurrentChild = new ExpandListProfileChild();
    tempCurrentChild = (ExpandListProfileChild)GetChild(_groupIndex, _childIndex);
    EditText tempEditText = null;
    LayoutInflater tempInflater = (LayoutInflater)this.mActivity.GetSystemService(Context.LayoutInflaterService);

            // Only used to make the switch statement easier.
            ChildType currentType = tempCurrentChild.GetChildType();
            if (_view == null)
            {
                switch (currentType)
                {
                    case ChildType.SimpleText:
                        _view = tempInflater.Inflate(Resource.Layout.ProfileSimpleText, null);
                        tempEditText = _view.FindViewById<EditText>(Resource.Id.profileChild);
                        tempEditText.Hint = tempCurrentChild.GetHint();
                        tempEditText.Text = tempCurrentChild.GetDisplayedText();
                        break;
    
                    case ChildType.NumbersOnly:
                        _view = tempInflater.Inflate(Resource.Layout.ProfileNumbersOnly, null);
                        tempEditText = _view.FindViewById<EditText>(Resource.Id.profileChild);
                        tempEditText.Hint = tempCurrentChild.GetHint();
                        tempEditText.Text = tempCurrentChild.GetDisplayedText();
                        break;
    
                    case ChildType.LongTextField:
                        _view = tempInflater.Inflate(Resource.Layout.ProfileTextBox, null);
                        tempEditText = _view.FindViewById<EditText>(Resource.Id.profileChild);
                        tempEditText.Hint = tempCurrentChild.GetHint();
                        tempEditText.Text = tempCurrentChild.GetDisplayedText();
                        break;
    
                }
    
                tempEditText.TextChanged += (sender, e) =>
                {
                    String tempString = e.Text.ToString();
                    tempCurrentChild = (ExpandListProfileChild)GetChild(_groupIndex, _childIndex);
    
                    // Set the new child data.
                    if (tempString != "")
                    {
                        tempCurrentChild.SetDisplayedText(tempString);
                        updateData(_groupIndex, _childIndex);
                    }
                };
            }
    

    In the TextChanged event the editText object does not trigger on the correct group and child indexes, which is weird :/ I could be pressing group 0, child 1, and it will give me goup 2, child 5...

    Would really appreciate if anyone could help me solve this. Thanks in advance :=)!

  • ClockWiseClockWise USMember

    So a quick update: I've localized the problem, but not really sure how to fix it. When opening/closing a list the getChildView will be called once for each child, which is understandably. But since I use an EditText and a listener to when it's changed in my childview, the event will trigger when closing/opening a list since the edittext has been changed. I'm not really sure exactly how this works, but when the TextChanged event is triggered on opening/closing a list it will update wrong children with data even though nothing has actually changed.

    TLDR; The TextChanged event for EditText is triggered when opening/closing a list, since it's text is being changed for each view.

  • ClockWiseClockWise USMember
    edited September 2014

    Fixed a few problems, but there is still the one with views left. It appears that the view is being reused as long as there are enough views to reuse. So let's say that my first main item has 4 sub items and my second main item has 6 sub items and my third main item has 3 sub items, like this:

    Main item 1

    1. sub item
    2. sub item
    3. sub item
    4. sub item

    Main item 2

    1. sub item
    2. sub item
    3. sub item
    4. sub item
    5. sub item
    6. sub item

    Main item 3

    1. sub item
    2. sub item
    3. sub item

    If I expand main item 1 first, and it's the first time any list has been expanded, then the view will be null for each sub item and inflate for each of them - which is exactly what I want. If I then collapse main item 1 and expands main item 2, the first 4 of its sub items will reuse views and not inflate, while the remaining 2 will have views that are null and ends up being inflated. If I then proceed to collapse main item 2 and expand main item 3 it will reuse 3 views and will not inflate. Now this is a problem since I might need 3 different layout inflates on main item 3 which means that they will have the wrong layout inflated since they are reusing views (which in turn have the wrong inflated layout file). I've been working on this on and off for over a week and I can't find a solution other than creating the views every time. Seems like there is no common way of doing this.

  • ClockWiseClockWise USMember

    Final update: So I solved it. I'm not sure if this is appropriate but I could see no other way. Anyway, for the interested, what I did was to simply store a view in each child which I used instead of the parameter from GetChildView. So first I get the view from the current child, if that view is null I inflate it and all that, then set the new inflated view as the child's new view with a set method. That's it. Seems to work fine, and I no longer recreate the views each time either.

Sign In or Register to comment.