cupertino_native_better
Native iOS Liquid Glass widgets for Flutter with pixel-perfect fidelity. Includes Button, Icon, TabBar, Slider, Switch, and more with reliable version detection.
1.5.4
6.9K downloads/mo
#3434 most downloaded on pub.dev
gunumdogdu/cupertino_native_better
What this package is like to depend on
Last release 23 days ago
01 Aug 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 40 of 40 stable releases
Nothing withdrawn
no release was ever pulled
9 months old
42 releases · first in 2025
42 releases in the last 12 months
see the full history below
Release timeline
42 releases · Nov 2025 to Aug 2026Releases
latest 42-
1.5.401 Aug 2026Release notes
Open source →LiquidGlassContainer's native glass rendered short of its frame whenever
that frame reached into the bottom safe area (floating bottom panel on
home-indicator devices). UIHostingController propagates the screen's
safe area into its SwiftUI content, so the hosted GeometryReader/shape
was inset by the overlap.Fixed by @fbernack in PR #64 via hostingController.safeAreaRegions = [].
Reproduced and verified on a physical iPhone (iOS 26.5): a 140pt panel
flush to the bottom of a 34pt inset rendered ~21pt short before the fix
and filled its frame completely after. Reporter measured up to 22pt on
an iPhone 17 Pro / iOS 26.4 simulator.macOS unaffected — NSHostingController, and macOS windows have no
bottom safe-area inset in practice.Adds Testing -> "PR #64: LiquidGlass safe-area clip" demo with live
offset/height/shape controls and Flutter-drawn frame + safe-area
reference markers so the defect is directly visible.Co-Authored-By: Claude Opus 5 (1M context) [email protected]
Release notes
Open source →Fixed — #64
LiquidGlassContainerglass renders short in the bottom safe areaWhen a
LiquidGlassContainer's frame reached into the bottom safe area — the common "floating bottom panel" layout on home-indicator devices — the native glass stopped short of the frame it was given. Flutter-drawn children stayed in the right place, so they visually spilled outside the glass.Cause:
LiquidGlassContainerPlatformViewhosts the SwiftUI glass in aUIHostingController, which propagates the screen's safe area into its SwiftUI content. Where the platform view's frame overlapped the home-indicator inset, the hostedGeometryReader/shape was inset by that overlap, so the glass filled only the reduced size.Fix:
self.hostingController.safeAreaRegions = [], matching the intent of the existingsafeAreaInsetsoverride inCupertinoSwitchPlatformView.swift.safeAreaRegionsis iOS 16.4+ and the class is already@available(iOS 26.0, *), so no extra availability guard is needed.Reported and fixed by @fbernack (PR #64), who measured up to 22 pt short on an iPhone 17 Pro (iOS 26.4 simulator). Independently reproduced and verified on a physical iPhone running iOS 26.5: with a 140 pt panel pinned flush to the bottom of a 34 pt inset, the glass fell ~21 pt short of its frame before the fix and filled it completely after.
macOS is unaffected —
LiquidGlassContainerNSViewusesNSHostingController, and macOS windows have no bottom safe-area inset in practice.Example app
- New:
Testing → PR #64: LiquidGlass safe-area clip— a glass panel whose bottom offset, height, and shape (rect/capsule/circle) are adjustable live. A solid red strip fills exactly the safe-area inset (the zone the bug leaves uncovered), a Flutter-drawn magenta outline marks the panel's true frame, and a cyan dashed line marks the safe-area boundary — so "glass short of frame" is directly visible rather than a judgement call. Sliding the bottom offset past the boundary shows whether the glass stays attached to its frame.
- New:
-
1.5.328 Jul 2026Release notes
Open source →CNTabBar taps were silently swallowed whenever an ancestor widget held
an active gesture recognizer over the same region (e.g. requests_inspector
wrapping the app in GestureDetector(onLongPress:)). The platform views
were constructed without a gestureRecognizers set, making them passive
arena participants.Both the iOS UiKitView and macOS AppKitView branches now pass an
EagerGestureRecognizer, which resolves accepted on pointer-down so
touches forward to the native UITabBar regardless of competition.Merged from PR #63 by @MohamedAboElM3aTy, amended before merge: the
submitted bare TapGestureRecognizer() is a no-op because Flutter's
isPointerAllowed returns false when no callbacks are set.Also formats tab_bar.dart (contributor indentation broke dart format
and cost 10 pana points).Follow-up sweep for the remaining components tracked in #65.
Co-Authored-By: Claude Opus 5 (1M context) [email protected]
Release notes
Open source →Fixed — #62
CNTabBartaps swallowed by ancestor gesture recognizersCNTabBarstopped responding to taps whenever any ancestor widget held an active gesture recognizer over the same region. The reporter's minimal repro:GestureDetector( onLongPress: () {}, // any active recognizer is enough child: CNTabBar(items: [...], currentIndex: i, onTap: ...), )Tapping a tab did nothing. In the wild this surfaced via
requests_inspector, which wraps the whole app in a long-pressGestureDetector— installing it silently killed the tab bar.Cause:
_buildNativeTabBarPlatformViewconstructed the iOSUiKitView/ macOSAppKitViewwithout agestureRecognizersset. With none supplied, the platform view is a passive arena participant and only receives touches if nothing else claims them, so the ancestor won uncontested.Fix: both platform-view branches now pass
Factory<EagerGestureRecognizer>(() => EagerGestureRecognizer()).EagerGestureRecognizer.addAllowedPointerimmediately callsresolve(GestureDisposition.accepted), so the platform view claims the pointer on pointer-down and touches forward to the nativeUITabBarregardless of what is competing.Note the trade-off: gestures made directly over the tab bar (long-press, drag) now go to the native bar instead of bubbling to ancestor recognizers. This is the intended behaviour for a tab bar, which is only ever tapped.
Reported and originally patched by @MohamedAboElM3aTy (#62, PR #63). The submitted patch used a bare
TapGestureRecognizer(), which is a no-op — Flutter'sTapGestureRecognizer.isPointerAllowedreturnsfalsewhen none ofonTapDown/onTap/onTapUp/onTapCancel/onTapMoveare set, so the recognizer never enters the arena. Amended toEagerGestureRecognizerbefore merge and verified on-device (iPhone, iOS 26.5).Known — same gap remains in other components (#65)
The identical issue affects other platform-view widgets and is tracked in #65. It is not a uniform fix, so it was deliberately kept out of this release:
button.dart,switch.dart,slider.dart,popup_menu_button.dartpass a bareTapGestureRecognizer()and therefore carry the same latent no-op.segmented_control.dart,glass_button_group.dart,icon.dart,liquid_glass_container.dart,floating_island.dart,search_bar.dart,search_scaffold.dartpass nogestureRecognizersat all.- Several of those must not get a claiming recognizer —
icon.dartis decorative (it would steal taps from parent widgets),liquid_glass_container.dart/floating_island.dart/search_bar.dartdeliberately wrap the platform view inIgnorePointerand handle interaction Flutter-side, andsearch_scaffold.dart's view isPositioned.fillbehind all Flutter content. - The button-like components need an armed tap recognizer (
TapGestureRecognizer()..onTap = () {}) rather than an eager one, so drags still fall through to a parent scrollable —button.dart:654documents that intent explicitly.
Example app
- New:
Testing → #62 / PR #63: CNTabBar tap gesture arena— three switchable scenarios verifying the fix on-device: an ancestorGestureDetector(onLongPress:)(the reporter's minimal repro), an ancestorPageView(drag-vs-tap competition), and a no-ancestor baseline for regression coverage. Each scenario avoids nesting aScrollablein the gesture region so ancestor gestures resolve deterministically.
-
1.5.208 Jul 2026Release notes
Open source →- #61: CNBottomSheet.showCupertino compile error on Flutter < 3.44
(scrollableBuilder param window). Switched to builder: which compiles
from Flutter 3.35 through master. - #46 bug A: CNToast queue deadlock after route pop — store
OverlayState instead of BuildContext on queued entries. - #46 bug B: yellow double-underlines under MaterialApp — wrap toast
content in Material(type: MaterialType.transparency) inside
_ToastOverlay.build. - New Testing demo screen reproducing both #46 bugs.
Co-Authored-By: Claude Opus 4.7 [email protected]
Release notes
Open source →Fixed — #61
CNBottomSheet.showCupertinocompile error on Flutter < 3.44CNBottomSheet.showCupertinoin v1.5.1 called Flutter'sshowCupertinoSheet()with ascrollableBuilder:named parameter. That parameter was only added toshowCupertinoSheetin Flutter 3.44.0 (via flutter/flutter#177337, 2026-01-23). Anyone consuming the package on stable 3.35 – 3.41.x — including a substantial share of production Flutter users, FlutterFlow environments, and CI setups — hit a hard compile error:No named parameter with the name 'scrollableBuilder'.Fix: switched to
builder:(the current API on 3.35 – 3.41; deprecated-but-still-accepted on 3.44+). The lambda didn't use itsScrollControlleranyway, so the swap is behaviour-preserving. Compatible from Flutter 3.35 through today's master.Thanks @ArkayGit for the clean, precisely-scoped bug report.
Fixed — #46
CNToastqueue deadlock after route popCNToaststored the caller'sBuildContexton each queued_ToastEntryand re-resolvedOverlay.of(entry.context)inside_showNext()— which fires from aTimerafter each toast's duration. If the caller's widget was disposed while toasts were pending (typical: user shows a toast then taps back), the framework crashed with:Looking up a deactivated widget's ancestor is unsafe.Worse, after the throw,
_isShowingwas lefttrueand the queue was permanently stuck — every subsequentCNToast.show/success/error/warning/infocall would silently_queue.add()without displaying, until app restart. OnlyCNToast.loading()still worked (it bypasses the queue and inserts into the overlay directly).Fix (in
lib/components/toast.dart):_ToastEntrynow stores anOverlayState(resolved eagerly atCNToast.show()time), not aBuildContext._showNext()no longer touches the caller's context and cannot throw on a deactivated widget.- Added
entry.overlay.mountedshort-circuit and atry/catcharoundoverlay.insert(...)— if the OverlayState disappears between enqueue and display (extremely rare), the entry is dropped and the queue keeps draining._isShowingis guaranteed to reset.
Fixed — #46
CNToastrenders with yellow double-underline underMaterialApp(reporter's screenshot)The same issue also carried a second, unrelated defect surfaced by @macedondev's screenshot: text rendered as dim red monospace with a yellow double-underline. That's
MaterialApp._errorTextStyle(flutter/lib/src/material/app.dart:45), Flutter's built-in "your Text has no Material ancestor" debug fallback.MaterialAppinstalls it as the ambientDefaultTextStyleat the app root;_ToastOverlayrenders itsTextinside anOverlayEntrywith noMaterialbetween them, so the fallback style wins.CupertinoAppdoesn't install_errorTextStyle, which is why the maintainer couldn't reproduce the bug locally.Fix: wrap the toast content in
Material(type: MaterialType.transparency, ...)inside_ToastOverlay.build(), positioned betweenIgnorePointerandAlignsoPositionedstill sees theOverlay'sStackas its direct parent (aMaterialbetween them would breakPositioned's parent-data contract and throwIncorrect use of ParentDataWidget). Transparent Material paints nothing, soCupertinoAppusers see no visual change; MaterialApp users get proper text-style resolution and the yellow underlines are gone. Applies to both the queued (_showNext()) and direct-insert (loading()) toast paths.Thanks @macedondev for the report.
Example app
- New:
Testing → #46: CNToast use_build_context_synchronously— two labeled scenarios. Bug A (queue crash on dispose): spam-and-pop button that queues 5 toasts then pops the route ~250ms in, reproducing the "Looking up a deactivated widget's ancestor" crash pre-fix and demonstrating the queue-drains-cleanly behaviour post-fix. Bug B (yellow underlines): a route whose body is a nestedMaterialAppsoCNToastfires into an overlay with the ambient_errorTextStyle— reproduces the reporter's exact rendering. Plus a quick-trigger row for all sixCNToast.*variants for regression coverage.
- #61: CNBottomSheet.showCupertino compile error on Flutter < 3.44
-
1.5.124 Jun 2026Release notes
Open source →Fixed — #53 PlatformView z-order bleed under bottom sheets
iOS hybrid composition was reusing the same
PlatformViewContainerfor both a host-page CN-widget and a CN-widget inside a presented sheet, causing the host-page widget's pixels to leak through the sheet's scrim (and vice-versa).Fix: new
ModalHideMixin(inlib/utils/modal_hide_mixin.dart) applied to all 9 CN widgets that use a PlatformView —CNButton,CNGlassButtonGroup,CNSwitch,CNSegmentedControl,CNPopupMenuButton,CNSearchBar,CNLiquidGlassContainer,CNFloatingIsland,CNSlider. Each widget now destroys its PlatformView (with a same-size placeholder reserving the layout slot) while a sheet covers it, and recreates it when the sheet dismisses.Each affected widget gained an
autoHideOnModal: bool = trueconstructor parameter so users can opt out per-instance.New —
CNBottomSheet+CNSheetGeometryProbeFor the modal-hide to be position-aware (only widgets actually behind the sheet hide, not the entire host route), the sheet has to publish its rect each frame. Two new public APIs cover this:
-
CNBottomSheet(inlib/components/bottom_sheet.dart) — drop-in wrappers that inject the probe automatically:CNBottomSheet.show(context: context, builder: (ctx) => MySheet()); CNBottomSheet.showCupertino(context: context, builder: (ctx) => MySheet()); CNBottomSheet.showModalPopup(context: context, builder: (ctx) => MySheet()); -
CNSheetGeometryProbe— wrap your own sheet builder manually if you need to keep using the framework APIs directly:showModalBottomSheet( context: context, builder: (ctx) => CNSheetGeometryProbe(child: MySheet()), );
Without one of these the package falls back to a conservative "hide every CN-widget on this route while any modal is up" behavior — safe, but coarser than needed (an app-bar CN-button could disappear behind a 30%-height sheet).
CNTabBarRouteObserveralso gainedtopModalRect: ValueNotifier<Rect?>andpublishTopModalRect(Rect?), used by the probe.Fixed — #55
CNPopupMenuItem.isDestructiveCNPopupMenuItemgainedisDestructive: bool = false. When true:- iOS 14+ adds
UIMenuElement.Attributes.destructive→ the label renders in the system destructive red (previously only the icon could be red viaiconColor). - iOS 13 legacy fallback uses
UIAlertAction.Style.destructive. - iOS < 26 / non-iOS Cupertino fallback uses
CupertinoActionSheetAction(isDestructiveAction: true).
Thanks @ashellz for the report.
Fixed — CNGlassButtonGroup remount blink
CNGlassButtonGroup'sFutureBuilderreturnedSizedBox.shrink()for one frame between the modal-hide placeholder removal and the platform view actually mounting — text below jumped up then back down on every sheet dismiss. The pending branch now mirrors the placeholder's axis-aware dimensions so the layout slot is held across the swap.Fixed — PR #57 macOS
CNSwitchrendered as a checkboxThe macOS
Toggledefaulted to a checkbox under recent SDKs. Applied.toggleStyle(.switch)to force the switch appearance. iOS unaffected. Thanks @jonathanfristedt.Fixed —
MissingPluginExceptionstorm during transitionsch.invokeMethod('setTransitioning', …)calls now use.catchError((_) {})to swallow async rejections, and fallback platform-view classes (iOS < 26) register no-opMethodChannelhandlers so Dart-side calls fromModalHideMixinand route-transition containment don't throw.Docs
pubspec.yamldocumentation:now points to https://gunumdogdu.com/docs.- README documents
CNBottomSheet/CNSheetGeometryProbeusage and the navigatorObserver requirement for modal-hide to work.
Example app
- New:
Testing → #53: CNButton under bottom sheet— four sheet-opener variants over a host page full of CN widgets. - New:
Testing → #55: PopupMenu isDestructive— text, icon, and mixed menus with destructive items. - New:
Testing → Glass widgets modal halo test— all 9 CN widgets behind sheets. - New:
Testing → CNButton modal halo test— modal route push/pop animations. - New:
Testing → #37: CNAppBar button halo test.
Known limitations
CNGlassButtonGroupglass merging at default spacing still shows a "dumbbell" between buttons. The single-uniform-pill rewrite hit a SwiftUI hit-testing limitation (.glassEffect()intercepts touches at a layer below.allowsHitTesting(false)); a UIKitUIVisualEffectViewrewrite is queued for the next release.
-
-
1.5.001 Jun 2026Release notes
Open source →New — CNTabBarNative gains minimize, native lists, accessory & root mode
Building on the existing
CNTabBarNative(the native iOS 26 Liquid Glass tab bar), this release adds:- Minimize-on-scroll (resolves #32) —
minimizeBehavior:withCNTabMinimizeBehavior.{automatic, never, onScrollDown, onScrollUp}, changeable at runtime viasetMinimizeBehavior(...). Requires a tab backed by aCNNativeList, since iOS drives the minimize from a real native scroll view. - Native list tabs —
CNTab(nativeList: CNNativeList(items: [CNListItem(...)]))renders a native scrollable list;onListItemTap(tabIndex, itemIndex)reports taps. NewCNNativeList/CNListItemmodels (now exported from the package). - Bottom accessory pill —
bottomAccessory: CNTabAccessory(...)floats above the bar and slides inline when it minimizes;onAccessoryTapreports taps; show/update/hide at runtime withsetBottomAccessory(...)(passnullto hide). - Presentation modes —
asRoot:selects modal presentation (default) or root presentation; in root mode a tab with nonativeListhosts your real Flutter UI. - Search filtering option —
nativeSearchFilter(defaulttrue) filters the search tab's own list locally; setfalseto drive results yourself viaonSearchChanged+setItems. - Mutation API —
setItems(...)for dynamic/paginated data, plusonDismissed(fires when the bar is closed natively, e.g. via the ✕ button).
The native manager was rewritten (
CNNativeTabBar.swiftreplacesCNNativeTabBarManager.swift) on a stable SwiftUITabViewview tree.Docs
- Rewrote the README "Native iOS 26 Tab Bar (CNTabBarNative)" section: native-takeover mental model, a
CNTabBarvsCNTabBarNativecomparison table, presentation modes, and a per-method API reference. Added a preview GIF (minimize + accessory + search). - Documented that
CNTabBarNativeis a native takeover, not a Flutter bottom-nav — for Flutter screens per tab, useCNTabBar(clarifies #7).
Deprecated
CNTabBarNative.enableparametersonSearchSubmitted,onSearchCancelled,onSearchActiveChanged— the search tab now reports throughonSearchChanged; these are no longer fired and will be removed in a future major release.CNTabBarNative.checkIsEnabled()— use the synchronousisEnabledgetter instead.
Notes
- #48 (color the unselected tab item): investigated and intentionally not added to
CNTabBar. iOS 26's Liquid Glass tab bar enforces the system color for unselected items and ignores customization — verified on-device with both the legacyUITabBar.unselectedItemTintColorand the modernUITabBarAppearanceper-stateiconColor/ titleforegroundColor. The selectedtintis honored; the unselected state is system-owned, so a public knob would silently no-op on the package's target OS.
- Minimize-on-scroll (resolves #32) —
-
1.4.623 May 2026Release notes
Open source →Bug Fixes
- Fixed #39 / merged PR #42 —
CNTabBar.iconSizeis now honored forcustomIconitems (anyIconDatalikeCupertinoIcons.houseorIcons.home). Previously the custom-icon rasterizer was hardcoded to 25pt regardless of the bar-leveliconSizeor per-itemicon.size. Bug originally surfaced via #39 (SVGimageAssetlayout glitch on v1.4.3) and addressed by @Azzeccagarbugli's PR #42, with an extra refinement on top:lib/components/tab_bar.dart:_prepareCreationParamsnow passeswidget.iconSize ?? item.icon?.size ?? 25.0toiconDataToImageBytes; same precedence onactiveCustomIcon;_buildTabIcon(Flutter fallback) mirrors the precedence across all icon kinds.lib/utils/icon_renderer.dart: full rewrite oficonDataToImageBytes. Drops the heavyRenderRepaintBoundary+BuildOwnersetup in favor of aTextPainter+ canvas + alpha-channel crop approach. Final step (refinement on top of the PR): re-blit the cropped glyph into a squaresize × sizecanvas with the glyph scaled to fill, so custom icons at a given pointSize match SF Symbol's visible ink at the same pointSize (matches SF Symbol's "pointSize is ink size" convention — previously, font em-box padding made customIcon visually smaller than equivalent SF Symbols at the same size).test/widget_test.dart: 6 new widget tests verifying theiconSize > icon.size > 25ptprecedence across SF Symbol / customIcon / imageAsset in the Flutter fallback path.
New
-
Swift Package Manager support — fixes #44. The plugin now ships a
Package.swiftmanifest for both iOS and macOS targets and is recognized bypanaas "Swift PM-ready".Flutter's SPM rollout is well underway: SPM support landed in Flutter 3.24 (Aug 2024) as opt-in, became the default for new apps in Flutter 3.44, and CocoaPods is being phased out — Firebase stops publishing to CocoaPods in October 2026 and the CocoaPods registry becomes read-only on December 2, 2026. Plugins without SPM support already lose pana points and trigger build warnings on modern Flutter versions.
Compatibility (no users locked out): the plugin's own pubspec constraints stay at
sdk: ^3.9.0/flutter: '>=3.3.0'. The SPMPackage.swiftsits alongside the existing podspec and is only consulted by Flutter 3.24+. Older Flutter consumers continue to resolve the package via CocoaPods exactly as before — the podspec'ssource_filespath was updated to point at the new SPM-shaped source directory (ios/cupertino_native_better/Sources/cupertino_native_better/**, mirrored on macOS) so both build paths produce the same result.Consumer Flutter Build path 3.3 – 3.23 (pre-SPM) CocoaPods via podspec. Package.swift ignored. Unchanged from v1.4.5. 3.24 – 3.43 (SPM opt-in) CocoaPods by default; SPM if flutter config --enable-swift-package-manageris set. Both paths work.3.44+ (SPM default) SPM via Package.swift.Thanks to @josec-ecw for the PR.
Example app
- Added:
Testing → PR #42: CNTabBar iconSize (customIcon)— three side-by-sideCNTabBars (SF Symbol / customIcon / SVG imageAsset) with aniconSizeslider so all three icon kinds can be verified to scale identically. Four Stratis UI Figma SVGs bundled (camera-01,card-add,chromecast,home-03) — same source as #39 reporter — for SVG verification.
Pana
- 160/160 (now includes "Swift PM-ready" recognition)
- Fixed #39 / merged PR #42 —
-
1.4.510 May 2026Release notes
Open source →Bug Fixes
-
Fixed #35 / #41 (recreate animation on launch + navigation) —
CNTabBarno longer plays a visible "morph through every tab" animation on app launch or after navigating away and back.- Launch glitch (#35): Swift
refreshcyclesbar.selectedItemthrough every tab to force UITabBar's label layout (workaround for an old "5 items, sporadic missing labels" bug — Issue #6). On iOS 26 with Liquid Glass, that cycling was visible as the selection pill morphing through every tab. The cycle is now wrapped inUIView.setAnimationsEnabled(false) … true— labels still render correctly, but the pill no longer animates between items. Tab bar appears instantly with the configuredcurrentIndex. - Recreate-on-return (#41 part 1):
autoHideOnPageTransitionpreviously swapped the platform view to aSizedBoxduring route slides, destroying the nativeUITabBar. On return, a fresh view was created and_onCreatedre-ransetSelectedIndex+refresh→ visible animate-to-index. Fix: whenautoHideOnPageTransitionis on,CNTabBar.buildnow always returns anIndexedStack(children:[SizedBox, UiKitView]); only the painted index toggles between 0 and 1 across the transition. TheUiKitView's element stays mounted in both states, so the nativeUITabBaris preserved across navigation. Bar just appears with the correct index, no animation.
- Launch glitch (#35): Swift
-
Fixed #41 (PlatformViewGuard 500 ms fallback flash on first build) — non-iOS26 fallback widgets briefly visible during cold start.
- Cause:
PlatformViewGuard.ensureScheduledalways delayed platform-view creation by 500 ms to give Flutter'sFlutterPlatformViewsControllertime to purge stale registrations from a previous Dart isolate after a hot restart. That race only exists in debug; release builds (cold-start, no isolate recycling) were paying the same flash-of-fallback cost for nothing. - Fix:
PlatformViewGuardis now ready immediately inkReleaseMode. Native iOS 26 widgets render from the first frame in production; debug-mode hot-restart safety is preserved unchanged.
- Cause:
-
Fixed #36 follow-up —
LiquidGlassContainer's rectangular layer drop shadow leaking past its rounded glass corners while a modal/sheet was presented above (was already targeted in v1.4.4 but only clipped the rectangular layer bounds; rounded clip wasn't applied across all shape configurations correctly). The corner-radius clip inapplyTransitionContainmentnow consistently matchesrect(configured cornerRadius),capsule(min(width, height)/2), andcircle(min(width, height)/2) — no more square shadow nubs.
New
-
Fixed #40 (CNButton label customization) —
CNButtonConfignow accepts:labelFontFamily— custom font family (must be registered inInfo.plistor as a Flutter font asset).labelFontSize— point size override.labelColor— explicit foreground color (overrides thetint-derived default for non-filled styles, and the system default for filled / borderedProminent / prominentGlass).labelFontWeight— FlutterFontWeightoverride.
Implementation: Swift side applies them via
UIButton.Configuration.titleTextAttributesTransformer, so the overrides take effect on the native label without losing the iOS 26 Liquid Glass / prominent / tinted button background. Both creation-time (creationParams) and runtime (setLabelStylechannel call from_syncPropsToNativeIfNeeded) updates are supported. FlutterFontWeight.value(0-8) is mapped toUIFont.Weight.Example:
CNButton( label: '1', tint: CupertinoColors.systemOrange, onPressed: () {}, config: const CNButtonConfig( style: CNButtonStyle.prominentGlass, width: 80, minHeight: 80, labelFontSize: 36, labelFontWeight: FontWeight.w600, labelColor: CupertinoColors.white, ), )
Behavioural details
CNTabBar.autoHideOnPageTransitionkeeps its defaulttrue. With the IndexedStack-based hide it's now zero-cost: state is preserved across navigation while still preventing the original page-wide PlatformViewLayer occlusion artifact during route slides.- Multi-label
CNButton(e.g. dial-pad style: large number + small letters underneath) is intentionally not added toCNButton's API. The same effect composes cleanly viaLiquidGlassContainerwrapping aColumnof two FlutterTexts — fullTextStylefreedom on both labels with the native iOS 26 Liquid Glass background. See the closing comment on Issue #40 for a snippet.
Example app
- Added:
Testing → #40: CNButton label style— interactive screen for verifying the new label-style params (font-size slider, color swatches, font-family segmented control, style picker).
Pana
- 160/160
-
-
1.4.428 Apr 2026Release notes
Open source →Bug Fixes
- Fixed #36 —
LiquidGlassContainer's rectangular layer drop shadow leaking past its rounded glass corners while a modal/sheet was presented above. Visible as four square shadow nubs at the card's corners through the modal's scrim, even though the visible glass was rounded.- Root cause:
applyTransitionContainment(true)(added in v1.4.3 for the dynamic halo containment) only setclipsToBounds = trueon the container's CALayer, which clips to the rectangular layer bounds — leaving the four corners outside the rounded glass shape unclipped. The layer's drop shadow rendered into those corners and bled through the modal scrim. - Fix: in
LiquidGlassContainerView.swift,applyTransitionContainment(true)now also setscontainer.layer.cornerRadius(and the hosting view's) to match the configured glass shape:rectshape → uses the configuredcornerRadiuscapsule/circle→min(width, height) / 2
- The clip is now rounded, matching the visible glass exactly. Reverted to 0 when containment goes inactive so it doesn't affect the at-rest visual.
- Root cause:
Documentation
- README: added a prominent "Required Setup: register
CNTabBarRouteObserver" section directly under Quick Start, documenting:- Why the observer is needed (hybrid composition, halo containment, z-order with sheets).
- Where to register it:
CupertinoApp/MaterialApp/GoRoutersnippets. - What it fixes across all 7 glass widgets, with explicit references to Issues #29, #31, #36.
- Manual
markAnyModalActive/markAnyModalInactiveAPI for non-route overlays (Scaffold.showBottomSheet). - Several users reported needing this observer to fix sheet bleed-through; with this section it should now be impossible to miss during initial setup.
Example app
- Added:
Testing → #36: LiquidGlassContainer behind modal— focused reproduction page for Issue #36. Card-shapedLiquidGlassContainermatching the issue reporter's_AdaptiveGlassContainerwidget exactly (cornerRadius: 15,rect,EdgeInsets.all(13), no tint), four sheet variants including the reporter's exactshowModalBottomSheetinvocation (rounded top, scaffold-bg,Clip.antiAlias, bounce animation,useRootNavigator: true), and aCalendarDatePickerinside each sheet matching the modal content from the issue's screenshots. White scaffold + black/white pill buttons mirror the reporter's app styling.
Pana
- 160/160
- Fixed #36 —
-
1.4.320 Apr 2026Release notes
Open source →Bug Fixes
-
Fixed #34 — CNButton glass capsule not stretching with its parent frame; icon overflowing a small pill when wrapped in
SizedBox/Expanded. Regression introduced in v1.4.0.- Root cause: the v1.4.0 "feat: fixes" commit added always-on
container.clipsToBounds = true+uiButton.clipsToBounds = true(plus layer shadow/background clearing) across every iOS 26 glass widget as part of the #29 halo containment.UIButton.Configuration.glass()renders its capsule via an internal background subview whose visual size includes a soft-edge glow extending slightly beyond the button's layer bounds — the always-on clipping was cropping that glow AND preventing the capsule from growing with a stretched frame. - Fix: reverted all the always-on clipping across
CNButton,CNPopupMenuButton,CNFloatingIsland,CNGlassButtonGroup,LiquidGlassContainer,CNSearchBar. Containers are unclipped at rest, so the glass capsule renders its full soft-edge glow and stretches properly withSizedBox/Expanded/Container(width: ...).
- Root cause: the v1.4.0 "feat: fixes" commit added always-on
-
Fixed #29 (fully) — the original halo-during-route-transition artifact is now resolved via a dynamic containment pattern instead of always-on clipping. This also catches the popup/sheet bleed cases that the v1.4.0 fix didn't cover (popup routes, persistent bottom sheets).
- New native method
setTransitioning(active:)onCNButton,CNPopupMenuButton,CNFloatingIsland,CNGlassButtonGroup,LiquidGlassContainer,CNSearchBar, and the regularCNTabBarvariant. When active, it applies the halo-containment clipping + shadow/background clearing; when inactive, it reverts. - Dart side listens to two signals and calls
setTransitioning(true)when either fires:ModalRoute.secondaryAnimation— catchesCupertinoPageRoute/MaterialPageRouteforward/reverse transitions.- A new
CNTabBarRouteObserver.anyModalDepthcounter that tracks anyPopupRoute/ Sheet / Popup / Dialog-named route (showCupertinoSheet,showCupertinoModalPopup,showModalBottomSheet,DialogRoute, etc.).
- For the split-search variant of
CNTabBar(whose native container is intentionally unclipped so the floating search orb can render above the bar), the auto-hide trigger is broadened toanyModalDepthso popups over a search-enabled tab bar no longer leak shadow through the sheet's top edge.
- New native method
New
-
CNTabBarRouteObserver.anyModalDepth(read-onlyValueListenable<int>) — broader counter than the existingmodalDepth. Tracks every modal-like route (allPopupRoutes plus any route whose runtime type containsSheet/Popup/Dialog). Used internally by the glass widgets for halo-containment activation. -
CNTabBarRouteObserver.markAnyModalActive()/markAnyModalInactive()— public manual API for non-route overlays thatNavigatorObservercan't see, notablyScaffold.showBottomSheet(persistent bottom sheet anchored toScaffoldState, not the Navigator):final controller = Scaffold.of(context).showBottomSheet(...); CNTabBarRouteObserver.markAnyModalActive(); controller.closed.whenComplete(CNTabBarRouteObserver.markAnyModalInactive);
Example app
- Added:
Testing → CNButton modal halo test— stretched CNButton variants + 4 sheet types (showCupertinoSheet,showCupertinoModalPopup,showModalBottomSheet,showBottomSheet) for verifying halo containment across every overlay variant. - Added:
Testing → Glass widgets modal halo test— same 4-sheet matrix againstCNPopupMenuButton,CNGlassButtonGroup,LiquidGlassContainer,CNSearchBar,CNFloatingIsland. - Updated:
Stack+Positioned tab barandSplit-search clip reproscreens now include all 4 sheet types for regression coverage. - Added:
DefaultMaterialLocalizations.delegateto the rootCupertinoAppso demos can mixshowModalBottomSheet(Material) with Cupertino routes without addingflutter_localizations.
Behavioural details
- At rest, glass widgets render the full iOS 26 Liquid Glass capsule (including the soft-edge glow that extends slightly beyond the view's layer bounds) and stretch to fill bounded parent frames. This matches native iOS behaviour.
- During a route transition or while a modal/sheet/popup/dialog is above the widget's route, the native container is clipped and layer shadows are suppressed — the visible change is essentially invisible (the widget's visible frame is unchanged), but Flutter snapshots of the outgoing/incoming page no longer include a halo that extends past the platform-view bounds.
CNTabBarwithoutsearchItemstill uses the narrow Sheet-onlymodalDepthheuristic for its auto-hide (avoids the recreate-and-restore flash on quick action-sheet popups).CNTabBarwithsearchItemuses the broaderanyModalDepthbecause its container can't be clipped (the floating search orb needs to render above the bar's top edge).
Pana
- 160/160
-
-
1.4.217 Apr 2026Release notes
Open source →CNTabBar auto-hide while full-screen sheet is presented (Issue #31)
Adds
CNTabBarRouteObserver(NavigatorObserver) andCNTabBar.autoHideOnModal.
With one line of setup the tab bar disappears while a full-screen sheet
(CupertinoSheetRoute, ModalBottomSheetRoute) is on top and reappears
when dismissed — matching iOS UITabBarController's native behaviour and
fixing the z-order bug where Flutter-rendered TextFields inside the
sheet were invisible behind the tab bar's native UIView.Auto-hide is intentionally narrow: only routes whose runtime type name
containsSheet. Action-sheet popups, dialogs, and regular page pushes
do NOT trigger auto-hide — those don't fully cover the bar and the
platform-view recreate animation would look ugly on quick popups.Setup:
CupertinoApp(
navigatorObservers: [CNTabBarRouteObserver()],
...
)Opt-out per-bar: CNTabBar(autoHideOnModal: false, ...)
Also fixes a related bug in
_onCreated: the order of the post-create
calls wasrefresh -> setSelectedIndex, but nativerefreshcaptures
bar.selectedItemat start and asynchronously cycles + restores. That
restored the stale creationParams selectedIndex (0) over the
setSelectedIndex we'd just sent. Swapped the order to setSelectedIndex
-> refresh; refresh now captures the correct index.Pana: 160/160.
Co-Authored-By: Claude Opus 4.7 (1M context) [email protected]
Release notes
Open source →New
-
CNTabBarRouteObserver— aNavigatorObserverthat letsCNTabBarauto-hide while a full-screen sheet is presented over its route. Resolves Issue #31 (MaterialTextFieldinvisible insideshowCupertinoSheetwhenCNTabBaris in the bottom nav slot).The native
UITabBaris rendered inside a FlutterUiKitView. When a Flutter-rendered sheet route is presented over the same navigator, hybrid composition can leave the tab bar's UIView at a higher z-index than the modal's Flutter content — makingTextFields inside the sheet invisible and letting the bar bleed through during sheet drags. Auto-hide swaps the platform view for an empty placeholder while the sheet is up, mirroring what iOS does natively when aUITabBarControllerpresents a full-screen modal.Setup (one line per app):
CupertinoApp( navigatorObservers: [CNTabBarRouteObserver()], // ... )Or
MaterialApp(navigatorObservers: [CNTabBarRouteObserver()], ...). Without this observer registered,CNTabBarstill renders correctly — it just won't auto-hide on top of sheets and you may hit the Issue #31 z-order glitch. -
CNTabBar(autoHideOnModal: bool = true)— opt-out for the auto-hide behaviour. Defaulttrue. Setfalseto keep the tab bar visible behind sheets (rare; typically requires a native sheet that won't trigger the z-order issue).
Bug Fixes
- Fixed: tab bar's selected index resetting to 0 after a modal/sheet closed and the platform view was recreated (Issue #2 page repro).
- Root cause: in
_onCreatedwe calledrefreshbeforesetSelectedIndex. The nativerefreshmethod (a workaround for the 5-item-label-rendering bug Issue #6) capturesbar.selectedItemat start, cycles through items asynchronously, then "restores" the captured value — overriding thesetSelectedIndex(currentIndex)we sent right after, leaving the bar stuck at the stalecreationParams.selectedIndex = 0. - Fix: swapped the order —
setSelectedIndexnow runs BEFORErefresh. Refresh then captures the correct index and restores to it. Applied to both the 50ms and 200ms recreation passes.
- Root cause: in
Behavioural details
- Auto-hide is intentionally narrow: it triggers only for routes whose runtime type name contains
Sheet(CupertinoSheetRoute,ModalBottomSheetRoute). Action-sheet popups (CupertinoModalPopupRoute), dialogs, and regular page pushes do NOT trigger auto-hide. This avoids a visible "platform view recreate + index restore" jump animation on quick popups, while still fixing the z-order issue for full-screen sheets.
Example app
- Added:
Testing → #31: TextField — NO search variant (hypothesis test)— same flow as the Issue #31 reproduction but withCNTabBarconfigured withoutsearchItemandautoHideOnModal: false, used to verify the bug isn't search-specific. - Added: registered
CNTabBarRouteObserver()on the example app'sCupertinoAppso all demo screens benefit from auto-hide.
Pana
- 160/160
-
-
1.4.117 Apr 2026Release notes
Open source →iOS 26 Liquid Glass selection pill no longer cropped at top
The v1.4.0 Issue #2 fix clipped the platform-view container to stop
the Liquid Glass drop shadow from bleeding over modal bottom sheets.
The same clip was also cutting off the iOS 26 tab bar's selection
pill during its morph animation between tabs.Fix: container still clips (shadow containment preserved), but the
UITabBar is positioned 14pt below container.topAnchor in all 5
layout sites, and getIntrinsicSize reports barHeight + 14pt. The
selection pill — including rapid morph between tabs — now renders
fully inside the clipped container. Bar's visible position on screen
is unchanged.Example app:
- New "#33: SVG in CNTabBar" reproduction screen
- New "Stack+Positioned tab bar" reference screen
- "CNTabBar split-search clip" enhanced with modal test + teal bg
- iOS deployment target bumped 14.0 -> 15.0
Known issue documented in CHANGELOG and inline Swift comment:
simulator Liquid Glass rendering differs from real device; verify on
hardware before treating visual artifacts as bugs.Pana: 160/160.
Co-Authored-By: Claude Opus 4.7 (1M context) [email protected]
Release notes
Open source →Bug Fixes
- Fixed:
CNTabBariOS 26 Liquid Glass selection pill was being cropped at its top edge after the v1.4.0 Issue #2 fix.- Root cause: v1.4.0 clipped the platform-view container to block the Liquid Glass drop shadow from bleeding over modal bottom sheets. The same clip also cut off the selection pill, which extends ~12–14pt above the bar's top during its morphing animation between tabs.
- Resolution: the container still clips (shadow containment preserved), but the UITabBar is now positioned 14pt below the container's top edge, and the reported intrinsic height is bar-height + 14pt. The Liquid Glass selection pill — including its morph animation when rapidly switching tabs — renders fully inside the clipped container. Bar's visible position is unchanged at the bottom of the allocated space.
- Applied to all 5 layout sites: single-bar init, split-bar init, and the equivalent setLayout rebuilds, for both iOS 26+ and iOS < 26 code paths.
Example app
- Added:
Testing → #33: SVG in CNTabBar— reproduction screen mirroring the SVG-icons-in-CNTabBar pattern reported in Issue #33, including the reporter'sNavBarItemwrapper,iconSize: 24, andtintconfiguration. Local iOS 26 verification shows SVGs render correctly; the screen is published so the reporter (and future users hitting the same symptom) can confirm on their own setup. - Added:
Testing → Stack+Positioned tab bar— demonstrates theStack+Positioned(bottom: 0)layout pattern as an alternative toScaffold.bottomNavigationBarfor users who need custom z-order control. - Enhanced:
Testing → CNTabBar split-search clip— bright teal background and a modal-bottom-sheet trigger button so both the search-orb top-edge clip and the Issue #2 shadow-bleed scenarios can be verified side-by-side on one screen. - Bumped: example app iOS deployment target from 14.0 to 15.0 (required by the plugin's
s.platform = :ios, '15.0').
Known issues
- iOS simulator (not real device): iOS 26 Liquid Glass rendering on the simulator is software-rasterized and has visible differences from real Metal hardware. You may see the Liquid Glass selection pill appear slightly clipped at the top, or a brief rectangular outline around buttons on press. These artifacts do not appear on real iOS 26 devices. Always verify Liquid Glass behavior on a real iPhone/iPad before treating a visual quirk as a package bug.
Pana
- 160/160
-
1.4.016 Apr 2026Release notes
Open source →Bug Fixes
-
Fixed:
CNTabBartop-edge shadow bleeding over modals / bottom sheets — the regression of Issue #2 that landed between v1.3.0 and v1.3.8 (Issue #2)- Root cause: in v1.3.3 the
clipsToBounds = truecontainment from the original v1.3.0 fix was made conditional and disabled on iOS 26+. That removed the only thing keeping the UITabBar's top-edge hairline inside the platform view's bounds. container.clipsToBounds = truerestored unconditionally on the regular tab-bar platform view (5 sites — single-bar and split-bar in bothinitandsetLayout)- Added
bar.shadowImage = UIImage()on everyUITabBarinstance as belt-and-suspenders against iOS 26 ignoring the appearance-level shadow override
- Root cause: in v1.3.3 the
-
Fixed: Liquid Glass halo rendering outside platform-view bounds during iOS route transitions — the "placeholder square" reported across CNButton, CNTabBar, and other widgets (Issue #29)
- Root cause: iOS 26 Liquid Glass effects (
UIButton.Configuration.glass(),UITabBarglass material,.glassEffect()SwiftUI modifier) render a translucent halo that extends slightly outside the view's frame. Without containment, that halo became visible during route transitions as a square outline around the widget on the outgoing page. - Same containment pattern as Issue #2 applied to:
CNButton,CNPopupMenuButton,CNSearchBar,CNFloatingIsland,CNLiquidGlassContainer container.clipsToBounds = true,container.layer.shadowOpacity = 0,container.layer.backgroundColor = clear,container.isOpaque = falseplus the same on the inner subview where applicable
- Root cause: iOS 26 Liquid Glass effects (
-
Fixed:
CNTabBarwithsearchItem— the floating Liquid Glass search orb's top edge was being cropped (commented in Issue #31 by @el2zay)- The iOS 26+ search-tab-bar variant (
CupertinoTabBarSearchPlatformView) now leaves its container un-clipped so the search orb can render its top edge correctly. Top-edge hairline is still suppressed viabar.shadowImage = UIImage()andbar.layer.shadowOpacity = 0, so the original Issue #2 shadow bleed does not return.
- The iOS 26+ search-tab-bar variant (
-
Fixed:
CNGlassButtonGroupbadge X-position — the last badge floated near the screen edge instead of sitting on its button when buttons were centered as a tight pill inside a wider containerupdateBadgePositions()now estimates each button's rendered width from icon size + padding + minHeight (capsule width = max(intrinsic, minHeight)), computes the centered-HStack starting offset, and places each badge at the actual button's top-right corner instead of dividing container width evenly across button count.
-
Fixed:
CNGlassButtonGroupAuto Layout_UITemporaryLayoutWidth = 0warning on initial mount — silenced by lowering hosting-view constraint priorities to.defaultHighso UIKit can break them silently during the brief temp-width=0 phase without logging.
Test demos added
Testing → #2: Modal bottom sheet shadow— opens aCupertinoModalPopupover aCNTabBarso the top-edge shadow bleed (or its absence) is easy to inspectTesting → #29: Per-widget halo test— one slow-transition push per widget so each can be verified in isolationTesting → CNTabBar split-search clip—CNTabBarwith asearchItemso the floating orb is easy to inspect at the bottom-rightTesting → #31: TextField disappear in modal— MaterialScaffold+CNTabBar(withsearchItem) inbottomNavigationBar, opens a modal sheet with a MaterialTextFieldand aCupertinoTextFieldfor comparison
Pana
- 160/160
-
-
1.3.903 Apr 2026Release notes
Open source →New Features
- Added:
checkedproperty onCNPopupMenuItemfor checkmark/selected state (Issue #28)- Native iOS uses
UIAction.state = .onfor native checkmark display - Supports single-selection, multi-selection, and mixed checked+disabled states
- Flutter fallback shows a checkmark icon before the label
- Native iOS uses
Bug Fixes
- Fixed:
PlatformException(recreating_view)on iOS hot restart (PR #30 by @lucakramberger)- New
PlatformViewGuardutility delays platform view creation during startup CNTabBarrefactored from nested FutureBuilders to state-managed async pipeline- Native
deinitcleanup added to tab bar platform views
- New
- Added:
-
1.3.823 Mar 2026Release notes
Open source →Bug Fixes
- Fixed: macOS build — resolved 5 compilation errors in native Swift code
badgeCountparameter missing fromsetupSwiftUIButtonmethod.clearcolor inference onCALayer.backgroundColor(now usesNSColor.clear.cgColor)FlutterPlatformViewprotocol replaced withNSViewfor LiquidGlassContainer- Removed invalid
namespaceargument fromGlassButtonSwiftUIcall NSButton.titlenon-optional handling
- Fixed: macOS build — resolved 5 compilation errors in native Swift code
-
1.3.723 Mar 2026Release notes
Open source →New Features
- Added: Popup menu button support in
CNGlassButtonGroupviaCNButtonData.popup()(PR #23 by @byackee)- Mix regular icon buttons and popup menu buttons in the same glass button group
- Native SwiftUI rendering with
UIMenusupport CNButtonDataPopupItemmodel for popup menu items
- Added:
labelFontFamilyandlabelFontSizeproperties forCNTabBar(PR #26, Issue #16 by @byackee)- Customize tab bar label font with any registered font family
- Dynamic font updates via method channel
Bug Fixes
- Fixed:
buttonCustomIconColornow works on iOS 26 with Liquid Glass rendering (PR #24, Issue #21 by @byackee)- Color is now sent to the native side via
capturedButtonIconColor - Native side applies
.withTintColor(.alwaysOriginal)to preserve custom icon colors - Menu item
iconColoralso supported for customIconDataicons
- Color is now sent to the native side via
- Fixed:
CNSwitchno longer pushed upward by keyboard (PR #25, Issue #4 by @byackee)- iOS 16.4+: uses
safeAreaRegions.remove(.keyboard)official API - Pre-iOS 16.4: runtime fix targeting the hosting view's private keyboard notification handler
- iOS 16.4+: uses
- Added: Popup menu button support in
-
1.3.617 Mar 2026Release notes
Open source →Bug Fixes
- Fixed: Horizontal glass button group "waist" effect — reduced toolbar shrinkage between adjacent buttons by enforcing minimum 80pt glass spacing for horizontal groups with 2+ buttons (PR #20 by @byackee)
- Fixed:
CNTabBarnow shows a Flutter fallback tab bar while the native view initializes, instead of blank space for ~2 seconds (Issue #5) - Fixed:
CNTabBarwith 5 items no longer has sporadic missing labels — added a second refresh pass for slow-to-initialize native views (Issue #6)
Improvements
- Added: macOS podspec for CocoaPods support (Issue #10)
-
1.3.506 Mar 2026Release notes
Open source →Bug Fixes
- Fixed:
CNTabBariconSizenow correctly applies toCNImageAsset(SVG/image) icons (Issue #19)- Previously, only SF Symbol icons respected the
iconSizeproperty - Image assets loaded via
loadFlutterAssetandcreateImageFromDatanow receive the size parameter
- Previously, only SF Symbol icons respected the
- Fixed:
-
1.3.402 Feb 2026Release notes
Open source →New Features
- Added:
interactionproperty forCNButtonConfigandCNButtonDataConfig(PR #15 by @anirudhrao-github)- Allows disabling button touch handling without changing visual appearance
- When
interaction: false, button maintains normal look but doesn't respond to touches - Useful for conditional interactivity while preserving UI consistency
Improvements
- Improved:
LiquidGlassContainerlayout simplified for better parent alignment control
- Added:
-
1.3.314 Jan 2026Release notes
Open source →New Features
-
Added:
customIconSizeproperty forCNButtonConfigandCNButtonDataConfig(PR #12 by @anirudhrao-github)- Allows customizing the size of custom icons (IconData) in buttons
- Previously hardcoded to 20.0 points, now configurable
-
Added:
iconSizeproperty forCNTabBarto control SF Symbol icon sizes- Supports dynamic icon sizing with automatic height adjustment
- Note: Icons above 30pt may have minor visual quirks due to UITabBar constraints
Bug Fixes
-
Fixed:
CNGlassButtonGroupno longer forces equal width on all buttons (PR #12 by @anirudhrao-github)- Buttons now use their intrinsic width based on content
- Label buttons can now be wider than icon-only buttons in the same group
- Uses SwiftUI
.fixedSize(horizontal: true, vertical: false)for proper sizing
-
Fixed:
CNTabBar.onTapnow fires for reselects (Issue #13)- Previously, tapping the already-selected tab did not trigger the callback
- Now all taps fire
onTap, allowing scroll-to-top or navigation reset on reselect
-
Fixed:
CNTabBaricon clipping on iOS 26+ Liquid Glass- Disabled
clipsToBoundson iOS 26+ to allow proper Liquid Glass pill overflow - Tab bar height now adjusts dynamically based on icon size
- Disabled
Improvements
- Improved: Initial layout rendering for
CNGlassButtonGroup- Added immediate layout pass after view creation for correct first render
-
-
1.3.231 Dec 2025Release notes
Open source →New Features
- Added: Badge support for
CNGlassButtonGroupicon buttons (PR #11 by @anirudhrao-github)- New
badgeCountproperty onCNButtonData.icon()for displaying notification badges - Badges display as red circles with white text, showing "99+" for counts over 99
- Uses UIKit overlay on iOS to prevent glass effect sampling artifacts
- Proper clipping during page transitions
- New
Improvements
-
Improved: Added library-level documentation for better API discoverability
- Enhanced dartdoc comments for
button,button_data,button_style, andcupertino_nativelibraries - 91.4% API documentation coverage
- Enhanced dartdoc comments for
-
Fixed: Dart formatting issues for pub.dev compliance
- Resolved formatting in
button.dartandglass_button_group.dart - Achieves 160/160 pana score
- Resolved formatting in
- Added: Badge support for
-
1.3.128 Dec 2025Release notes
Open source →Bug Fixes
- Fixed: Tint color now works correctly when buttons are inside
CNGlassButtonGroup(PR #8 by @anirudhrao-github)- Previously, button tint colors were ignored when placed inside grouped glass buttons
- Now buttons properly inherit and display their configured tint colors within button groups
- Fixed: Tint color now works correctly when buttons are inside
-
1.3.015 Dec 2025Release notes
Open source →New Features
-
Added:
CNTabBarNative- Native iOS 26 Tab Bar with full UITabBarController integration- Uses native
UITabBarController+UISearchControllerfor authentic iOS 26 liquid glass effects CNTabBarNative.enable()/CNTabBarNative.disable()for app-level tab bar managementCNTabclass for tab configuration with SF Symbols and search tab support- Callbacks:
onTabSelected,onSearchChanged,onSearchSubmitted,onSearchCancelled,onSearchActiveChanged - Full badge count support and dynamic styling
- Uses native
-
Added:
CNSearchScaffold- Native search scaffold controller for standalone search UI -
Added:
CNToast- Toast notification widget with Liquid Glass effects- Static methods:
show(),success(),error(),warning(),info(),loading() - Duration presets: short (2s), medium (3.5s), long (5s)
- Position options: top, center, bottom
- Auto-dismiss with queue management
CNLoadingToastHandlefor dismissing loading toasts
- Static methods:
-
Added:
labelproperty toCNTabBarSearchItemfor customizing the search tab label- Defaults to 'Search' to match iOS native behavior
-
Added:
preserveTopToBottomOrderproperty toCNPopupMenuButton(Issue #3)- When
true, menu items maintain top-to-bottom order (1,2,3,4) regardless of menu direction - Default
falsepreserves native iOS behavior where item 1 stays closest to the button - Uses
UIDeferredMenuElement.uncachedfor dynamic position detection
- When
Improvements
-
Enhanced:
PlatformVersionnow auto-initializes on first access- No longer need to call
await PlatformVersion.initialize()inmain() - Just use
PlatformVersion.isIOS26OrLaterdirectly - Old
initialize()method kept for backwards compatibility (marked deprecated)
- No longer need to call
-
Added: New helper properties to
PlatformVersion:isIOS,isMacOS,isAndroid,isAppleisIOSVersionInRange(min, max),isMacOSVersionInRange(min, max)
Bug Fixes
-
Fixed:
CNPopupMenuButton.iconnow respects the order defined in items (Issue #3)- Added
preserveTopToBottomOrderparameter to control item ordering behavior - Native iOS behavior keeps first item closest to button; set
preserveTopToBottomOrder: truefor consistent top-to-bottom order
- Added
-
Fixed: Tab bar shadow artifact appearing over modals and bottom sheets (Issue #2)
- Changed
configureWithDefaultBackground()toconfigureWithTransparentBackground() - Added explicit shadow removal:
shadowColor = .clear,shadowImage = UIImage() - Added
container.clipsToBounds = trueandlayer.shadowOpacity = 0
- Changed
-
Fixed: Search bar keyboard auto-opening behavior (Issue #1)
automaticallyActivatesSearch: falsenow properly prevents keyboard from auto-opening- This is native iOS behavior - the search bar expands but keyboard only opens on text field tap
-
-
1.2.004 Dec 2025Release notes
Open source →New Features
-
Added: iOS 26 Search Tab Feature for CNTabBar with animated Liquid Glass expansion
- Native
UISearchTab-style search integration that follows Apple's iOS 26 design - Search button expands into a full search bar with smooth spring animation
- Tabs collapse to icon-only mode when search is active
- Full Flutter fallback for iOS < 26 with identical behavior
- Native
-
Added:
CNTabBarSearchItemconfiguration class for search tab customizationplaceholder: Custom placeholder text for the search fieldonSearchChanged: Callback for live filtering as user typesonSearchSubmit: Callback when user submits searchonSearchActiveChanged: Callback for expand/collapse state changesautomaticallyActivatesSearch: Control keyboard auto-activation behavior
-
Added:
CNTabBarSearchStylefor visual customization- Icon sizes, colors, and active states
- Search bar dimensions, padding, and border radius
- Animation duration control
- Clear button visibility toggle
-
Added:
CNTabBarSearchControllerfor programmatic search controlactivateSearch()/deactivateSearch(): Expand/collapse search programmaticallytextproperty: Get/set search textclear(): Clear search text with optional deactivation- Listener support for reactive state management
Improvements
- Enhanced:
automaticallyActivatesSearchnow properly controls keyboard behavior- When
false: Search bar expands but keyboard only opens when user taps the text field - When
true(default): Keyboard opens automatically when search expands - Mirrors
UISearchTab.automaticallyActivatesSearchfrom UIKit
- When
Bug Fixes
- Fixed:
MissingPluginExceptionerrors during hot reload forsetItemsandrefreshmethods- Added try-catch error handling to prevent crashes during development
- Search view now handles all expected method channel calls
-
-
1.1.929 Nov 2025Release notes
Open source →New Features
- Added: Lightweight
setBadgesmethod for CNTabBar to update badge values without rebuilding the entire tab bar- Previously, badge updates required recreating all tab bar items which caused visible flicker
- New implementation only updates
badgeValueon existing UITabBarItems for smooth, instant badge changes - Automatically detected when only badges changed (not labels, icons, or symbols) and uses fast path
Improvements
- Optimized: CNTabBar now detects badge-only updates in
_syncPropsToNativeIfNeeded()and calls lightweight nativesetBadgesmethod instead of fullsetItemsrebuild - Performance: Badge updates are now instant with no view recreation or animation interruption
- Added: Lightweight
-
1.1.829 Nov 2025 -
1.1.729 Nov 2025Release notes
Open source →Fixes
-
Fixed: Split mode tab selection bug where the wrong tab appeared selected on first load
- Issue: When using
split: truein CNTabBar, the right bar (e.g., Rewards tab) would incorrectly appear selected even when the left bar tab (e.g., Discover) was actually selected - Root Cause: In the
refreshmethod, when restoring selection after cycling through tabs for label rendering, the code was incorrectly settingright.selectedItem = rightItems.firstwhenrightOriginalwas nil - Solution: Changed to restore the original selection directly (
right.selectedItem = rightOriginal), which correctly keeps the right bar unselected when a left bar tab is active
- Issue: When using
-
Fixed: Added
setSelectedIndexcall afterrefreshin Flutter widget to ensure correct selection state after view initialization
-
-
1.1.629 Nov 2025Release notes
Open source →Fixes
- Fixed: Attempted fix for split mode tab selection (superseded by 1.1.7)
-
1.1.529 Nov 2025Release notes
Open source →Breaking Changes
- iOS Minimum Version: Raised iOS deployment target from 13.0 to 15.0
- Required for
@FocusStateand other iOS 15+ SwiftUI features - Most production apps already target iOS 15+ (released September 2021)
- Required for
Fixes
- Fixed: Swift compiler error
'FocusState' is only available in iOS 15.0 or newer - Fixed: Swift compiler error
'self' used before 'super.init' callin CNSearchBar - Fixed: Pod installation issues when used in projects with iOS 15+ deployment target
- iOS Minimum Version: Raised iOS deployment target from 13.0 to 15.0
-
1.1.429 Nov 2025 -
1.1.329 Nov 2025Release notes
Open source →Fixes
- Fixed: Full 50/50 pub.dev static analysis score (160/160 pana points)
- Fixed: All remaining lint and formatting issues
-
1.1.228 Nov 2025 -
1.1.128 Nov 2025 -
1.1.028 Nov 2025Release notes
Open source →Documentation Overhaul
- Added: Complete documentation for all widgets with real iOS 26 screenshots
- Added: CNSwitch documentation with controller examples
- Added: CNPopupMenuButton documentation with text and icon variants
- Added: CNSegmentedControl documentation with SF Symbols support
- Added: Button Styles Gallery showcasing multiple button styles
- Added: Popup menu opened state preview image
- Enhanced: Features table with Controller column
- Enhanced: All images now use centered alignment for better presentation
New Screenshots
- Real iOS 26 Liquid Glass component screenshots (replacing AI-generated placeholders)
- Button styles gallery (4 preview images)
- Switch, Slider, Popup Menu, Segmented Control, Tab Bar previews
- Popup menu opened state preview
Test Suite Updates
- Added: Comprehensive widget tests for CNSearchBar, CNFloatingIsland, CNGlassButtonGroup
- Added: Controller tests for CNSearchBarController, CNFloatingIslandController, CNSliderController
- Added: Data model tests for CNButtonData, CNButtonDataConfig, CNSymbol, CNImageAsset
- Updated: Platform and method channel tests with error handling and null response tests
- Updated: Enum tests for all new enums (CNGlassEffect, CNGlassEffectShape, CNSpotlightMode, etc.)
- Total: 82 tests covering all major components and APIs
-
1.1.0-prerelease.128 Nov 2025 pre-releaseNothing published for this version
-
1.1.0-prerelease28 Nov 2025 pre-releaseNothing published for this version
-
1.0.623 Nov 2025Release notes
Open source →Improvements
- Fixed: Dart formatting issues to achieve full 50/50 static analysis score on pub.dev
- Added: Preview image for pub.dev package page
-
1.0.523 Nov 2025Release notes
Open source →Improvements
Static Analysis Cleanup
- Fixed: All
use_build_context_synchronouslywarnings by capturing context-derived values before async gaps - Fixed:
dangling_library_doc_commentswarning - Fixed:
unnecessary_library_nameandunnecessary_importwarnings - Improved: Pub points score (static analysis section)
- Fixed: All
-
1.0.423 Nov 2025Release notes
Open source →Bug Fixes
CNButton Tap Detection (iOS < 26 Fallback)
- Fixed: Unreliable tap detection in CupertinoButton fallback mode
- Issue: Buttons showed press animation but
onPresseddidn't fire consistently - Solution: Added
minSize: 0to prevent CupertinoButton's internal minimum size from conflicting with SizedBox constraints - Added: Explicit
borderRadiusandpressedOpacityfor better hit testing and visual feedback
-
1.0.323 Nov 2025Release notes
Open source →Bug Fixes
Critical: iOS 18 Crash Fix
- Fixed: Reverted GestureDetector overlay that caused crash on iOS 18
- Error:
unrecognized selector sent to instance 'onTap:' - Solution: Removed Stack/GestureDetector approach, kept simple CupertinoButton
Icon Button Padding (kept from 1.0.2)
- Fixed: Increased default padding for icon buttons from 4 to 8 pixels
-
1.0.223 Nov 2025Release notes
Open source →Bug Fixes
CNButton Tap Detection (iOS < 26 Fallback)
- BROKEN: Added GestureDetector overlay that crashed on iOS 18
- Use 1.0.3 instead
Icon Button Padding
- Fixed: Increased default padding for icon buttons from 4 to 8 pixels
- Icons now have proper breathing room from the button border
-
1.0.121 Nov 2025Release notes
Open source →- Pub Points Improvement: Addressed static analysis issues to improve package score.
- Fix: Resolved
use_build_context_synchronouslywarnings across multiple components. - Fix: Replaced deprecated
Color.valueandwithOpacityusages with modern alternatives. - Documentation: Added missing documentation for public members.
-
1.0.021 Nov 2025Release notes
Open source →Major Release - Complete iOS Fallback Fixes
This release addresses critical issues that caused components to malfunction on iOS versions below 26.
Breaking Changes
- Package renamed from
cupertino_native_plustocupertino_native_better - Main import changed to
package:cupertino_native_better/cupertino_native_better.dart
Bug Fixes
CNButton Label Disappearing (iOS < 26)
- Fixed: Buttons with both icon AND label now correctly display both elements in fallback mode
- Root Cause:
widget.isIconwas returningtruefor any button with an icon, even if it also had a label - Solution: Changed fallback check to
widget.isIcon && widget.label == nullto only treat truly icon-only buttons as icon-only
CNTabBar Icons Not Showing (iOS < 26)
- Fixed: Tab bar icons now render correctly using CNIcon instead of empty placeholder circles
- Root Cause: Fallback code only checked for
customIcon, ignoring SF Symbols (icon/activeIcon) - Solution: Added
_buildTabIcon()helper that properly handles all icon types with correct priority
CNIcon/CNButton/CNPopupMenuButton Showing "..." (iOS < 26)
- Fixed: All CN components now properly render SF Symbols on older iOS versions
- Root Cause: Components were checking
shouldUseNativeGlass(iOS 26+) for SF Symbol support, but SF Symbols work on iOS 13+ - Solution: Added new
supportsSFSymbolsgetter that always returns true on iOS/macOS
New Features
- Added
PlatformVersion.supportsSFSymbolsfor checking SF Symbol availability (iOS 13+, macOS 11+) - Comprehensive dartdoc documentation for all public APIs
- Full comparison table with other packages in README
Documentation
- Complete rewrite of README with feature comparison
- Migration guide from cupertino_native_plus
- Comprehensive code examples for all widgets
- Package renamed from