Skip to main content

BnScroll

Namespace: BlazorNative.Components

A scrolling viewport. Renders as a native ScrollView on Android and a UIScrollView on iOS. It is a flex item (BnLayoutItem.Grow, BnLayoutItem.Shrink, BnLayoutItem.Basis, BnLayoutItem.AlignSelf, the box, BnLayoutItem.Margin, BnLayoutItem.Position) that scrolls its content.

public sealed class BnScroll : BnLayoutItem, Microsoft.AspNetCore.Components.IComponent, Microsoft.AspNetCore.Components.IHandleEvent, Microsoft.AspNetCore.Components.IHandleAfterRender

Inheritance Object → ComponentBase → BnLayoutItem → BnScroll
Implements IComponent, IHandleEvent, IHandleAfterRender
Attributes NullableContextAttribute, NullableAttribute

Remarks:

Not a flex container. There is no Direction, Justify, Align, Wrap, Gap or Padding parameter: those would style the viewport itself rather than the content inside it — they would space nothing, or push the content to a negative offset a scroll view can never scroll back to. To lay out the content, put a BnColumn inside: <BnScroll Height="200"><BnColumn Gap="8">…</BnColumn></BnScroll>. Both platforms ignore those style names on a scroll node, so there is no way around it.

Vertical only. Horizontal scrolling is a different widget class on Android, and is not supported rather than half-supported.

Give it a definite height. An auto-height BnScroll takes its height from its content, so the viewport equals the content and nothing scrolls; the shells log one warning when that happens. Use an explicit BnLayoutItem.Height, or — inside a parent with a definite height — Grow="1" Basis="0" (CSS's flex: 1).

alone is not enough, and it is the mistake everybody makes here. With BnLayoutItem.Basis left at auto, the scroll node's flex basis is its content's height, so the free space against a shorter parent is negative — and BnLayoutItem.Grow only distributes positive free space. The negative goes to the shrink pass, and Yoga's BnLayoutItem.Shrink default is 0, so nothing shrinks: the viewport keeps its content's full height, overflows its parent, and does not scroll. Basis="0" (or Shrink="1") is what fixes it — which is exactly why CSS's flex: 1 shorthand sets the basis to 0.

Your children are re-parented into a content node inside the viewport, whose height is the total content height — that is what the platform scrolls.

Properties​

OnScroll​

Raised with the vertical content offset, in dp on Android and pt on iOS, as the viewport scrolls. Optional: nothing is attached to the native control unless you supply a handler.

Events are conflated, not queued — at most one per rendered frame, latest offset wins. A slow handler therefore sees fewer, fresher events rather than a growing backlog, so you cannot use this to count scroll ticks.

The offset arrives raw. iOS rubber-banding can report a negative offset, or one past the end of the scroll range. Clamp it if your maths depends on it being inside the content.

public EventCallback<BnScrollEventArgs> OnScroll { get; set; }

Property Value​

EventCallback<BnScrollEventArgs>

AutoScrollToEnd​

Scroll to the end of the content on every render, for append-driven views — a log tail, a chat transcript, console output — where new content arriving below the fold should bring itself into view. Default false.

Every render, not every append. This component cannot see that your content grew; it only knows it re-rendered. So a re-render for an unrelated reason also scrolls to the end. That is usually what a view with this switched on wants, but it is why it is a parameter you choose rather than a default — if you need "only when items were added", call BnScroll.ScrollToEndAsync() yourself at the point you add them.

public bool AutoScrollToEnd { get; set; }

Property Value​

Boolean

ChildContent​

The content to scroll. Wrap it in a BnColumn to give it a gap, a padding or an alignment — this component will not do that for you.

public RenderFragment? ChildContent { get; set; }

Property Value​

RenderFragment

BackgroundColor​

Fill colour behind the component. Null leaves it transparent.

public string? BackgroundColor { get; set; }

Property Value​

String

Margin​

Space outside the component, between it and its siblings. Null = none.

public BnAutoLength? Margin { get; set; }

Property Value​

BnAutoLength?

Remarks:

auto is legal here and absorbs free space, which re-centres the node.

AlignSelf​

Cross-axis alignment for this item alone, overriding the parent's. Null = inherit.

public FlexAlign? AlignSelf { get; set; }

Property Value​

FlexAlign?

Grow​

Share of leftover space this item takes (unitless ratio). Null = Yoga's default (0).

public float? Grow { get; set; }

Property Value​

Single?

Shrink​

Share of overflow this item gives up (unitless ratio). Null = Yoga's default (1).

public float? Shrink { get; set; }

Property Value​

Single?

Basis​

Starting main-axis size before grow/shrink. Null = auto.

public BnAutoLength? Basis { get; set; }

Property Value​

BnAutoLength?

Width​

Box width. Null = auto.

public BnAutoLength? Width { get; set; }

Property Value​

BnAutoLength?

Height​

Box height. Null = auto.

public BnAutoLength? Height { get; set; }

Property Value​

BnAutoLength?

MinWidth​

Lower bound on width. Null = unset.

public BnLength? MinWidth { get; set; }

Property Value​

BnLength?

MaxWidth​

Upper bound on width. Null = unset.

public BnLength? MaxWidth { get; set; }

Property Value​

BnLength?

MinHeight​

Lower bound on height. Null = unset.

public BnLength? MinHeight { get; set; }

Property Value​

BnLength?

MaxHeight​

Upper bound on height. Null = unset.

public BnLength? MaxHeight { get; set; }

Property Value​

BnLength?

Position​

Positioning scheme. Null = Yoga's default (relative).

public FlexPosition? Position { get; set; }

Property Value​

FlexPosition?

Top​

Top inset. Null = unset.

public BnLength? Top { get; set; }

Property Value​

BnLength?

Right inset. Null = unset.

public BnLength? Right { get; set; }

Property Value​

BnLength?

Bottom​

Bottom inset. Null = unset.

public BnLength? Bottom { get; set; }

Property Value​

BnLength?

Left​

Left inset. Null = unset.

public BnLength? Left { get; set; }

Property Value​

BnLength?

Constructors​

BnScroll()​

public BnScroll()

Methods​

ScrollToAsync(Single)​

Scrolls to offset — dp on Android, pt on iOS, the same units BnScroll.OnScroll reports. An offset outside the content is clamped by the platform, not rejected here.

public ValueTask ScrollToAsync(float offset)

Parameters​

offset Single
The vertical content offset to scroll to.

Returns​

ValueTask
A task that completes when the command has been QUEUED for the next frame — not when the view has finished moving. Use BnScroll.OnScroll to observe where it actually landed.

ScrollToEndAsync()​

Scrolls to the end of the content.

public ValueTask ScrollToEndAsync()

Returns​

ValueTask
A task that completes when the command has been QUEUED for the next frame — not when the view has finished moving.

Remarks:

The end is computed by the shell, not here: content height is a layout result the platform holds, so an offset computed on this side would be one frame stale — exactly wrong for the append-driven case this exists to serve.