Scrolling and communicating with the UI
This page covers the older Java codegen-based Sections API. If using the Kotlin Lazy Collection API, refer to the interactions docs for Lazy Collection for similar relevant content.
Introductionβ
Data flows through the section hierarchy before they are eventually represented on the UI by components. Section provides a set of functionalities to allow you to respond to the data and interact with the UI.
@OnRefreshβ
A method annotated with this annotation will be called when the the UI rendered by the section's hierarchy is requesting for a refresh of the content.
APIβ
Call SectionTree#refresh()
to propagate your refresh request to all the sections in the hierarchy. Then you can handle it in your section like this:
class SectionSpec {
@OnRefresh
static void onRefresh(SectionContext c, @Prop yourProp, @State yourState) {
// Handle your refresh request
}
}
@OnViewportChangedβ
A method annotated with this annotation will be called when there is a change in the visible viewport.
APIβ
Call SectionTree#viewPortChanged()
or SectionTree#viewPortChangedFromScrolling()
to allow your sections to know that something on the viewport is now different.
class SectionSpec {
@OnViewportChanged
static void onViewportChanged(
SectionContext c,
int firstVisiblePosition,
int lastVisiblePosition,
int totalCount,
int firstFullyVisibleIndex,
int lastFullyVisibleIndex,
@Prop YourProp prop,
@State YourState state) {
}
}
firstVisiblePosition
Position of the first visible components in the viewport. Components are partially hidden from the visible viewport.lastVisiblePosition
Position of the last visible components in the viewport. Components are partially hidden from the visible viewport.totalCount
Total number of items in the section's hierarchy, with the section that contains the annotated method as its root.firstFullyVisibleIndex
Position of the first fully visible components in the viewport.lastFullyVisibleIndex
Position of the last fully visible components in the viewport.
Change in Viewportβ
A viewport change could occur due to any number of the following reasons:
- Components added to the visible viewport.
- Components removed from the visible viewport.
- Scrolling.
- Components in the visible viewport are updated.
- Components have moved in or out of the visible viewport.
Positions and Countsβ
Positions and total count returned are with respect to the number of components this section has. For example:
Section A
/ \
Section B Section C
| |
10 items 10 items
(visible) (hidden)
When the first item of Section C comes into the viewport due to scrolling, firstVisiblePosition
of Section C
is 0 while the lastVisiblePosition
of Section B
is 10.
Section A has a total of 20 items while Section B and C have 10 each.
@OnDataBoundβ
A method annotated with this annotation will be called when the data changes corresponding to this
section's hierarchy is made available to the SectionTree.Target
.
Data changes could occur due to any number of the following:
- Insertion
- Update
- Delete
- Move
Availability of these data changes do not mean they are visible on the viewport.
To detect visibility, use @OnViewportChanged
.
class SectionSpec {
@OnDataBound
static void OnDataBound(
SectionContext c,
@Prop YourProp prop
@State YourState state) {
// Handle data changes
}
}
Scrolling: requestFocus()β
Use this method to give focus to one of the components in a section. If the component is hidden from the visible viewport, the section will be scrolled to reveal it, thereby calling the @OnViewportChanged
annotated method.
The data that renders the component being requested for focus has to be available before the method can work. Hence, only use requestFocus()
after the @OnDataBound
annotated method has been called.
APIβ
There a few variations of the requestFocus()
method.
SectionLifecycle.requestFocus(SectionContext c, int index)β
Calls focus by the index of the Component
in the Section
scoped by the given SectionContext
As with @OnViewportChanged
, the index is with respect to the number of components this section has.
SectionLifecycle.requestFocus(SectionContext c, String sectionKey)β
Calls focus to the first index of the component in the section represented by the section's key you provided.
SectionLifecycle.requestFocusWithOffset(SectionContext c, int index, int offset)β
Same as SectionLifecycle.requestFocus(SectionContext c, int index)
but with an offset.
SectionLifecycle.requestFocusWithOffset(SectionContext c, String sectionKey, int offset)β
Same as SectionLifecycle.requestFocus(SectionContext c, String sectionKey)
but with an offset.
SectionLifecycle.requestFocus(SectionContext c, String sectionKey, FocusType focusType)β
FocusType
is either:
FocusType.START
Calls focus to the first index of the component in the sectionFocusType.END
Calls focus to the last index of the component in the section
SectionLifecycle.requestSmoothFocus(SectionContext c, int index, SmoothScrollAlignmentType type)β
Use this variation if you need to specify a snapping mode.
SmoothScrollAlignmentType
is either:
SNAP_TO_ANY
SNAP_TO_START
SNAP_TO_END
SNAP_TO_CENTER
For the full list of methods available to request scroll to a position, check out the SectionLifecycle documentation.
@OnEvent(LoadingEvent.class)β
Sections should use this annotation to declare a method to receive events about its children loading state.
APIβ
class YourSectionSpec {
@OnCreateChildren
protected static Children onCreateChildren(SectionContext c) {
return Children.create()
.child(
ChildSection
.create(c)
.loadingEventHandler(YourSection.onLoadingEvent(c)))
.build();
}
@OnEvent(LoadingEvent.class)
static void onLoadingEvent(
SectionContext c,
@FromEvent LoadingState loadingState,
@FromEvent boolean isEmpty,
@FromEvent Throwable t) {
switch (loadingState) {
case INITIAL_LOAD:
case LOADING:
// Handle loading
break;
case FAILED:
// Handle failure
break;
case SUCCEEDED:
// Handle success
break;
}
// Dispatch the same loading event up the hierarchy.
SectionLifecycle.dispatchLoadingEvent(
c,
isEmpty,
loadingState,
t);
}
}
LoadingState loadingStateβ
INITIAL_LOAD
Loading has startedLOADING
Loading is still ongoingSUCCEEDED
Loading is successfulFAILED
Loading has failed.
boolean isEmptyβ
Returns true if the data set is empty after the loading event
Throwable tβ
Returns the reason for a LOAD_FAILED
event
Dispatch up the hierarchyβ
The loading event will be passed up the hierarchy until there is a section that has chosen to handle it. If your section handles the loading event, it has to dispatch the event up its hierarchy if there are parent sections looking to handle it as well.
SectionLifecycle.dispatchLoadingEvent(c, isEmpty, loadingState, t);