0

I have a custom component that extends RelativeLayout which in turns holds a GridLayout(named mFormLayout). I have a public method that adds two spinners with their proper adapter source and an imageview which acts as a button to remove rows.

public class EditableTwinSpinnerGridForm extends EditableGridForm
{
    public void addTwinSpinnerRow(final Locale.MapKey spinner1DefVal, final Locale.MapKey spinner2DefVal)
    {
        Spinner spinner1 = createSpinner(mTSP.getFirstSpinnerRes(), spinner1DefVal.getId());
        spinner1.setOnItemSelectedListener(mTSP.getIsl());

        Spinner spinner2 = createSpinner(mTSP.getSecondSpinnerRes(), spinner2DefVal.getId());


        ImageView rmvBtn = createRemoveBtn();


        mFormLayout.addView(spinner1);
        mFormLayout.addView(spinner2);
        mFormLayout.addView(rmvBtn);
    }
}

For some reason, this method works when I am adding rows from a call to onCreate in an activity, but when I am calling this method after the activity is created(from an onclicklistener) the Spinners are either not there or only one of them shows up. They do take the space because I see the row and the removable image view.

I have also noticed that when I focus on a EditText in the same activity and the keyboard pops up, the added spinners show up when I press back to remove the keyboard.

Here's the code I use to create a spinner :

protected Spinner createSpinner(Integer spinnerSrc, String defaultSpinnerValue)
    {
        Spinner spinner = new Spinner(mCtx, Spinner.MODE_DIALOG);
        // Setting the bg color to the containing color to remove the spinner arrow.
        spinner.setBackgroundResource(R.color.container_bg);

        SparseArray<Phrase> map = Locale.getInstance().getMap(spinnerSrc);
        PhraseArrayAdapter adapter = createSpinnerFromMap(spinnerSrc);
        spinner.setAdapter(adapter);

        if (defaultSpinnerValue.equals(Utilities.EMPTY_STRING) || defaultSpinnerValue.isEmpty())
        {
            throw new IllegalStateException();
        }
        else
        {
            Utilities.getInstance().setMapSpinnerPosByValue(map, defaultSpinnerValue, spinner);
        }

        adapter.setDropDownViewResource(R.layout.editable_spinner_dropdown_item);
        setSpinnerLayoutParams(spinner);

        return spinner;
    }

protected void setSpinnerLayoutParams(Spinner spinner)
    {
        GridLayout.LayoutParams lp = createDefaultGridParams();
        lp.setGravity(Gravity.FILL_HORIZONTAL);
        lp.width = 250;
        lp.rightMargin = 0;
        spinner.setLayoutParams(lp);
    }

The code works when the activity is loaded so I'm a bit stumped. I looked around and some people suggested I set LayoutParams in addView, but why would this method work in onCreate, but not afterwards?

Here's what's happening visually(The first three rows are added from a loop in onCreate(), the two second ones are added by pressing "Add +"). As you can see the second spinner isn't showing up, sometimes both aren't showing up. I also tried calling invalidate and requestLayout to no avail. Snapshot

I had looked into the invalidate method, here's where it is located currently :

public abstract class EditableForm extends RelativeLayout implements ObservableInt
{
    private class OnAddClicked implements OnClickListener
    {
        @Override
        public void onClick(View v)
        {
            onAddClicked(v);
            EditableForm.this.invalidate();
            mFormLayout.invalidate();
        }
    }
}

Which calls(In a subclass of EditableGrid) :

@Override
protected void onAddClicked(View clickedView)
{
    addTwinSpinnerRow();
    notifyObservers(new ObservableData(EDITABLE_ADD_GRID_CLICKED, null));
}

protected void addTwinSpinnerRow()
{
    Locale.MapKey v1 = Locale.getInstance().getMap(mTSP.getFirstSpinnerRes()).get(0).getMapId();
    Locale.MapKey v2 = Locale.getInstance().getMap(mTSP.getSecondSpinnerRes()).get(0).getMapId();
    addTwinSpinnerRow(v1, v2);
}
Patrick.SE
  • 4,444
  • 5
  • 34
  • 44
  • Try calling invalidate() on your layout to force it to redraw, looks like that is your issue. – Nanoc Nov 13 '15 at 15:30

1 Answers1

1

Have you tried calling the Invalidate method of the container view rather than the added view?

Most likely the views you are adding are there, they just need to be drawn which is suggested by your keyboard hide/show difference. Does rotating the device also cause them to appear? If so, this again suggests that you need to redraw your custom layout.

When it's necessary to execute invalidate() on a View?

Community
  • 1
  • 1
Kuffs
  • 35,581
  • 10
  • 79
  • 92
  • I updated my question. I may not be doing the invalidate() in the correct place. Also, on screen rotation any added element vanishes, I hadn't handled screen rotation yet so I can't really comment on this behavior. – Patrick.SE Nov 13 '15 at 15:42
  • I actually think that rather than subclassing a RelativeLayout, you would be better using a view that is designed to have entries added to it (such as a RecyclerView). This would also help you with your screen rotation as well as give you built in control over scrolling etc Doing this you would just add your items to the Adapter then ask the RecyclerView to redraw by calling NotifyDatasetChanged – Kuffs Nov 13 '15 at 15:50
  • Thanks, I will look into it. I've never heard of the RecyclerView. – Patrick.SE Nov 13 '15 at 20:22