simple_parallax 2.3.2
simple_parallax: ^2.3.2 copied to clipboard
Parallax widgets for Flutter, in pure Dart with no dependencies. A container mode and a per-item mode, either axis, with a drift, a zoom, a blur and an overlay set on their own.
SimpleParallax Versions #
2.3.2 #
Changed #
- A
SimpleParallaxItemgiven its extent along the scroll no longer reads the screen size, so it is not rebuilt when the window is resized. - Internal cleanup, no change in behaviour: the item's
buildis split into smaller parts, the overscan of the layer is worked out in one place, and whether the wheel is eased is decided by one function shared by both views.smoothis now a getter; reading it gives the same value. - The tests are split by topic into eight files.
2.3.1 #
Fixed #
- Turning
smoothon or off on a view already on screen no longer sends it back to the top. The view was built anew, since the easing wrapped it in a widget of its own only when it was on; that widget now stays in place either way and hands the view another controller, whose position takes over the offset. On iOS and Android a view with no controller is the primary one, which Flutter builds differently, so going from no easing to easing there still builds it anew; the easing is off by default on those platforms, which have no wheel to ease.
2.3.0 #
Added #
placeholderColor,fadeInanderrorBuilderon both widgets, for animagestill loading or failing. The colour fills the background until the picture is decoded, the picture fades in over it, and the builder takes its place if it cannot be loaded. An image the cache already holds is drawn at once, and the fade is left out under reduced motion. Until now this took abackgroundwidget, which gave up the decoding at the size drawn.- The example's five hundred blocks fade in over a placeholder.
- A sixth README animation, a carousel in a page with each card drifting both ways.
- The example's recorders decode the pictures the way the widgets draw them. They precached the asset, which the widgets no longer use since they decode at the size drawn, and could have recorded blank backgrounds. Regenerated this way, the five animations and four screenshots already published match the library, so they are left as they are.
Fixed #
- A background kept its first size when the widget changed in place: a new
scrollDirection, a newoverscan, or acrossParallaxadded or removed left the layer laid out for the old one, so part of the view went uncovered as it drifted. The flow now lays it out again.
Changed #
- The
.sliversconstructor documents how a list built lazily estimates its extent, and what to hand it for the background to follow the scroll exactly.
2.2.0 #
Added #
crossParallaxonSimpleParallaxItem, a drift along the other axis that follows the nearest scrollable running that way. A block in a horizontal carousel inside a vertical page can now slide sideways with the carousel and downwards with the page at the same time, each axis at its own speed and overscan. The background is drawn larger on both axes for it, and decoded to match. The zoom and the blur keep following the main scrollable, and nothing changes when it is leftnull.- A third row in the example's carousel screen, following both.
Fixed #
- A line of the
decodeAtDisplaySizedocumentation broke in the middle of a sentence.
2.1.0 #
Added #
respectReducedMotionon both widgets, on by default. When the platform asks for reduced motion (Reduce Motion on iOS, Remove animations on Android,prefers-reduced-motionon the web), the container holds its background at the top of its travel and each item draws its block as it looks in the middle of the screen, zoom and blur included. The smooth wheel lands each notch in one step, still bringing it to a horizontal view. Passfalsefor the previous behaviour.controllerandphysicsonSimpleParallaxContainer, asSimpleParallaxWidgetalready had.SmoothScrollControlleris exported. Given as thecontrollerof either scroll view, it keepssmoothon, so the view can be driven from outside with the wheel still eased. Any other controller turnssmoothoff unless it is asked for, and asking for both is an error.SimpleParallaxWidget.builder, which creates its blocks as they come into view instead of taking them all as a list.decodeAtDisplaySizeon both widgets, on by default. Animageis decoded at the size it is drawn, worked out from the layer, the overscan, the zoom and the pixel density, instead of at full resolution: a photo of 4000 by 3000 pixels in a block of 300 no longer sits in memory at full size. The size is rounded up so a small resize reuses the decode, and an image aResizeImagealready sizes is left alone. Turn it off when one decoded copy should serve a full-size view of the same image elsewhere, and when the image is warmed up withprecacheImage, which decodes the full-size copy the widget would no longer use.alignmentandborderRadiusonSimpleParallaxItem.alignmentwas only on the container;borderRadiusclips the whole block, which a card needs and which took aClipRRectaround the item until now.restorationId,keyboardDismissBehaviorandclipBehavioron both scroll views, handed to theCustomScrollViewunder them.scrollAxisonSimpleParallaxItem, to follow a scrollable further up than the nearest one. A block in a horizontal carousel inside a vertical page can slide with the page instead of the carousel. The nearest scrollable still lays the block out, soheightandwidthdefault as before.
Changed #
smoothleft unset is off on iOS and Android. There is no wheel to ease there, and the controller the easing needs kept the view from being the primary one, so a tap on the iOS status bar no longer scrolled it back to the top. It stays on on desktop and the web, andsmooth: truestill turns it on anywhere.SimpleParallaxContainerpaints its background from aFlowbound to the scroll metrics, as item mode already did. A scroll used to rebuild the transforms and the blur around the layer on every frame; it now repaints that layer and rebuilds nothing.- With a blur, the progress of the background is measured once per frame instead of twice: the flow works it out and the blur, painted inside the flow, reads it. The layer keeps a repaint boundary of its own, so a scroll moves it without drawing it again.
- The README is down to what it takes to start: the two widgets, the four effects, and a short list of what else there is. The parameter tables are left to the API reference, which already carried every one, and the 1.x migration table moved to the 2.0.0 entry below.
- The example has eleven screens instead of thirteen, grouped in the menu. The zoom and the blur
share one screen, the video joined the other widget backgrounds, and the sideways items became a
carousel in a page. It gains the builder,
scrollAxis, a containercontroller, and a switch that shows every screen under reduced motion.
Fixed #
- Scrolls running the other way. A horizontal container on a right-to-left page drifted its
background against the content instead of with it. An item in a right-to-left list, or in a list
with
reverse: true, read its crossing backwards, so a zoom shrank, a blur cleared andreachcounted from the wrong end. - Item mode did not compile on the oldest Flutter the package admits, 3.22 among them: the zoom used
Matrix4.translateByDoubleandscaleByDouble, which thevector_maththose versions pin does not have. A CI job now builds and runs the package on 3.22.2. - The background is left out of the semantics tree, in both modes and whether it is an
imageor abackgroundwidget. An unlabelled image used to mark its surroundings as an image, so a screen reader announced an item's caption as "Chapter one, image".
2.0.2 #
Changed #
- The README is half the length. The parameter tables stay, and so does what the package is fast at; the tour of every option goes, since the demo shows it running and the API reference carries an example per member.
- The README carries its build badge again, pointed at the branch the repository actually builds from.
SimpleParallaxItemno longer holds aGlobalKeyper item: the flow reads the background size from its own child. The widget is now stateless.
Fixed #
SimpleParallaxContainerignores a nested scrollable on its own axis too. A vertical list inside the content used to drive the background with its own scroll.SimpleParallaxContainerkeeps its background in step when nothing scrolls: a resize, content that grows or shrinks, an offset restored on the first layout, or a newparallax,zoomorblur. The background used to stay where it was until the next scroll.- A horizontal view with
smoothon no longer holds on to the vertical wheel once it has reached the end it is heading for. Inside a vertical page, the page used to stop scrolling under it. - The library example still passed
autoSpeed, which 2.0.0 removed.
2.0.1 #
Changed #
- The README badge row carries the maintainer again, and a licence badge in a colour of its own rather than the grey shields puts in every label. Nothing about the library changed.
2.0.0 #
Every effect is configured on its own object, and a fixed overlay joins them.
Added #
ParallaxProperties,ZoomProperties,BlurPropertiesandOverlayProperties, one per effect. Each carries what belongs to it, so a zoom running the whole way and a blur stopping at the middle now sit in the same widget. In 1.3.0reachandbackwere shared, which made that impossible.overlayon both widgets, a fixed layer of colour over the background and under the content. It does not drift, scale or blur with the background: it stays put while the background moves under it.OverlayProperties.darkenand.lightentake an opacity, the default constructor takes any colour, and.gradienttakes a gradient for a scrim that fades across the image. Six tests.ItemOverlayDemo, a thirteenth example screen showing the three forms one under the other.
Changed #
speedmeans the same thing in both modes: the fraction of the available travel the background uses, from0to1. It used to be a travel per pixel scrolled on the container and a fraction on the item, under one name. Three tests.zoomandblurare nullable, sonullis off and there is no longer a figure that means nothing.smoothdefaults totrueon both scroll views. A wheel notch landing on one frame is exactly what shows on a parallax background, so the flag was set on every screen of the example and on every sample in the README. OnSimpleParallaxWidgetit turns itself off when acontrolleris given, since the easing lives in a controller of the view's own; passing both is still an error. Passsmooth: falsefor the old behaviour.
Removed #
autoSpeed. Aspeedof1, which is the default, spends the whole travel over the whole scroll, which is exactly what the flag did.- The flat
speed,overscan,zoom,blur,reachandbackparameters, replaced by the four objects above, as follows.
Migration #
| Before | Now |
|---|---|
speed: 0.4, overscan: 2 |
parallax: ParallaxProperties(speed: 0.4, overscan: 2) |
autoSpeed: true |
nothing: speed defaults to 1, which is the same thing |
speed: 0.3 on a container |
a fraction now, not a travel per pixel. Pick one between 0 and 1 |
zoom: 0.25 |
zoom: ZoomProperties(0.25) |
blur: 16 |
blur: BlurProperties(16) |
zoom: 0.6, reach: 0.5, back: true |
zoom: ZoomProperties(0.6, reach: 0.5, back: true) |
a hand-rolled scrim in child |
overlay: OverlayProperties.darken(0.45) |
Nothing else moves, except smooth, which now defaults to true. Pass smooth: false for the
platform wheel behaviour.
1.3.0 #
The background can be a widget, it can push in or go soft as it travels, and the mouse wheel works on either axis.
Added #
backgroundon both widgets, which takes the background layer as a widget in place ofimage. The layer is laid out to fill the box the parallax hands it, so a gradient, aStackof several layers, a video, a shader or aCachedNetworkImageall work. It is also how to reach theImageparameters the package does not forward:loadingBuilder,errorBuilderandcacheHeightamong them.zoomon both widgets, the scale the background gains across its travel,0by default. A negative figure runs the same range backwards, so the background starts enlarged and settles instead of pushing in. It turns about the middle of the viewport rather than the middle of the layer, so it leaves the drift alone and the two settings can be given independently. The scale never goes below 1, which would show the page down both sides of the layer. Eight tests.bluron both widgets, the gaussian sigma the background gains across its travel,0by default. It reads likezoom, a negative figure running the same range backwards, so a background can arrive soft and come into focus as well as the other way round. Only the background is filtered: the content over it stays sharp. It is the one setting here that is a filter rather than a transform, so the layer is blurred again on each frame it moves; the sigma is rounded to a quarter of a pixel and a sigma of zero pushes no layer at all. Seven tests.reachandbackon both widgets, which shape where along the travelzoomandblurhappen.reachis the point they are done by,nullby default so they spread over the whole travel;0.5has them finished at the middle of the screen and holding there.backruns the range backwards from that point instead, which makes a zoom in and out, or a background that comes into focus as it passes the eye and goes soft again. With the sign of the effect saying which end it starts from, the three cover six shapes. The drift is never shaped this way. Nine tests.smoothonSimpleParallaxContainerandSimpleParallaxWidget. AScrollablelands a wheel notch on one frame, which a parallax turns into a visible step, and it reads the wheel on its own axis alone, so a sideways view never moves under a plain wheel. The flag eases each notch in and feeds a sideways view the delta it would otherwise drop. Dragging and flinging are untouched. Seven tests.- Seven example screens:
ContainerCustomDemoandItemCustomDemofor the widget background,ContainerVideoDemoandItemVideoDemodrifting a looping video,ItemZoomDemo, which puts a block zooming in above one zooming out so the sign can be read off the screen,ItemBlurDemo, which does the same for the blur, andItemReachDemo, which puts a zoom held at the middle above the same zoom sent back from it. Eight tests. - The README previews are rendered again from the current package, and a fifth is added for the
widget background. They are no longer captured by hand:
example/tool/record_previews.dartdraws each frame from a scroll offset it computes, andexample/tool/assemble_previews.pyturns the frames into the animated WebP files. The motion is exactly regular as a result, and the loop closes on itself. - Four screenshots for pub.dev, declared in the pubspec and rendered from the example's own
screens by
example/tool/record_screenshots.dart, so one cannot show what the example does not. - The example is rebuilt: twelve screens behind a menu, a way back over each one, inset cards that
leave the background visible, captions on a scrim, and
smoothset throughout. It also shows theScrollBehaviora desktop needs for a mouse to drag a list at all, which the package leaves to the app. Its content is the copy the README previews use, so the two show the same thing.
Fixed #
- An item's background stood still for the first and last stretch of the block being on screen. The
effect was measured from the middle of the block against the viewport alone, so it only ran while
that middle crossed, which is
viewportof scrolling out of theviewport + heightthe block is visible for. On a block half as tall as the screen that was a third of the way in and a third of the way out with nothing moving. It now runs from the moment the leading edge appears to the moment the trailing edge goes. The drift and the zoom both cover the whole crossing as a result, and both read as stronger for the samespeedandzoom.
Changed #
imageis now optional, and exactly one ofimageandbackgroundmust be given, which an assert checks. No constructor was added: the container still has two, one per content form, and the item still has one. What the background is made of is a parameter, not a constructor name.imageis nullable, so code readingwidget.imagefrom the outside now has a null to handle. Nothing changes at a call site.fitandalignmentapply toimageonly: a widget background fills the layer as it stands.
1.2.1 #
Modify topic widgets to sliver in to pubspec.yaml
1.2.0 #
Both scroll views move to slivers.
Added #
SimpleParallaxContainer.slivers, which takes the content as a list of slivers instead of a single child. The content then builds as it scrolls, and aSliverAppBaror aSliverGridcan ride over the background. On a long list prefer a fixedspeed:autoSpeedspreads the traveloverscanallows over the whole extent, so the drift becomes imperceptible.- A fifth example screen,
ContainerSliversDemo.
Changed #
SimpleParallaxContainerbuilds aCustomScrollViewrather than aSingleChildScrollView. The default constructor putschildin aSliverToBoxAdapter, which lays it out exactly as before.SimpleParallaxWidgetbuilds aCustomScrollViewover oneSliverListrather than aSingleChildScrollViewover aColumnor aRow, so its blocks build as they come into view. Two consequences, both of themListViewbehaviour: a block is laid out across the full cross axis instead of being centred on it, and a block outside the viewport is not in the tree. Pass a block that must keep a narrower cross extent through anAlignor aCenter.
1.1.1 #
Documentation and example, no library change.
- The example covers all four combinations, two modes by two axes, behind a menu. They share
example/lib/main.dartbecause that is the only file pub.dev renders on the example tab, so the three separate entry points only ever showed one of them there. - The four preview animations are redone in one format, 520x260 at 25 frames a second, and laid out as a grid: modes in rows, axes in columns. 1.1.0 shipped before they were regenerated, so its README sized the vertical pair as portrait.
1.1.0 #
Horizontal parallax.
Added #
SimpleParallaxContainer.scrollDirectionandSimpleParallaxWidget.scrollDirection. The background drifts along the scrolled axis, andoverscansizes it on that axis.SimpleParallaxItemreads the axis from the scrollable it sits in, so it slides sideways in a horizontal list with nothing to pass. Itsheightandwidthdefaults swap accordingly: the scrolled axis falls back to the screen extent, the cross axis to the incoming constraints.SimpleParallaxContainer.width, the horizontal counterpart ofheight.- A horizontal example,
example/lib/main_horizontal.dart, and horizontal previews in the README.
Fixed #
SimpleParallaxContainerignores scroll notifications from a nested scrollable running on the other axis, which used to drag the background along.
1.0.2 #
Add animated previews in to README.md
1.0.1 #
Improve example and comments.
1.0.0 #
Rewrite. Breaking changes, see the migration table below.
Changed #
- The package is no longer a Flutter plugin. The
android,ios,linux,macosandwindowsfolders held nothing but theflutter create --template=pluginscaffold, whose only method was never called from Dart. They are gone, along with theflutter: plugin:declaration andlib/simple_parallax_web.dart. - No dependencies left beyond the Flutter SDK.
providerwas replaced byValueListenableBuilderand byFlow, both from the SDK, andflutter_web_pluginswent with the plugin declaration. - Both widgets now take an
ImageProviderinstead of an asset path, so network images, files and raw bytes work. decalis renamedoverscan, which is what it actually controls.SimpleParallaxItemfinds the enclosingScrollableon its own. It works inside aListView, aCustomScrollViewor any other scroll view, and no longer throws when used outsideSimpleParallaxWidget.SimpleParallaxItem.speedis now a0..1fraction of the available travel, default1.0.autoSpeedderives the speed from the real scroll extent instead of requiring the caller to put aGlobalKeyon their child, which was undocumented and silently did nothing when absent.SimpleParallaxWidgetgainedcontroller,paddingandphysics.
Fixed #
- Scrolling rebuilt the whole subtree, content included, on every frame: the
Consumerwrapped the user's widgets. Container mode now rebuilds only the background transform, behind aRepaintBoundary, and item mode repaints without rebuilding anything at all. - Two
ChangeNotifierinstances were never disposed, one per parallax item and one per parallax widget. _key.currentContext!.findRenderObject()!in a post-frame callback crashed when the item left the tree before the next frame. The measurement now happens at paint time, with no force-unwrap.setStatewas called from a post-frame callback without checkingmounted.- The scroll notification was swallowed by returning
true, so an ancestor listener never saw it. - A non-finite scroll metric could place the background nowhere.
- The background could travel past its overscan and uncover its bottom edge; the offset is clamped.
Removed #
providerandflutter_web_pluginsdependencies.- Dead code:
ScrollNotifier.speedandsetSpeed, never called, and the unused scroll offset on the per-item notifier. - Two lints removed from Dart years ago, still listed in
analysis_options.yaml.
Added #
- A test suite. There was none.
Migration #
| Before | Now |
|---|---|
imagePath: 'assets/a.webp' |
image: AssetImage('assets/a.webp') |
decal: 1.5 |
overscan: 1.5 |
SimpleParallaxItem(speed: 0.3) |
speed is a 0..1 fraction, default 1.0 |
SimpleParallaxItem only inside SimpleParallaxWidget |
works inside any scrollable |
0.1.1 #
- Improved README.md
0.1.0 #
- Add parallax mods container and widget.
- Rename all classes
0.0.2 #
- Add comments
- Update depedencies
0.0.1 #
- Initial release