Updating a Manager's Extent in onSublayout

Summary

When you override onSublayout ( width, height ) in a manager, you must be aware that the extent of the manager may need to be updated at some point in onSublayout. In HorizontalManagers, width changes could require the height to be updated (ie. when a RichTextField wraps to a new line). In VerticalManagers, changes in height could require the width to be updated. Updating the extent only takes a call to setExtent ( width, height ).

An Example

A RichTextField is added to an AbstractHorizontalFieldManager. In onSublayout, the RichTextField is shifted to the left so that its text wraps to a new line. Since the line wrap did not occur in the call to super.onSublayout, the extent of my manager does not include the extra height needed by the wrapped line of the RichTextField. In order to correctly update my manager's height, I need to call setExtent ( getWidth(), RichTextField.getHeight() ) after I've called layoutChild ( RichTextField, width, height ).

Another Example

I have a section called ContactSection that is an AbstractHorizontalFieldManager. ContactSection has an InnerManager that is also an AbstractHorizontalFieldManager. InnerManager contains a LabelField and a ContentManager that is an AbstractVerticalFieldManager.

ContactSection.java
public abstract class ContactSection extends AbstractHorizontalFieldManager implements StyledField {

    private Contact contact;

    private String label;

    private AbstractHorizontalFieldManager innerManager;
    private AbstractVerticalFieldManager contentManager;

    private StyleManager styleManager;

    public ContactSection(String label, Contact contact) {

        super( USE_ALL_WIDTH | NO_HORIZONTAL_SCROLL );

        setLabel( label );
        setContact( contact );

        // this must be called before applyComputedStyle
        setInnerManager( new InnerManager() );

        applyComputedStyle();
    }  

    protected final void addFields() {

        super.add( getInnerManager() );
    }

    public void add( Field field ) {

        AbstractVerticalFieldManager contentManager = getContentManager();
        contentManager.add( field );
    }

    protected void onSublayout( int width, int maxHeight ) {

        int height = 0;

        Manager manager = getManager();
        if ( manager instanceof ContactDetailTab ) {

            ContactDetailTab contactDetailTab = (ContactDetailTab) manager;
            width -= contactDetailTab.getVerticalScrollbar().getScrollbarWidth();
        }

        Manager innerManager = getInnerManager();
        if ( innerManager != null && equals( innerManager.getManager() ) ) {

            ComputedStyle computedStyle = getStyleManager().getComputedStyle();

            // padding is really the margin for the inner manager
            Edges padding = computedStyle.getPadding();

            int fieldWidth = width - padding.getWidth();
            layoutChild( innerManager, fieldWidth, maxHeight );

            height = innerManager.getHeight();
        }

        setExtent( width, height );
    }

    private class InnerManager extends AbstractHorizontalFieldManager {

        private LabelField labelField;

        public InnerManager() {

            super( NO_HORIZONTAL_SCROLL );
        }

        protected void addFields() {

            add( getLabelField() );
            add( getContentManager() );
        }

        protected void onSublayout( int width, int maxHeight ) {

            int height = 0;

            int sectionHeaderWidth = 0;

            LabelField labelField = getLabelField();
            if ( labelField != null && equals( labelField.getManager() ) ) {

                ComputedStyle computedStyle = labelField.getStyleManager().getComputedStyle();
                sectionHeaderWidth = ContactPainter.instance().getSectionHeaderWidth( computedStyle );

                int fieldWidth = labelField.getPreferredWidth();
                int fieldHeight = labelField.getPreferredHeight();
                layoutChild( labelField, fieldWidth, fieldHeight );

                int fieldX = sectionHeaderWidth - fieldWidth;
                setPositionChild( labelField, fieldX, 0 );
            }

            Manager contentManager = getContentManager();
            if ( contentManager != null && equals( contentManager.getManager() ) ) {

                XYRect extent = contentManager.getExtent();

                int fieldWidth = width - sectionHeaderWidth;

                layoutChild( contentManager, fieldWidth, maxHeight );
                setPositionChild( contentManager, sectionHeaderWidth, extent.y );

                height = contentManager.getHeight();
            }

            setExtent( width, height );
        }
    }

    private class ContentManager extends AbstractVerticalFieldManager {

       ...
    }

1) ContactSection - onSublayout

If you look in the ContactSection's onSublayout, you see that we subtract from the manager's width in order to account for the VerticalScrollbar. This width change can, and does, cause a change in the amount of height this section requires. Once again, the added height comes from the wrapping of RichTextFields. As you see, we call setExtent ( width, InnerManager.getHeight() ) after the call to layout InnerManager to ensure that the section has enough height after the width has been changed.

2) InnerManager - onSublayout

If you look in InnerManager's onSublayout, a similar situation occurs. We subtract sectionHeaderWidth from the manager's width when we layout ContentManager. Once again, this reduction in width requires more height. This is accomplished by calling setExtent( width, contentManager.getHeight() ) after the call to layout ContentManager.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.

© 2011 Metova, Inc.