How to shift a Text by 100% with flutter? - flutter

let's say I have a Stack that takes all the device's width, in this Stack, I have a TextButton widget which I want to shift by 100% to hide on the right side of the Stack. How could I achieve that ?
Context : The goal is to make a component that the user can swipe, when swiping to the left on this component, the TextButton widget appears from the right. Hope that was clear.

There's a flutter widget for that, called dismissible, take a look on those links:
https://www.youtube.com/watch?v=iEMgjrfuc58
https://docs.flutter.dev/cookbook/gestures/dismissible

You can use Animated Container and wrap it inside the gesture detector. Detect the horizontal drag/swipe and then increase the width of the container. It will give the impression that the text button is appearing from the right.
Try this:
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
double _width = 0;
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return GestureDetector(
onPanUpdate: (details) {
if (details.delta.dx > 0){
print("Dragging in +X direction");
setState(() {
_width = size.width;
});
}
else
print("Dragging in -X direction");
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 500),
width: _width,
height: 100,
child: Text('Your text goes here...'),
),
);
}
}
Hope it helps. :)

Related

How to change the scroll physics using CarouselSlider in Flutter?

For example, if someone swiped the carousel once quickly, it would spin from 1 to 100 (currently its quite stiff and moves about 2 places).
I have tried to achieve this by creating a CustomScrollPhysics class that extends ScrollPhysics, and overriding the SpringDescription but this doesn't seem to work and not really sure if this is the right way to go about this?
class CarouselSpring extends StatefulWidget {
const CarouselSpring({Key? key}) : super(key: key);
#override
State<CarouselSpring> createState() => _CarouselSpringState();
}
class _CarouselSpringState extends State<CarouselSpring> {
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final List<int> items = [];
for (int i = 0; i < 100; i++) {
items.add(i);
}
return Scaffold(
body: Center(
child: SizedBox(
height: size.height * 0.50,
width: size.width * 0.50,
child: CarouselSlider(
items:
items.map((e) => Center(child: Text(e.toString()))).toList(),
options: CarouselOptions(
scrollPhysics: CustomScrollPhysics(),
),
),
),
),
);
}
}
class CustomScrollPhysics extends ScrollPhysics {
static final SpringDescription customSpring =
SpringDescription.withDampingRatio(mass: 1, stiffness:99);
#override
SpringDescription get spring => customSpring;
}
Thanks to the link provided by #pskink, I just needed to override the applyTo method in the CustomScrollPhysics class which extends ScrollPhysics.
Now I can adjust the scroll physics (e.g. here can spin through really fast on one flick).
class CustomScrollPhysics extends ScrollPhysics {
static final SpringDescription customSpring =
SpringDescription.withDampingRatio(mass: 200, stiffness:1);
#override
CustomScrollPhysics applyTo(ScrollPhysics? ancestor){
return CustomScrollPhysics();
}
#override
SpringDescription get spring => customSpring;
}

strange and unexpected values if widget get rotated

i have the following full simple code
import 'dart:developer';
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
var globalKey = GlobalKey();
getCurrentOffest(){
RenderBox renderBoxRed = globalKey.currentContext!.findRenderObject() as RenderBox;
log(renderBoxRed.localToGlobal(Offset.zero).toString());
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: RotatedBox(
quarterTurns: 0,
child: GestureDetector(
onTap: (){
getCurrentOffest();
},
child: Container(
key: globalKey,
color: Colors.red,
width: 250,
height: 250,
),
),
),
);
}
}
Now as shown , i provided global key to my red Container in order to know the current offset of where my red Container is located , as long as my container is not rotated yet (quarterTurns: 0,) it prints correct result . when i tap on it.. it show the following
Offset(0.0, 0.0)
and that's seems correct .
But when i rotate my Container using quarterTurns from zero to 2 and get to know the current offset it prints the following
Offset(250.0, 250.0)
How ? Why? Where did these values come from?
my container is still at his offset also i gave the width and height same value in order to make sure there is no any effect of rotation !!!
why this happening ? How Could i prevent these weird values ?
EDIT
that's happening because offset collocate the values according to the firt point in widget (dx ,dy)and when widget get rotated so the first point is also rotated .. i think the best way is to know the center point offset in widget to avoid this behavior but how to know the center offset ?

Flutter -- Problem with Image FrameBuilder

