Repository navigation
Releases
SkiaUi.Maui 1.11.0
New features
- .NET 11 and MAUI 11: SkiaUi.Maui, SkiaUi.Maui.CommunityToolkit, SkiaUi.Maui.Markdown and SkiaUi.Maui.Markdown.Math target
net11.0-*with MAUI 11.0.10 (Community Toolkit 17.0.0) next tonet10.0-*with MAUI 10, so .NET 10 apps keep restoring the net10 assets and never see MAUI 11. The net11 assets need Android 7.0 (API 24) and build with .NET SDK 11.0.100 and Xcode 27.2; the other minimum OS versions are unchanged. Details and the behaviour differences between the lines: ImplementationPlan-1.11.md.
Breaking changes
- The net10 assets need MAUI 10.0.130: all four packages'
net10.0-*assets now reference MAUI 10.0.130 (was 10.0.120). A .NET 10 app with its ownMicrosoft.Maui.Controlsreference below 10.0.130 must raise it, or restore fails with NU1605 (package downgrade). MAUI 10.0.130 leaves room for a shape's stroke only when it has one (dotnet/maui#37319): a drawn shape withoutStroke(both layers) now fills its bounds and measures withoutStrokeThickness, as MAUI's shapes do, and a stroke appearing or going measures it again.
Other
- Demo Release builds measure without MAUI's visual tree diagnostics: the demo's profiling default sets a diagnostic endpoint, which also turned on MAUI's visual tree diagnostics; those look up each new child's index among its siblings, so building a layout of N children cost O(N²) (a 1,000-button grid built 4× slower on .NET 11 iOS). Non-Debug builds with profiling on now set
EnableMauiDiagnostics=falseand keep the endpoint; Testing.md explains how to do the same in an app. - Headless test suite flake:
SamplesTests.EveryExamplePageIsOneDrawnSurfaceThatLaysOutAndDrawsfailed about one run in three withCollection was modifiedwhile disposing a surface. The Markdown example's background build handed its result toSkUiTestHelpers.UseTestDispatcher(), whoseDispatchran it inline on the calling pool thread, so the document's Core tree changed while the test tore it down. The package is unchanged (with a real dispatcher the result goes on the UI thread); the test now uses the newSkUiTestHelpers.UseUiThreadDispatcher(), which queues work dispatched from other threads untilTestDispatcherProvider.RunDispatched(), plus aTestUiContextfor the examples' own async continuations, andABackgroundMarkdownBuildChangesTheTreeOnlyOnTheUiThreadchecks the hand-over.
Full changelog: https://github.com/rafalka/MauiSkiaUi/blob/master/CHANGELOG.md
SkiaUi.Maui 1.10.3
Fixes
- Simulated taps whose handler ends the press (#95):
SkUiDiagnostics.SimulateTap(element, releaseOnlyIfTap)andSimulateTapAtreportedWinner: nullandIsTap: falsefor a tap that ran when its own handler ended the press while it ran: it opened a popup or navigated (cancelling the surface's pointers), disabled its control, or removed it from the tree. They now report the recognizer that took the tap. The gesture arena ends once per pointer and keeps the release's winner when the release's handlers take it out; a recognizer that gives up the release itself (a scroller after a press that did not move) still leavesWinnerempty, and so does a control disabled before the release.
Full changelog: https://github.com/rafalka/MauiSkiaUi/blob/master/CHANGELOG.md
SkiaUi.Maui 1.10.2
New features
- Simulated taps report what took them (#93):
SkUiDiagnostics.SimulateTapAt(root, rootPoint, releaseOnlyIfTap = true)andSkUiDiagnostics.SimulateTap(element, releaseOnlyIfTap)return anSkUiSimulatedTap, so automation can report a tap truthfully instead of "succeeding" on a label inside a scroller, a disabled control or a control without a tap.Hit(the element hit, as before),Winner(the recognizer that won the press),IsTap(the winner completes on release: taps, a control's own tap, slider / stepper taps, text fields),PassedToNative(a real touch would reach native views around the surface: a parent's tap recognizer, or a hosted native view, which is not pressed; per platform, as each surface hands touches on) andReleased.releaseOnlyIfTap: a press that a release without movement would not turn into a tap is cancelled instead of released, so a failed tap has no side effects (no fling, no pressed state left behind).SimulateTap(element, releaseOnlyIfTap)also cancels a press another element's recognizer would take (drawn over the element, or at its center while it is scrolled out of view), even withoutreleaseOnlyIfTap;Winnernames it.SimulateTap(element)is unchanged (returns the hit, always releases), except that a native view hosted on the surface (SkUiMauiContentView) is no longer pressed through to the drawn content under it.
- DevFlow extension for apps: the
dev.skiauiDevFlow agent extension the demo uses (a tree of drawn elements with window bounds, taps, hit-testing) is now ready to copy into any app that uses SkiaUi. The new docs/DevFlow.md covers setup, and the newskiaui-devflowagent skill (/plugin install skiaui-devflow@skiaui) does it for you. It isn't a NuGet package because the DevFlow agent is still in preview.- Taps report whether a drawn tap recognizer took them (
taken,winner,passedToNative,released). A press that isn't a tap is cancelled unlessforceis set, and a press another element would take (the target is covered or scrolled out of view) is cancelled and reported ascoveredBy. - A new
tapAttool taps the drawn content at a window point.
- Taps report whether a drawn tap recognizer took them (
Fixes
- Toggles: one-way bindings on
CheckState,IsCheckedorIsToggledstop updating after their first change (#92): the control wrote the state back to its own bindable property with a plainSetValue, whose specificity outranks a binding's, so later values from the binding were stored below it and never applied (a three-state "select all" box bound one-way stayed on the dash). Check boxes, radio buttons and switches now skip writing a value the property already holds and write derived values (taps, the other view of the state) as handler values, as MAUI's own controls do: two-way bindings still get them, and the next value from a one-way binding, a style or the app replaces them. - Input controls: one-way bindings stop updating after the first user change (the rest of #92's bug class): controls wrote user changes and derived values back to their own bindable properties with a plain
SetValue(or the CLR setter), whose specificity outranks a binding's, so later values from a one-way binding were stored below it and never applied. They are now written as handler values (SetValueFromRenderer, as MAUI's own controls do) and skipped when the property already holds them: two-way bindings still get them, and the next value from a one-way binding, a style or the app replaces them.SkUiSlider.Value(drag, tap, screen reader, range clamp);SkUiStepper.ValueandSkUiStepper<T>.Value(buttons, keys, screen reader, range changes).SkUiEntry/SkUiEditor/SkUiSearchBarText(typing,MaxLengthcuts,TextTransform, formatters),CursorPositionandSelectionLength(the user's selection),SkUiEntry.IsPasswordRevealed(the reveal button);SkUiNumericEntry<T>.Valueand the text it shows.SkUiPicker.SelectedIndex/SelectedItem,SkUiPickerColumn.SelectedIndex/SelectedItem,SkUiDatePicker.Date,SkUiTimePicker.Time,SkUiDateTimePicker.Date(popup choices, clearing, range clamps) and every picker'sIsOpen(taps, closing).SkUiPickerColumnnow derives fromElement(wasBindableObject) to write handler values; its API is otherwise unchanged.SkUiCollectionView.SelectedItem(taps, keys, the selection mode, removed items),IsLoadMoreActiveandIsRefreshing;SkUiCarouselView.Position/CurrentItem(swipes,ScrollTo, the linked indicator);SkUiIndicatorView.Position(taps, keys, screen reader, the linked carousel, a count clamp);SkUiExpander.IsExpanded(header taps);SkUiRefreshView.IsRefreshing(pulls, automatic completion, disabling).- The group layout's
RadioButtonGroup.SelectedValue(a radio button checked), and the uniformCornerRadiusthat followsCornerRadiion labels, image buttons, entries and pickers.
Other
- Built with Xcode 27.2: CI and the packages build with workload set 10.0.404 (iOS / Mac Catalyst 27.2 SDKs, Xcode 27.2 on the
xcode-27image) instead of 10.0.402.1 (Xcode 27.1); the Xcode 26.6 build (10.0.401) stays. The library still compiles against the iOS / Mac Catalyst 26.0 SDK, so apps keep building with Xcode 26.6, 27.1 or 27.2.
Full changelog: https://github.com/rafalka/MauiSkiaUi/blob/master/CHANGELOG.md
SkiaUi.Maui 1.10.1
Fixes
- Check box and radio button: a look can set the unchecked colors (#90): an unchecked check box's outline and fill and an unselected radio button's ring were hard-coded (the color scheme's
Muted, white), so matching a design system meant re-implementingDrawCheckBoxCore. They now come from the look's virtualSkUiLook.CheckBoxBorderColor,CheckBoxBackgroundColorandRadioButtonRingColor, whose defaults are the old colors; both layers, still at half alpha while disabled.
Full changelog: https://github.com/rafalka/MauiSkiaUi/blob/master/CHANGELOG.md
SkiaUi.Maui 1.10.0
New features
- Community Toolkit layouts:
SkUiDockLayoutandSkUiUniformItemsLayoutin SkiaUi.Maui.CommunityToolkit (namespaceMauiSkiaUi.CommunityToolkit), drawn counterparts of the toolkit'sDockLayoutandUniformItemsLayoutlaid out by the toolkit's own layout managers, so toolkit pages port by changing the prefix: SkUiDockLayout.md, SkUiUniformItemsLayout.md.SkUiDockLayout:ShouldExpandLastChild,HorizontalSpacing,VerticalSpacing,Add(view, position); children keep the toolkit's attachedDockLayout.DockPosition, and changing it re-lays the dock out.SkUiUniformItemsLayout:MaxRows,MaxColumns. Unlike the toolkit's layout, cells follow the first child when it changes size, and children pastMaxRows×MaxColumnsare hidden instead of keeping an old frame.- The migration checker suggests them for the toolkit's layouts in drawn trees; the gallery shows each beside the toolkit's own.
- Keyboard navigation in collection views: an interactive
SkUiCollectionViewis one tab stop with a current item, as native lists are: Keyboard.- Arrow keys move it (in grids also across, keeping the column; mirrored right to left), Home / End to the ends, Page Up / Page Down by the part of the viewport sticky parts leave uncovered; each move scrolls it into view.
- Space / Enter select and tap it as a tap would (
SelectionChanging,ItemTapped,ItemTappedCommand); withAllowGroupExpandCollapse, group headers are stops that the arrows and Enter expand and collapse. - The focus ring is drawn on the current item while focus came from the keyboard; the item is kept across collection changes and recycling, and passes to its neighbor when removed.
- Extended selection in collection views:
IsExtendedSelectionEnabledwithSelectionMode="Multiple"selects as desktop lists: a click selects only its item, Ctrl+click (Command+click on Apple) toggles one, Shift+click selects the range from the anchor; modifier clicks select without raisingItemTapped. The keyboard never drops the selection by moving: the arrow keys move only the current item, Space toggles it, Insert toggles it and moves on, Shift+arrows toggle the items they move onto (selected ones are deselected; the item the range starts on keeps its state, so a click then Shift+Down selects both), Enter taps (opens) without selecting, Ctrl / Command+A selects all. Touch keeps the toggling tap. Each gesture is one cancelable change (Keyboard). - Selected item template in collection views:
SelectedItemTemplate(a template or selector) makes a selected item's row, for selected rows that show more or differ in size. A selection change swaps the row's view (recycled per template) and measures it again with what shows kept in place, in lists and grids; nothing changes while it is unset. Leak scenarioCollectionViewSelectedTemplate. - Animated item changes in collection views:
AnimatesItemChanges="True"(or a look'sCollectionViewAnimatesItemChanges) animates inserts, removes and moves as native lists do: moved items and grid cells glide to their new places, inserted ones fade in, removed ones fade out where they were; expanding and collapsing groups too (Animated changes).- Off by default in 1.x. The changes of a frame animate together; everything runs on the render thread, the views keep their final layout and taps hit it.
- With a
SelectedItemTemplateof another size, the rows after a selected row glide to make room. - The look's new transitions
ItemInsert,ItemRemove,ItemMove(per platform). Leak scenarioCollectionViewItemsAnimated, bench scenarioscollection-changesandcollection-changes-animated.
- Modifier keys on pointer samples:
SkUiTouchEvent.ModifiersandSkUiPointer.Modifiers(SkUiKeyModifiers, now public) report Shift, Control, Alt and Command held during a press, move or release, from Android (GPU surfaces), UIKit (iOS 13.4+, Mac Catalyst) and Windows (EventMechanism.md). - Layouts of your own on other layout managers:
SkUiLayout.AffectsChildLayout(a child's attached property that re-lays the layout out) andOnChildrenChangedare now protected virtuals, so a layout outside SkiaUi can run another library'sILayoutManager(SkUiLayout.md).
Breaking changes
- Collection view items clip to their bounds (
ClipItemsToBounds, defaulttrue): an item's or grid cell's content wider or taller than its slot (a row of buttons in a narrow grid column) spilled over the neighboring items, which are drawn after it, and covered them in part. Item and group header containers now clip what they show, native views hosted in them included, as Android's lists do. A template that draws past its row on purpose (a shadow into the item spacing, a part overlapping the next row, content scaled up on press) is cut at the edge: setClipItemsToBounds="False", or give the template's root a margin that leaves the shadow room.
Fixes
- No stuck
Selectedlook under the pointer: a collection item deselected while the pointer was over it (on a desktop, or selecting with the keyboard) kept itsSelectedvisual state when its template defined noPointerOverstate, until the pointer left it, as MAUI's visual state manager leaves a group in its state when the next one is missing. Drawn views now go toNormalwhen they have noPointerOverstate.
Other
- Control / Command with a letter now reaches drawn key handlers on Apple and Windows too (as on Android), as
SkUiKey.Characterwith the lowercase letter; pickers' type-ahead ignores it. - Gallery pages for the collection view's keyboard and extended selection and its animated changes (next to MAUI's
CollectionView), and its selected item template. - Collection view items are no longer tab stops one by one: the list is one stop and the arrow keys move between its items (above). Buttons inside items stay tab stops.
Full changelog: https://github.com/rafalka/MauiSkiaUi/blob/master/CHANGELOG.md
SkiaUi.Maui 1.9.0
New features
- Tile layout:
SkUiTileLayoutandSkUiCoreTileLayoutlay out equal tiles for galleries and attachment strips: as many columns of at mostTileSizeas the width takes, stretched to fill the row but never past it, a column dropped belowMinimumTileSize,TileAspectRatio,ColumnSpacing/RowSpacing: SkUiTileLayout.md.MaximumRowscuts the rows: the children past it are neither measured nor drawn, and anOverflowTemplate(bound toSkUiTileOverflow.HiddenCount: "+5") shows over the last tile, withOverflowTapped/OverflowCommand(andOverflowCommandParameter, by defaultOverflow).- Replaces a
Gridrebuilt inSizeChanged(Migration.md); the gallery's tile layout pages, on both layers.
- Core state container:
SkUiCoreStateContainer, the Core twin of the attachedSkUiStateContainer: its content, or the node of the stateCurrentStatenames, from keyedStates(a node, or a factory run when the state is first named).CanStateChange,ChangeStateWithAnimationand the before / after state change animations on the render thread work as on the SkUi* layer; aSkUiCoreShimmermakes a skeleton loading state (SkUiStateContainer.md). - Core expander:
SkUiCoreExpander, the Core twin ofSkUiExpander:Header,Content,IsExpanded,Direction,Command,ExpandedChanged,LazyContentExpansion,AnimationLength/AnimationEasing, the content growing from the header while the height follows. Each animation frame re-records only the nodes whose size changed (SkUiExpander.md). - Core nodes scale each axis:
ScaleX,ScaleY(multiplied byScale, as in MAUI),AnchorXandAnchorYon every Core node, composite-time and animatable on the render thread (AnimateAsync,SkUiViewAnimation), with transform-aware hit testing. - Password reveal:
IsPasswordRevealed(two-way),ShowsPasswordRevealButtonandHidesPasswordOnUnfocus(defaulttrue) onSkUiEntryandSkUiCoreEntry(and the numeric entries): a password field draws its text instead of the bullets, with an optional reveal button (an eye) at its end that toggles without focusing the field, or withPasswordRevealMode="WhilePressed"shows the text only while held (SkUiEntry.md).- The field stays a password field for the platform while revealed (the keyboard, autofill and password managers see one) and copying stays off; the caret and selection stay put, and the text is masked again when the field loses focus.
- Screen readers read the text only while it shows, and the button as "Show password" / "Hide password" (
SkUiStrings.ShowPasswordText/HidePasswordText, automation id{AutomationId}_Reveal). - The look sizes and draws the button:
TextFieldPasswordRevealButtonWidth,DrawTextFieldPasswordRevealButton(DrawTextFieldPasswordRevealButtonCore,DrawPasswordRevealGlyph,TextFieldPasswordRevealButtonPainter) withSkUiPasswordRevealButtonPaint.
- Reorder from a drag handle: the attached
SkUiCollectionView.IsReorderHandlemarks a view in the item template (a ⋮⋮ or ≡ glyph) as the item's drag handle. WithCanReorderItems, a press on it lifts the item at once, with any pointer, and drags it; the rest of the item no longer lifts it, so the row's own taps and long presses (LongPressedCommand: entering a select mode) work, and a drag there scrolls the list. Items with no handle lift with a long press anywhere, as before; a hidden handle stops reordering its item with any pointer; the screen-reader moves stay on the item (SkUiCollectionView.md).
Breaking changes
- Animating one scale axis of a Core node scales that axis only: an
SkUiViewAnimation(or a Core shimmer's state change animation) ofScaleXorScaleYon a Core node used to scale both axes, or was rejected; it now scales its own axis, as on SkUi* views and in MAUI. AnimateScaleto scale both (Migration.md).
Fixes
- An empty
SkUiCollectionViewwithout an empty view no longer pushes the footer down: with noEmptyView(or anEmptyViewTemplatethat makes no view), the empty state took the height the list had left, so theFootersat at the bottom of the list instead of after the header. Nothing shows for it now, and the footer follows the header as it follows the last item. - VoiceOver finds buttons inside drawn controls by touch: explore by touch (and Accessibility Inspector's pointer) on iOS and Mac Catalyst picks the front-most, innermost drawn element, as TalkBack and Narrator do; UIKit picked the top-left of overlapping elements, so a text field's clear and password reveal buttons and actions inside a described group were reached only by swiping.
- A drawn root sized by its content grows with it again: a surface root in a MAUI layout (a drawn stack in a
VerticalStackLayoutin aScrollView) kept its old height when a nestedBindableLayoutlist gained items while the page was shown, cutting off what was below the list until the page laid out again. A native layout pass that arranged the root after the change and before its next frame measured it at its old bounds, capping its height, so its relayout found no change to report. It is now measured with the constraint the native layout gave it, which is asked again when the root's size changed.
Other
- Shaped borders' first frame: borders with the same outline (equal ticket-shaped cards in a list) share its content clip and shadow silhouette, which took a path operation per border: 400 such cards record their first frame in 25 ms instead of 590 ms on a desktop CPU (SkUi*; Core 8 ms instead of 570 ms), and reach it in 0.6 s instead of 1.9 s on a Galaxy S9 and 0.17 s instead of 1.0 s on an iPhone 8 (Performance.md). It also works when each card makes its own stroke shape.
- Core layout changes re-record less: a Core node whose measure changes (a label's new text, a box's new size) re-records itself and the containers whose size changes, no longer every container up to the host, as SkUi* views since 1.0.
SkUiCoreTablestill re-records when a cell's measure changes, since its track fills and separators follow the cells. - Device tests: a password reveal check with the platform's real text input (the keyboard is not restarted, the field stays a password field, screen readers follow), passed on a Galaxy S9 and an iPhone 8;
scripts/device_tests.sh --xcodelaunches on iOS 16 devices with an older Xcode, whose developer image Xcode 27 no longer mounts. - Gallery: Core state container and Core expander pages; drag handles on the collection view reordering page.
- Demo: two-way property editors: a component page's editors follow their property when it changes on a preview: the password reveal button toggles the
IsPasswordRevealedswitch, typing in either preview updates theTexteditor (and the other preview), dragging a slider or swiping a carousel moves its editor.IsEnabledstays one-way (MAUI reports the effective value, false while a command cannot execute).
Full changelog: https://github.com/rafalka/MauiSkiaUi/blob/master/CHANGELOG.md
SkiaUi.Maui 1.8.0
New features
- Markdown: a drawn Markdown view on both layers (
SkUiMarkdownView,SkUiCoreMarkdown), in a new package, SkiaUi.Maui.Markdown, on Markdig.SkiaUi.Mauigets no new dependency.- Headings, emphasis of every kind, inline code, quotes, alerts, containers, code blocks with a copy button, rules, nested and task lists, pipe and grid tables, links, emoji, footnotes, definition lists and images.
- Nothing a document says happens by itself: links and images raise events, remote images load only with
AllowRemoteImages, and a document cannot read a local file (ImageResolverreplaces the rule). - Bad input never throws: a document past a limit, or one that cannot be built, shows as plain text with a
Warning. - Parsing and creating nodes run on a background thread, with the latest text winning; only putting them on screen runs on the UI thread.
- A growing text only builds its tail, so a streamed answer stays cheap.
- The gallery's Markdown page, the samples app's "A Markdown document", and SkUiMarkdownView.md.
- Formulas in Markdown: block and inline math in a second package, SkiaUi.Maui.Markdown.Math, on CSharpMath (
UseSkiaUiMarkdownMath(),UseMath()). A deep formula could end the process with a stack overflow, so every formula is checked before the engine sees it; one past the limits shows its source. - Zoom:
SkUiZoomViewandSkUiCoreZoomView, with pinch, pan, double tap and wheel at composite time, so nothing re-records: SkUiZoomView.md.IsWheelZoomEnabledturns the wheel off for a view in a scroll view.AllowImageZoomon the Markdown view opens a picture in one through the app's popup presenter. - Inline objects in text: a span can draw something in the line instead of its text, on both layers (
SkUiCoreSpan.InlineObject,SkUiSpan.InlineObjecton MAUI'sSpan,SkUiInlineObject). It wraps, aligns and takes taps as a word, and follows the bidi order: SkUiLabel.md. - Baseline shift on spans:
SkUiCoreSpan.BaselineShiftandSkUiSpan.BaselineShift, for real superscripts and subscripts. SkUiPopups.ShowContentAsync: a popup of any drawn view through the app's presenter, on the same contract as a picker's list.
Fixes
- A pinch beats a pan on the same element: with two fingers down, one finger moving first no longer starts the element's
PanUpdatedand ends the pinch. <sub>and<sup>in HTML text sit below and above the baseline; before, they were only smaller.- A scroll that waits for the layout (a keyboard inset, say) ends in the frame that ends it; before, its task ended through a pool thread, which a busy pool could delay past the frames that needed it.
Full changelog: https://github.com/rafalka/MauiSkiaUi/blob/master/CHANGELOG.md
SkiaUi.Maui 1.7.0
New features
- Vector icons: an
.svgfile,MauiAsset, download or stream now draws at runtime on both layers (Source="check.svg"), through a small SVG reader inSkiaUi.Mauiwith no new dependency. It is drawn again at the size its view shows it in exact pixels, larger or smaller, onSkUiImage,SkUiImageButtonand their Core twins; explicit decode bounds win. AMauiImageof the same name still wins. A file with something the reader knows it cannot draw (a gradient,<use>, an embedded image) fails with aLoadErrornaming it, and a file cannot make requests or hold a thread for long.SkUiVectorImageSource, a MAUIImageSourceshaped likeFontImageSource, works in every image property of the SkUi* controls:Source,Color(the starting value ofcurrentColor; colors written in the file stay) andSize(the longest edge in DIPs).ColortakesAppThemeBinding,DynamicResourceand bindings, and a new color keeps the icon shown until it is drawn.- Core:
SkUiImageSource.FromVector(source, color, size)andFromVectorText(svg, color, size). - Once loaded, an icon costs what a PNG of its size does: Performance.md.
- The samples app's "Icons from SVG files" example and the gallery's "SVG icons at runtime" page; how to use them: SkUiImage.md, and moving icons over: Migration.md.
Fixes
- No backdrop flashing through resized GPU surfaces on Windows: a hardware-accelerated surface being resized (a splitter drag, a window resize, anything that changes its layout) showed strips of the window's backdrop at its edges and, for a frame, stretched content. WinUI does not synchronize a swap chain's presents with its own layout, so a swap chain resized with its slot could be shorter than what XAML showed. The swap chain panel is now longer than its slot and clipped to it, and changes only when the slack runs out, so most resizes do not touch the swap chain. A surface starts with 192 epx of slack per direction; one that outgrows it takes 384, and keeps up to 768. Still open: a resize of more than 96 epx in one layout pass can show a gap for a frame, and each change of the panel can flash the whole surface for a frame; a drag back and forth now changes it once instead of twice per sweep.
- No exception when a touch closes its own surface: a release can disconnect the surface's handler while the touch is still being handled (such as the pick that closes a picker's popup); code reading the handler's view afterwards (the demo's input trace on Windows, a frame already queued) threw
InvalidOperationException: VirtualView cannot be null here. SkUiAvatarViewfollows edits of its image source: changing a property of a live source (aFontImageSource'sColor, aUriImageSource'sUri) reloaded the old values.
Full changelog: https://github.com/rafalka/MauiSkiaUi/blob/master/CHANGELOG.md
SkiaUi.Maui 1.6.0
New features
- Viewport insets:
ViewportInsets(Thickness, default none) onSkUiScrollView(and soSkUiVirtualScrollView),SkUiCoreScrollView(SetViewportInsets) andSkUiCollectionViewsays which parts of the viewport are covered by views drawn over the scroller, so an edge-to-edge page scrolls its content under translucent bars with nothing covered at the ends of the range.Paddingkeeps its meaning.- The band left uncovered is what the scroll bars' track,
SnapPointsAlignment,ScrollToAsync(element / node, position),ScrollToIndex/ScrollTo,KeepSelectionVisible, keyboard and screen-reader reveal, keyboard paging, load-more triggers,RemainingItemsThresholdand reordering's auto-scroll use.ScrollToAsync(x, y)stays raw offsets. - Insets across the scroll axis pad the content and keep the scroll bar out of them (a landscape notch). The keyboard and the end inset count as the larger of the two.
- Changing the insets while scrolled keeps what shows in place; at the start of the range the scroller stays there.
- The collection view's sticky header, footer and group headers are drawn inside the insets; the refresh indicator of the collection view and of
SkUiRefreshViewcomes down from the start inset (the refresh view reads it from its content's first vertical scroller). - A bare
SkUiVirtualVerticalStackLayoutfollows the insets of theSkUiScrollViewaround it. - Native views hosted in the content (
SkUiMauiContentView) are clipped to the band, as they show above the drawn surface: they are cut off at a bar and do not take its touches. This also keeps them out of a list's sticky header and footer, which they used to cover. - All of them implement
ISkUiViewportInsets, for app helpers that pass bars' sizes and the safe area on to whichever scroller or list a page shows.
- The band left uncovered is what the scroll bars' track,
SafeAreaInsetson the surface root: read-only and bindable, how far the window's bars, notch and home indicator reach into the root, whatever itsSafeAreaEdgessay; it follows rotation and window resizes, and zero inside a surface. An app binds its bars' padding andViewportInsetsto it. Nothing asks the platform until it is first read.- Demo and samples: the gallery's "Edge-to-edge scrolling" page; the samples app's "Order list" example opens a full edge-to-edge page that follows the insets through a rotation.
Fixes
- Layout changes made while a surface root is arranged are no longer lost: a
SizeChangedhandler that changed a view's layout during the root's first arrange (a bar setting a list's insets) asked the native layout, which was in its own pass and did not come back, so the tree stayed as it was until something else laid it out. The root now lays out again before its next frame. - Hosted native views follow a smaller clip: a
SkUiMauiContentViewkept its old clip when anSkUiScrollViewabove it, or an ancestor withClipToBounds, changed size without moving it (a sheet giving a list less height when the keyboard opens), and showed over what lies below until the next scroll. The clip is now placed again whenever that rectangle changes.
Full changelog: https://github.com/rafalka/MauiSkiaUi/blob/master/CHANGELOG.md
SkiaUi.Maui 1.5.1
Fixes
- Android: check boxes, radio buttons, switches and selected chips no longer crash accessibility with
Xamarin.AndroidX.Core1.19: an app that resolves 1.19 (through Google Play Services,Xamarin.AndroidX.CustomView1.2.0.4 and others) threwMissingMethodException: AccessibilityNodeInfoCompat.set_Checked(bool)as soon as TalkBack or a UI-test driver (UiAutomator, Maestro) read a drawn view with a check state, since that binding turnedCheckedinto the tri-stateint. The checked state is now set on the platform node, which works with every AndroidX version; on Android 16+ all three states go throughCheckedState(a mixed check box is partially checked, as before). CI also builds the Android TFM against the newestXamarin.AndroidX.Core, so a binding change like this one fails the build (issue #78).
Other
- Bugfix releases from
devel: the publish workflow's bumppatchondevelnow makes a stable release (1.5.0→1.5.1) and movesmasterto it, as bumpreleasedoes; before, it started a1.5.1-Prerelease01line. Prerelease lines start withminorormajor(autostill starts one withminor). Apatchfromdevelin a prerelease line is refused: the fix goes tomasteras a hotfix (docs/Releasing.md).
Full changelog: https://github.com/rafalka/MauiSkiaUi/blob/master/CHANGELOG.md