Page Transitions
rivella50 opened this issue · 7 comments
Hi there,
i would like to implement outstanding page transitions for my current Flutter game and was wondering if your package could be used for using e.g. this shader as a page transition between two pages in the transitionsBuilder
part of a PageRouteBuilder
?
My idea is to wrap the target page with AnimatedBuilder->ShaderBuilder->AnimatedSampler where the shader could output values for finally showing that page to the user.
Would that somehow be possible? Or do you have another idea how page transitions using shaders could be realized?
Thank you very much.
I think I have some code around here somewhere that makes it easy to use a shader with a page transition builder, let me see if I can find it. That would be a reasonable addition to this package.
That would be awesome. I was trying something like this but at the moment i only get back a black screen when trying to go to Page2:
Route _createRoute(BuildContext context) {
Page2 targetPage = const Page2();
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => targetPage,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return TweenAnimationBuilder(
tween: Tween(begin: 0.0, end: 1.0),
duration: Duration(milliseconds: 500),
curve: Curves.easeIn,
child: child,
builder: (BuildContext context, double value, Widget? child) {
return ShaderBuilder(
(context, shader, _) {
return AnimatedSampler(
(image, size, canvas) {
shader.setFloat(0, 20);
shader.setFloat(1, value);
shader.setFloat(2, size.width);
shader.setFloat(3, size.height);
shader.setImageSampler(0, image);
},
child: targetPage,
);
},
assetKey: 'assets/shaders/shader.frag',
);
},
);
}
);
}
Ok i got it working for the target page:
https://github.com/jonahwilliams/flutter_shaders/assets/54292/5b18403a-e232-445e-a822-1c7beb0ded43
The only missing thing is having access to the from page image in order to do decisive renderings like this in the .frag file:
fragColor = nextImage ? texture(toImage, uv) : texture(fromImage, uv);
This is where an update of your package could help. I have something like this in mind:
return AnimatedSamplerForTransition(
(fromImage, toImage, size, canvas) {
// perform all shader inputs
shader.setImageSampler(0, fromImage);
shader.setImageSampler(1, toImage);
canvas.drawRect(
Rect.fromLTWH(0, 0, size.width, size.height),
Paint()..shader = shader,
);
},
from: context.widget, // represents the currently shown page
to: targetPage,
);
Ahh I think I remember why I was having problems with this. Its fairly easy to run a shader over a single page as part of a page transition, but getting both pages requires some cooperation from the theme objects. let me think about this one for a bit.
Ok, i will also continue my investigations.
From what i've seen is that e.g. ZoomPageTransitionsBuilder can take snapshots for its routes by using SnapshotWidget. Perhaps this could be an approach in order to get the image from the current page.
I got it working:
https://github.com/jonahwilliams/flutter_shaders/assets/54292/10013873-4764-4d1f-879a-da8024003543
The caveat is that the page which serves as the from page needs to be wrapped with a RepaintBoundary
and a GlobalKey
being applied to its key
field.
// build method of the from page
@override
Widget build(BuildContext context) {
return RepaintBoundary(
key: scr,
child: Scaffold(
...
With that a ui.Image
can be taken by calling this method:
final scr = GlobalKey();
ui.Image _takeSnapshot() {
RenderRepaintBoundary b = scr.currentContext!.findRenderObject() as RenderRepaintBoundary;
return b.toImageSync();
}
and used as the ImageSampler
input for the shader.
So in general it would work, but if you have a better solution which doesn't need the wrapping with RepaintBoundary
(perhaps this could be done ad hoc?) that would be great.
EDIT: Using this method (slightly modified) from Screenshot package it works without wrapping the from page with RepaintBoundary
.
EDIT2: After further tests i've seen that using the method from EDIT doesn't work with a StatefulWidget
, since that widget will be recreated which loses its state (that's probably what you meant with cooperation from the theme objects) and results in a image with the widget's initial state. I haven't found yet a solution which allows keeping that state when trying to generate an image (except of course wrapping the from page widget with RepaintBoundary
).
Hi Jonah,
so for the moment i ended up with this solution:
- using your package in order to simplify the incorporation of shaders for page transitions incl. receiving an
ui.Image
of the target page - using the Screenshot package in order to getting a wrapper for the
RepaintBoundary
/GlobalKey
stuff which helps receiving anui.Image
of the from page
Of course 2 packages are needed to accomplish this - which is ok for me.
If you still think that extending your package with page transitions support would be a reasonable idea then you could try to include the RepaintBoundary
/GlobalKey
functionality (or a similar approach) in your package where as a result the builder
callback for AnimatedSampler
(or a variant of it for transitions) then could offer both the from and target ui.Image
, which would make the Screenshot package obsolete.
I'm looking forward to your opinion.