I'm using framebuilder within Listview.builder to fade in a list of images. It is a very nice effect. One problem I am having though: when I Navigator.pop back to this image list screen, the images keep fading in. In this case, considering they are already loaded, shouldn't this not happen? Thank you in advance.
Image.file(
File(Words.fromJson(jsonDecode(wordData[index])).imagePath),
gaplessPlayback: true,
frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
if (wasSynchronouslyLoaded) {
return child;
} else {
return AnimatedOpacity(
child: child,
opacity: frame == null ? 0 : 1,
duration: const Duration(seconds: 1),
curve: Curves.easeOut,
);
}
},
cacheWidth: 200,
fit: BoxFit.cover,
),
Have you tried wrapping the class where your Image is being loading with this? :
class MyWidget extends StatefulWidget {
#override
State<StatefulWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
return Container(
// Image Code
);
}
}

How do I manually calculate layout in Flutter

I would like to put the following widgets into a SingleChildScrollView, but I want the blue box to lie right below the fold when the page renders. The user can choose to scroll it into view as needed, but to start with, it is out of the view.
I see a simple way of achieving this if I could calculate the space my red and green boxes are occupying in the screen and setting the top margin of the red box to the remaining space. A complication is that the height of the red and green boxes is dynamic based on their content, as well as the width of the boxes in portrait vs landscape layouts.
Perhaps I should use a SizedBox instead of adjusting the margin of my red box, which won't be a problem. But I still need to be able to calculate the height of the blank space at the top of my layout.
#pskink had the right idea. Here is what I did with it in code to achieve the layout.
enum AuthWidgets { form, action, disclaimer }
class AuthLayoutDelegate extends MultiChildLayoutDelegate {
AuthLayoutDelegate({#required screenHeight}) : _screenHeight = screenHeight;
double _overlap = 50;
double _screenHeight;
#override
void performLayout(Size size) {
Size formSize;
Size actionSize;
Size disclaimerSize;
// if (formSize == null && hasChild(AuthWidgets.form)) {
formSize = layoutChild(AuthWidgets.form, BoxConstraints.loose(size));
// }
// if (actionSize == null && hasChild(AuthWidgets.action)) {
actionSize = layoutChild(AuthWidgets.action, BoxConstraints.loose(size));
// }
// if (disclaimerSize == null && hasChild(AuthWidgets.disclaimer)) {
disclaimerSize =
layoutChild(AuthWidgets.disclaimer, BoxConstraints.loose(size));
// }
if (formSize != null && actionSize != null && disclaimerSize != null) {
print('laying out children');
// Need the height of the form and action area, minus the overlap
var aboveTheFold = formSize.height + actionSize.height - _overlap;
var offsetY = _screenHeight - aboveTheFold;
offsetY += formSize.height - _overlap;
positionChild(AuthWidgets.action, Offset(0, offsetY));
offsetY += actionSize.height;
positionChild(AuthWidgets.disclaimer, Offset(0, offsetY));
positionChild(AuthWidgets.form, Offset(0, _screenHeight - aboveTheFold));
}
}
#override
bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) {
return false;
}
}
class AuthLayout extends StatelessWidget {
const AuthLayout({#required this.screenHeight, Key key}) : super(key: key);
final double screenHeight;
#override
Widget build(BuildContext context) {
return CustomMultiChildLayout(
delegate: AuthLayoutDelegate(screenHeight: screenHeight),
children: [
LayoutId(id: AuthWidgets.action, child: ActionMenu()),
LayoutId(id: AuthWidgets.disclaimer, child: Disclaimer()),
LayoutId(id: AuthWidgets.form, child: SignInForm()),
],
);
}
}
class SignInForm extends StatelessWidget {
const SignInForm({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 16),
child: Container(
color: Colors.red.withOpacity(0.5),
height: 350,
child: Center(
child: Text('SignInForm'),
),
),
);
}
}
class Disclaimer extends StatelessWidget {
const Disclaimer({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 300,
color: Colors.blue.withOpacity(0.5),
child: Center(child: Text('Disclaimer')),
);
}
}
class ActionMenu extends StatelessWidget {
const ActionMenu({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 200,
color: Colors.green.withOpacity(0.5),
child: Center(child: Text('ActionMenu')),
);
}
}
By using the delegate and the performLayout function, I was able to position my widgets precisely where I needed them. I did want my red area to appear "over" the top of the green area, so I had to ensure it was added to the CustomMultiChildLayout last (or at least after the green box).
Now I have been struggling with getting this to scroll on the page, but that is a question for a different thread.

Flutter Zoomable Widget

What I want to build is a widget that can make its child widget zoomable similar to the zoomable behavior.
Gestures I want to cover are
Pinch To Zoom
Double Tap to Zoom
Tap to get the local Position of the widget
Here is my widget plan:
ZoomableWidget(
child: // My custom Widget which should be zoomable.
)
Here is my current progress:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:vector_math/vector_math_64.dart';
class ZoomableWidget extends StatefulWidget {
final Widget child;
const ZoomableWidget({Key key, this.child}) : super(key: key);
#override
_ZoomableWidgetState createState() => _ZoomableWidgetState();
}
class _ZoomableWidgetState extends State<ZoomableWidget> {
double _scale = 1.0;
double _previousScale;
#override
Widget build(BuildContext context) {
return ClipRect(
child: GestureDetector(
onScaleStart: (ScaleStartDetails details) {
_previousScale = _scale;
},
onScaleUpdate: (ScaleUpdateDetails details) {
setState(() {
_scale = _previousScale * details.scale;
});
},
onScaleEnd: (ScaleEndDetails details) {
_previousScale = null;
},
child: Transform(
transform: Matrix4.diagonal3(Vector3(_scale.clamp(1.0, 5.0),
_scale.clamp(1.0, 5.0), _scale.clamp(1.0, 5.0))),
alignment: FractionalOffset.center,
child: widget.child,
),
),
);
}
}
The problem I have faced is, I cannot change the center of the pinch thus the image only zooms at (0,0) even after I zoom in the corner. Also, I cannot access horizontal drag and vertical drag to scroll the widget.
Thanks in advance.
As of Flutter 1.20, InteractiveViewer widget supports pan and Zoom out of the box.
To make any widget zoomable you need to simply wrap the child with InteractiveViewer.
#override
Widget build(BuildContext context) {
return Center(
child: InteractiveViewer(
panEnabled: false, // Set it to false to prevent panning.
boundaryMargin: EdgeInsets.all(80),
minScale: 0.5,
maxScale: 4,
child: FlutterLogo(size: 200),
),
);
}
This is working perfectly now, thanks for the reference #pskink.
import 'package:flutter/material.dart';
import 'package:matrix_gesture_detector/matrix_gesture_detector.dart';
class ZoomableWidget extends StatefulWidget {
final Widget child;
const ZoomableWidget({Key key, this.child}) : super(key: key);
#override
_ZoomableWidgetState createState() => _ZoomableWidgetState();
}
class _ZoomableWidgetState extends State<ZoomableWidget> {
Matrix4 matrix = Matrix4.identity();
#override
Widget build(BuildContext context) {
return MatrixGestureDetector(
onMatrixUpdate: (Matrix4 m, Matrix4 tm, Matrix4 sm, Matrix4 rm) {
setState(() {
matrix = m;
});
},
child: Transform(
transform: matrix,
child: widget.child,
),
);
}
}
I loved de resolution, you should put that in a packged in pub, you can even put some custom options, in my code I put doubletap to reset the zoom and locked the rotation.
import 'package:flutter/material.dart';
import 'package:matrix_gesture_detector/matrix_gesture_detector.dart';
class ZoomableWidget extends StatefulWidget {
final Widget child;
const ZoomableWidget({Key key, this.child}) : super(key: key);
#override
_ZoomableWidgetState createState() => _ZoomableWidgetState();
}
class _ZoomableWidgetState extends State<ZoomableWidget> {
Matrix4 matrix = Matrix4.identity();
Matrix4 zerada = Matrix4.identity();
#override
Widget build(BuildContext context) {
return GestureDetector(
onDoubleTap: (){
setState(() {
matrix = zerada;
});
},
child: MatrixGestureDetector(
shouldRotate: false,
onMatrixUpdate: (Matrix4 m, Matrix4 tm, Matrix4 sm, Matrix4 rm) {
setState(() {
matrix = m;
});
},
child: Transform(
transform: matrix,
child: widget.child,
),
),
);
}
}
You can use Zoom Widget Zoom Widget only need set a canvas size and child
Zoom(
width: 1800,
height: 1800,
child: Center(
child: Text("Happy zoom!!"),
)
);
As an alternative to MatrixGestureDetector, you can use the photo_view package: https://pub.dev/packages/photo_view
It has good limiting of the screen constraints so you can't drag the child off-screen, a bounce effect when hitting min/max size, and many other options.
It can be used with a custom child like this:
PhotoView.customChild(
child: <your widget>
)
I use zoom widget
first, add to pubsec.yaml :
dependencies:
zoom_widget: ^2.0.0
then import:
import 'package:zoom_widget/zoom_widget.dart';
Center text with max width and max height:
Zoom(
maxZoomWidth: 1800,
maxZoomHeight: 1800,
child: Center(
child: Text("Happy zoom!!"),
)
);