public class StickyHeaderContainer
ImplementsAnimation, Editable, Iterable<Component>, StyleListener
A scrollable container that pins the most recently scrolled-past section
header to the top of its viewport, in the style of the iOS contacts list
or sectioned material lists. As the next section’s header rises into the
pinned slot the previous header is replaced through a configurable
scroll-driven transition: a directional slide where the rising header
pushes the pinned one up and out, or a cover where the rising header
progressively slides on top of the pinned one. The outgoing header can
optionally fade out alongside either transition via
setHeaderFadeOut(boolean). Transitions are driven by scroll position
so the visual stays in sync with the user’s gesture and there is no
time-based animation that lags behind a slow drag or skips ahead on a
fling.
Sections are added with addSection(header, content). The header is a
real component that participates in the scroll: when it is the active
section’s header it is moved into a pinned overlay slot at the top of
the container, and a same-sized invisible placeholder is left behind in
the scroll content so nothing jumps. Because the pinned header is the
same instance, action listeners and child components remain interactive
while it is pinned.
StickyHeaderContainer sticky = new StickyHeaderContainer();
sticky.setTransitionStyle(StickyHeaderContainer.TRANSITION_SLIDE);
for (char c = 'A'; c <= 'Z'; c++) {
Label header = new Label("" + c, "StickyHeader");
Container items = new Container(BoxLayout.y());
for (int i = 0; i < 5; i++) {
items.add(new Label(c + " entry " + i));
}
sticky.addSection(header, items);
}
form.add(BorderLayout.CENTER, sticky);
Fields
public static final int TRANSITION_NONE = 0 | Replace the pinned header without any visible movement of the pinned header. |
public static final int TRANSITION_SLIDE = 1 | As the next section’s header rises into the pinned slot from below it pushes the pinned header up and out of the slot in sync with the scroll, replacing it once the rising header reaches the top. |
public static final int TRANSITION_FADE = 2 | Convenience equivalent to TRANSITION_SLIDE combined with setHeaderFadeOut(boolean) set to true: the pinned header both slides up and fades to transparency as the rising header closes the gap. |
public static final int TRANSITION_COVER = 3 | As the next section’s header rises into the pinned slot from below it progressively slides on top of the pinned header, covering it from the bottom up while the pinned header stays fixed in the slot. |
Constructors
public StickyHeaderContainer() | Creates an empty sticky header container. |
Methods
public void paint(Graphics g) | Paints the COVER overlay on top of the pinned slot: when the transition style is TRANSITION_COVER and a push is in flight, the rising section’s header is rendered again above the pinned host so it visibly slides over the pinned header instead of being hidden underneath it. |
public StickyHeaderContainer addSection(Component header, Component content) | Adds a section consisting of a sticky header and its content. |
public StickyHeaderContainer addSection(Component header) | Adds a header-only section. |
public Container getScrollContainer() | Returns the inner scrolling container that hosts the section content. |
public Container getStickyHost() | Returns the overlay container that hosts the currently-pinned header. |
public List<Component> getStickyHeaders() | Returns an unmodifiable view of the registered sticky headers in the order they were added. |
public int getActiveSectionIndex() | Returns the index of the currently pinned section, or -1 if no header is currently pinned. |
public void setTransitionStyle(int style) | Selects how the pinned header is replaced when the next section rises into the slot. |
public int getTransitionStyle() | |
public void setHeaderFadeOut(boolean fade) | When true the pinned header fades to transparency in proportion to the push progress as the next section rises into the slot. |
public boolean isHeaderFadeOut() | Returns whether the pinned header is configured to fade out during a swap. |
public void setTransitionDurationMillis(int millis) | Retained for API compatibility. |
public int getTransitionDurationMillis() | |
public boolean isTransitionInProgress() | Returns true while the next section’s header is overlapping the pinned slot, i.e. the scroll-driven transition is mid-flight. |
public float getTransitionProgress() | Returns the progress of the in-flight transition as a fraction in [0, 1]: 0 when the next section is just touching the slot from below and 1 when it has fully displaced the pinned header. |
public void setScrollPosition(int y) | Sets the scroll position of the inner scroll container. |
public int getScrollPosition() | Returns the current scroll position of the inner scroll container. |
public void clearSections() | Removes all sections and content from the container. |
public void updateSticky() | Recomputes which section header should be pinned and how far the next section has displaced it. |
Inherited fields
From Component
DEFAULT_CURSOR, CROSSHAIR_CURSOR, TEXT_CURSOR, WAIT_CURSOR, SW_RESIZE_CURSOR, SE_RESIZE_CURSOR, NW_RESIZE_CURSOR, NE_RESIZE_CURSOR, N_RESIZE_CURSOR, S_RESIZE_CURSOR, W_RESIZE_CURSOR, E_RESIZE_CURSOR, HAND_CURSOR, MOVE_CURSOR, DRAG_REGION_NOT_DRAGGABLE, DRAG_REGION_POSSIBLE_DRAG_X, DRAG_REGION_POSSIBLE_DRAG_Y, DRAG_REGION_POSSIBLE_DRAG_XY, DRAG_REGION_LIKELY_DRAG_X, DRAG_REGION_LIKELY_DRAG_Y, DRAG_REGION_LIKELY_DRAG_XY, DRAG_REGION_IMMEDIATELY_DRAG_X, DRAG_REGION_IMMEDIATELY_DRAG_Y, DRAG_REGION_IMMEDIATELY_DRAG_XY, BRB_CONSTANT_ASCENT, BRB_CONSTANT_DESCENT, BRB_CENTER_OFFSET, BRB_OTHER, CENTER, TOP, LEFT, BOTTOM, RIGHT, BASELINE
Inherited methods
From Container
encloseIn, encloseIn, initLaf, getUIManager, setUIManager, isSurface, add, addAll, add, add, add, add, add, getLeadComponent, setLeadComponent, getLeadParent, keyPressed, keyReleased, getLayout, setLayout, invalidate, setShouldLayout, setShouldCalcPreferredSize, getLayoutWidth, getLayoutHeight, applyRTL, constrainWidthWhenScrollable, constrainHeightWhenScrollable, addComponent, addComponent, addComponent, addComponent, replaceAndWait, replaceAndWait, replace, replaceAndWait, replace, createReplaceTransition, isEnabled, setEnabled, removeComponent, cancelRepaints, flushReplace, removeAll, revalidateWithAnimationSafety, revalidate, revalidateLater, forceRevalidate, clearClientProperties, paintGlass, layoutContainer, isSafeArea, setSafeArea, isSafeAreaRoot, getSafeAreaRoot, setSafeAreaRoot, getComponentCount, getComponentAt, getComponentIndex, contains, scrollComponentToVisible, getClosestComponentTo, getResponderAt, getComponentAt, findDropTargetAt, pointerPressed, calcPreferredSize, paramString, refreshTheme, isScrollableX, setScrollableX, isScrollableY, setScrollableY, getSideGap, getBottomGap, setScrollable, setCellRenderer, getScrollIncrement, setScrollIncrement, findFirstFocusable, dragInitiated, fireClicked, isSelectableInteraction, getGridPosY, paintComponentBackground, getGridPosX, animateHierarchyAndWait, createAnimateHierarchy, animateHierarchy, animateHierarchyFadeAndWait, createAnimateHierarchyFade, animateHierarchyFade, animateLayoutFadeAndWait, createAnimateLayoutFadeAndWait, animateLayoutFade, createAnimateLayoutFade, animateLayoutAndWait, animateLayout, updateTabIndices, createAnimateLayout, drop, createAnimateMotion, morph, morphAndWait, animateUnlayout, animateUnlayoutAndWait, createAnimateUnlayout, getChildrenAsList, iterator, iterator
From Component
setSameSize, isSetCursorSupported, parsePreferredSize, getDefaultDragTransparency, setDefaultDragTransparency, getEditingDelegate, setEditingDelegate, getCursor, setCursor, showNativeOverlay, hideNativeOverlay, updateNativeOverlay, getNativeOverlay, getAllStyles, getSameWidth, setSameWidth, getSameHeight, setSameHeight, getX, setX, getOuterX, getInnerX, getY, setY, getOuterY, getInnerY, isVisible, setVisible, getClientProperty, stripMarginAndPadding, putClientProperty, getDirtyRegion, setDirtyRegion, isOpaque, setOpaque, getWidth, setWidth, getOuterWidth, getInnerWidth, getHeight, setHeight, getOuterHeight, getInnerHeight, isDragRegion, getDragRegionStatus, getBaseline, getBaselineResizeBehavior, getPreferredSizeStr, setPreferredSizeStr, getPreferredSize, setPreferredSize, getScrollDimension, calcScrollSize, setScrollSize, getPreferredW, setPreferredW, getPreferredH, setPreferredH, getOuterPreferredH, getInnerPreferredH, getOuterPreferredW, getInnerPreferredW, setSize, getUIID, setUIID, setUIIDFinal, setUIID, getInlineAllStyles, setInlineAllStyles, getInlineSelectedStyles, setInlineSelectedStyles, getInlineUnselectedStyles, setInlineUnselectedStyles, getInlineDisabledStyles, setInlineDisabledStyles, getInlinePressedStyles, setInlinePressedStyles, remove, getParent, getOwner, setOwner, isOwnedBy, containsOrOwns, addFocusListener, removeFocusListener, addScrollListener, removeScrollListener, getSelectCommandText, setSelectCommandText, getLabelForComponent, setLabelForComponent, focusGained, focusLost, paintBackgrounds, paintShadows, getAbsoluteX, getAbsoluteY, isInClippingRegion, paintIntersectingComponentsAbove, paintScrollbars, paintScrollbarX, getScrollOpacity, getSelectedRect, paintScrollbarY, paintComponent, paintComponent, getBorder, getScrollable, paintBackground, isScrollable, getScrollX, setScrollX, getScrollY, setScrollY, onScrollX, onScrollY, getDraggedx, getDraggedy, contains, visibleBoundsContains, hasFixedPreferredSize, getBounds, getBounds, getVisibleBounds, getVisibleBounds, isFocusable, setFocusable, onSetFocusable, resetFocusable, getTabIndex, setTabIndex, getPreferredTabIndex, setPreferredTabIndex, isTraversable, setTraversable, handlesInput, setHandlesInput, consumesRawTextInput, hasFocus, setFocus, getComponentForm, getTopLevelContainer, repaint, repaint, longKeyPress, keyRepeated, registerForAnimation, deregisterFromAnimation, getAnimationManager, getScrollAnimationSpeed, setScrollAnimationSpeed, isBlockLead, setBlockLead, isIgnorePointerEvents, setIgnorePointerEvents, isRippleEffect, setRippleEffect, getInlineStylesTheme, setInlineStylesTheme, shouldRenderComponentSelection, isHideInLandscape, setHideInLandscape, createStyleAnimation, isSmoothScrolling, setSmoothScrolling, pointerHover, stopScrollMomentum, pointerHoverReleased, pointerHoverPressed, pinch, pinchReleased, pinch, rotation, isPinchBlocksDragAndDrop, setPinchBlocksDragAndDrop, pointerDragged, getDragImage, getDragTransparency, setDragTransparency, toImage, drawDraggedImage, draggingOver, dragEnter, dragExit, addPullToRefresh, setPullToRefresh, respondsToPointerEvents, pointerDragged, isStickyDrag, pointerPressed, isDragAndDropOperation, pointerReleased, longPointerPress, pointerReleased, setVerticalScrollBounds, setHorizontalScrollBounds, isVScrollThumbGrabbed, isHScrollThumbGrabbed, isVScrollThumbHover, isHScrollThumbHover, isTensileDragEnabled, setTensileDragEnabled, getTextSelectionSupport, addDropListener, removeDropListener, addDragOverListener, removeDragOverListener, isNativeDragSource, setNativeDragSource, getNativeDragOperation, setNativeDragOperation, createNativeDragOperation, isNativeDropTarget, setNativeDropTarget, getAcceptedDropMimeTypes, setAcceptedDropMimeTypes, getAcceptedDropActions, setAcceptedDropActions, canAcceptNativeDrop, nativeDragEnter, nativeDragOver, nativeDragExit, nativeDrop, addNativeDropListener, removeNativeDropListener, addNativeDragOverListener, removeNativeDragOverListener, dragFinished, addDragFinishedListener, addStateChangeListener, removeStateChangeListener, addPointerPressedListener, addLongPressListener, addContextMenuListener, removeContextMenuListener, addMouseWheelListener, removeMouseWheelListener, addStylusListener, removeStylusListener, mouseWheel, paintRippleOverlay, removePointerPressedListener, removeLongPressListener, removeDragFinishedListener, addPointerReleasedListener, removePointerReleasedListener, addPointerDraggedListener, removePointerDraggedListener, getDragSpeed, getStyle, getPressedStyle, setPressedStyle, initUnselectedStyle, initPressedStyle, initDisabledStyle, initSelectedStyle, getUnselectedStyle, setUnselectedStyle, getSelectedStyle, setSelectedStyle, getDisabledStyle, setDisabledStyle, installDefaultPainter, requestFocus, toString, refreshTheme, refreshTheme, isDragActivated, animate, scrollRectToVisible, scrollRectToVisible, paintBorder, paintBorderBackground, isCellRenderer, isScrollVisible, setScrollVisible, setIsScrollVisible, startEditingAsync, stopEditing, isEditing, isEditable, laidOut, deinitialize, initComponent, isInitialized, setInitialized, styleChanged, getNextFocusDown, setNextFocusDown, getNextFocusUp, setNextFocusUp, getNextFocusLeft, setNextFocusLeft, getNextFocusRight, setNextFocusRight, getName, setName, initCustomStyle, deinitializeCustomStyle, isRTL, setRTL, isTactileTouch, isTactileTouch, setTactileTouch, getPropertyNames, getPropertyTypes, getPropertyTypeNames, getPropertyValue, setPropertyValue, paintLockRelease, paintLock, isSnapToGrid, setSnapToGrid, shouldBlockSideSwipe, shouldBlockSideSwipeLeft, shouldBlockSideSwipeRight, blocksSideSwipe, isFlatten, setFlatten, getTensileLength, setTensileLength, isGrabsPointerEvents, setGrabsPointerEvents, getScrollOpacityChangeSpeed, setScrollOpacityChangeSpeed, growShrink, isAlwaysTensile, setAlwaysTensile, isDraggable, setDraggable, isDropTarget, setDropTarget, isChildOf, isHideInPortrait, setHideInPortrait, getBindablePropertyNames, getBindablePropertyTypes, bindProperty, unbindProperty, getBoundPropertyValue, setBoundPropertyValue, getCloudBoundProperty, setCloudBoundProperty, getCloudDestinationProperty, setCloudDestinationProperty, getComponentState, setComponentState, setHidden, isHidden, setHidden, isHidden, announceForAccessibility, getAccessibilityText, setAccessibilityText, getSemantics, getAccessibilityNode, accessibilityChanged, accessibilityChanged, getTooltip, setTooltip
Field details
TRANSITION_NONE
public static final int TRANSITION_NONE = 0TRANSITION_COVER is a more
useful choice, since with TRANSITION_NONE the rising header
disappears under the pinned one with no visual feedback that the
swap is approaching. Kept for backward compatibility.TRANSITION_SLIDE
public static final int TRANSITION_SLIDE = 1TRANSITION_FADE
public static final int TRANSITION_FADE = 2TRANSITION_SLIDE combined with
setHeaderFadeOut(boolean) set to true: the pinned header
both slides up and fades to transparency as the rising header
closes the gap. Prefer composing
setTransitionStyle(TRANSITION_SLIDE) with
setHeaderFadeOut(true) – or
setTransitionStyle(TRANSITION_COVER) with
setHeaderFadeOut(true) – when you want a fade-out on top of
another transition. Kept for backward compatibility.TRANSITION_COVER
public static final int TRANSITION_COVER = 3setHeaderFadeOut(boolean) to also fade the covered header out
during the overlap.Constructor details
StickyHeaderContainer
public StickyHeaderContainer()addSection(header, content).Method details
paint
public void paint(Graphics g)TRANSITION_COVER and a push is in flight,
the rising section’s header is rendered again above the pinned
host so it visibly slides over the pinned header instead of
being hidden underneath it. The natural paint in the scroller is
at the same viewport position, so re-painting the header after
super.paint(g) simply moves it to the top of the z-order in
the slot region; outside that region the second paint draws over
identical scroller content and is invisible. No-op for any other
transition style or when no swap is mid-flight.Parameters
gGraphics- the component graphics
addSection
public StickyHeaderContainer addSection(Component header, Component content)null for a header-only section. Returns this for
chaining.addSection
public StickyHeaderContainer addSection(Component header)getScrollContainer
public Container getScrollContainer()setScrollPosition(int).getStickyHost
public Container getStickyHost()getStickyHeaders
public List<Component> getStickyHeaders()getActiveSectionIndex
public int getActiveSectionIndex()-1 if no
header is currently pinned.setTransitionStyle
public void setTransitionStyle(int style)TRANSITION_NONE, TRANSITION_SLIDE
(default), TRANSITION_FADE or TRANSITION_COVER. The fade-out
of the pinned header is a separate, composable concern controlled
by setHeaderFadeOut(boolean).getTransitionStyle
public int getTransitionStyle()setHeaderFadeOut
public void setHeaderFadeOut(boolean fade)true the pinned header fades to transparency in proportion
to the push progress as the next section rises into the slot.
This is independent of the transition style and composes with
TRANSITION_SLIDE (slide + fade), TRANSITION_COVER (cover +
fade) and TRANSITION_NONE (fade only). TRANSITION_FADE
implies the fade-out behaviour regardless of this flag.
Defaults to false.isHeaderFadeOut
public boolean isHeaderFadeOut()setHeaderFadeOut(boolean).setTransitionDurationMillis
public void setTransitionDurationMillis(int millis)getTransitionDurationMillis
public int getTransitionDurationMillis()isTransitionInProgress
public boolean isTransitionInProgress()getTransitionProgress
public float getTransitionProgress()[0, 1]: 0 when the next section is just touching the slot from
below and 1 when it has fully displaced the pinned header.
Returns 0 when no transition is in progress.setScrollPosition
public void setScrollPosition(int y)getScrollPosition
public int getScrollPosition()clearSections
public void clearSections()updateSticky
public void updateSticky()