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 ObjectComponentBaseBnLayoutItemBnScroll
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.