Unable to achieve the page to start from the bottom in the page viewer I have tried converted bit of code this but was unable to load it from bottom.
Reference link to what I am trying to achieve : Swipe effect like inshorts news app
Here is my code for what I am trying
class InshortsPageTransformer extends PageTransformer {
#override
Widget transform(Widget child, TransformInfo info) {
double position = info.position ?? 0;
double rotation = position * 0.2;
double scale = math.max(0.8, 1 - position.abs());
if (position < -1) {
rotation = 0;
child = Opacity(
opacity: 0,
child: child,
);
} else if (position <= 0) {
child = Opacity(
opacity: 1,
child: child,
);
child = Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateY(rotation)
..scale(scale),
alignment: Alignment.center,
child: child,
);
} else if (position <= 1) {
child = Opacity(
opacity: 1,
child: child,
);
child = Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateY(rotation)
..scale(scale),
alignment: Alignment.center,
child: child,
);
} else {
rotation = 0;
child = Opacity(
opacity: 0,
child: child,
);
}
return Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateY(rotation)
..scale(scale),
alignment: Alignment.center,
child: child,
);
}
}
class ScaleAndFadeTransformer extends PageTransformer {
final double _scale;
final double _fade;
ScaleAndFadeTransformer({double fade = 0.3, double scale = 0.8})
: _fade = fade,
_scale = scale;
#override
Widget transform(Widget item, TransformInfo info) {
double position = info.position ?? 0;
double scaleFactor = (1 - position.abs()) * (1 - _scale);
double fadeFactor = (1 - position.abs()) * (1 - _fade);
double opacity = _fade + fadeFactor;
double scale = _scale + scaleFactor;
return Opacity(
opacity: opacity,
child: Transform.scale(
scale: scale,
child: item,
),
);
}
}
I recently created the same project look into it
https://github.com/bibek-ranjan-saha/prodt_test
I have used https://pub.dev/packages/another_transformer_page_view this package for achieving this effect.
sample code snippet
TransformerPageView(
scrollDirection: Axis.vertical,
itemCount: snapshot.data?.data.length ?? 0,
loop: false,
controller: homePageController,
transformer: DeepthPageTransformer()
itemBuilder: (context, index) {
return NewsView(
screenSize: screenSize,
news: snapshot.data!.data[index],
);
},
);
Related
How to add curves.bounceOut in text animation;
Container(child:Text("hello"));
you can define your own animation and controller and tweak it as you like
one way to do it
add with TickerProviderStateMixin to your class
example :
class homeState extends State<home> with TickerProviderStat
then in your class define :
late AnimationController controller;
late Animation<double> animation
;
after that in the init state of your class you can use
controller = AnimationController(
duration: const Duration(seconds: 20), // duration of the animation you want
vsync: this,
);
animation = CurvedAnimation(parent: controller /* the controller we defined above */ , curve: Curves.bounceOut /* the curve of the animation you want */ );
// use
controller.repeat(); //if you want the animation to loop
then use it with your container
if you want to know more here is the flutter documentation link
hope this helps
You can use animated_text_kit Wavy animation
Example from doc
return DefaultTextStyle(
style: const TextStyle(
fontSize: 20.0,
),
child: AnimatedTextKit(
animatedTexts: [
WavyAnimatedText('Hello World'),
WavyAnimatedText('Look at the waves'),
],
isRepeatingAnimation: true,
onTap: () {
print("Tap Event");
},
),
);
You can find more animation on package
Please Use this code for animation text;
follow this code if it helpfull;
Create Variables
late AnimationController controller;
late Animation<double> animation;
int hrs = 0;
int minute = 0;
int second = 0;
double opacity = 0.1;
int duration = 0;
double hp = 0.0;
double mp = 0.0;
double sp = 0.0;
Create Function and add within initState() function;
timer() async {
DateTime date = DateTime.now();
Future.delayed(const Duration(milliseconds: 1000), () {
setState(() {
duration = 900;
sp = 10;
date = DateTime.now();
second = date.second;
hrs = date.hour;
minute = date.minute;
var inputFormat = DateFormat('HH');
var inputDate = inputFormat.parse(hrs.toString());
var outputFormat = DateFormat('hh');
hrs = int.parse(outputFormat.format(inputDate).toString());
if (second == 0) {
mp = 10;
} else if (minute == 0) {
hp = 10;
}
timer();
});
});
Future.delayed(const Duration(milliseconds: 900), () {
setState(() {
sp = 0;
mp = 0;
hp = 0;
duration = 0;
});
});
}
Create a Widget
Widget animatedText(String text, double animatedPadding) {
return TweenAnimationBuilder(
duration: const Duration(milliseconds: 500),
curve: Curves.bounceIn,
tween: IntTween(begin: 0, end: 1),
builder: (context, int val, child) {
if (val != 1 && opacity < 1.0) {
opacity = opacity + 0.1;
} else if (opacity > 1.0 || opacity == 1.0) {
opacity = 1.0;
}
return Opacity(
opacity: opacity >= 0.0 && opacity <= 1.0 ? opacity : 0,
child: AnimatedPadding(
duration: Duration(milliseconds: duration),
curve: Curves.bounceOut,
padding: EdgeInsets.only(top: animatedPadding),
child: child),
);
},
child: Text(
text,
style: const TextStyle(
color: Colors.white,
fontSize: 24.0,
),
),
);
}
add animatedText in Container ;
Container(alignment: Alignment.center,
height: Sizes.height * 0.05,
width: Sizes.width * 0.1,
child: animatedText(second.toString(), sp)),
I am developing an shape editor in flutter. For that, I need to add a feature of adding shapes dynamically to the screen. Each of them should be able to independently scale, position, and rotate. There should be an anchor point like in word or in Photoshop to indicate the active shapes and to scale and rotate them. The shape should be positioned with drag and drop.
I found this answer :
Rotate and resize container
But the answer only rotate the shape from the center, I want to scale the shape from the corners also.
The code :
class FooResizer extends StatefulWidget {
#override
_FooResizerState createState() => _FooResizerState();
}
class _FooResizerState extends State<FooResizer> with TickerProviderStateMixin, ChangeNotifier {
Sizer currentSizer;
double angle = 0.0;
AnimationController ctrl;
final Map<String, Sizer> sizers = {
'l': Sizer('l', Alignment.centerLeft, {'t': 0.5, 'b': 0.5, 'M': 0.5}),
't': Sizer('t', Alignment.topCenter, {'l': 0.5, 'r': 0.5, 'M': 0.5}),
'r': Sizer('r', Alignment.centerRight, {'t': 0.5, 'b': 0.5, 'R': 1.0, 'M': 0.5}),
'b': Sizer('b', Alignment.bottomCenter, {'l': 0.5, 'r': 0.5, 'R': 1.0, 'M': 0.5}),
'R': Sizer('R', Alignment.bottomRight, {}),
'M': Sizer('M', Alignment.center, {}),
};
#override
void initState() {
super.initState();
ctrl = AnimationController(vsync: this, duration: Duration(milliseconds: 300), value: 1.0);
}
#override
Widget build(BuildContext context) {
return ClipRect(
child: ColoredBox(
color: Colors.black12,
// CustomMultiChildLayoutPainter:
// https://gist.github.com/pskink/0f82724b41d9ebe89604782fbf62fe03#file-multi_layout_painter-dart-L447
child: CustomMultiChildLayoutPainter(
delegate: _FooResizerDelegate(sizers, this),
children: [
LayoutId(
id: 'body',
child: AnimatedBuilder(
animation: this,
builder: (ctx, child) {
return Transform.rotate(
angle: angle,
child: child,
);
},
child: Material(color: Colors.grey[300], elevation: 4, child: FlutterLogo()),
),
),
...sizers.values.map(_sizerBuilder),
],
),
),
);
}
Widget _sizerBuilder(Sizer sizer) {
final colors = {
'M': Colors.orange,
'R': Colors.teal,
};
return LayoutId(
id: sizer.id,
child: GestureDetector(
onPanStart: (details) => _panStart(sizer),
onPanUpdate: _panUpdate,
onPanEnd: _panEnd,
child: AnimatedBuilder(
animation: ctrl,
builder: (context, child) {
final color = colors[sizer.id] ?? Colors.green;
return Opacity(
opacity: currentSizer == sizer? 1.0 : Curves.ease.transform(ctrl.value),
child: Container(
decoration: ShapeDecoration(
shape: CircleBorder(side: BorderSide(width: lerpDouble(0.0, 2.0, ctrl.value), color: Colors.black38)),
color: currentSizer == sizer? Color.lerp(Colors.deepPurple, color, ctrl.value) : color,
shadows: [BoxShadow.lerp(BoxShadow(spreadRadius: 2, blurRadius: 4, offset: Offset(2, 2)), null, ctrl.value)],
),
),
);
}
),
),
);
}
_panStart(Sizer sizer) {
currentSizer = sizer;
ctrl.reverse();
}
_panUpdate(DragUpdateDetails details) {
assert(currentSizer != null);
if (currentSizer.id == 'M') {
// move
sizers.values.forEach((sizer) => sizer.center += details.delta);
} else
if (currentSizer.id == 'R') {
// rotate
final localCenter = sizers['M'].center;
final globalCenter = (context.findRenderObject() as RenderBox).localToGlobal(localCenter);
final angle0 = (details.globalPosition - details.delta - globalCenter).direction;
final angle1 = (details.globalPosition - globalCenter).direction;
final deltaAngle = angle1 - angle0;
sizers.values
.where((sizer) => sizer.id != 'M')
.forEach((sizer) {
final vector = sizer.center - localCenter;
sizer.center = localCenter + Offset.fromDirection(vector.direction + deltaAngle, vector.distance);
});
angle += deltaAngle;
} else {
// resize
final adjustedAngle = angle + currentSizer.angleAdjustment;
final rotatedDistance = details.delta.distance * math.cos(details.delta.direction - adjustedAngle);
final vector = Offset.fromDirection(adjustedAngle, rotatedDistance);
currentSizer.center += vector;
currentSizer.dependents.forEach((id, factor) => sizers[id].center += vector * factor);
}
notifyListeners();
}
_panEnd(DragEndDetails details) {
assert(currentSizer != null);
// currentSizer = null;
ctrl.forward();
}
}
class _FooResizerDelegate extends MultiChildLayoutPainterDelegate {
static const SIZE = 48.0;
final Map<String, Sizer> sizers;
_FooResizerDelegate(this.sizers, Listenable relayout) : super(relayout: relayout);
#override
void performLayout(Size size) {
sizers['M'].center ??= init(size);
for (var sizer in sizers.values) {
layoutChild(sizer.id, BoxConstraints.tight(Size(SIZE, SIZE)));
positionChild(sizer.id, sizer.center - Offset(SIZE / 2, SIZE / 2));
}
final w = (sizers['l'].center - sizers['r'].center).distance;
final h = (sizers['t'].center - sizers['b'].center).distance;
layoutChild('body', BoxConstraints.tight(Size(w, h)));
positionChild('body', sizers['M'].center - Offset(w / 2, h / 2));
}
Offset init(Size size) {
final rect = (Offset.zero & size).deflate(24);
print('init rect: $rect');
for (var sizer in sizers.values) {
sizer
..center = sizer.alignment.withinRect(rect)
..angleAdjustment = sizer.alignment.x == 0? math.pi / 2 : 0;
}
return sizers['M'].center;
}
#override
bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) => true;
#override
void foregroundPaint(Canvas canvas, Size size) {
}
#override
void paint(Canvas canvas, Size size) {
final w = (sizers['r'].center - sizers['l'].center).distance;
final h = (sizers['b'].center - sizers['t'].center).distance;
final rect = Rect.fromCenter(center: sizers['M'].center, width: w, height: h);
final angle = (sizers['r'].center - sizers['l'].center).direction;
final matrix = Matrix4.identity()
..translate(rect.center.dx, rect.center.dy)
..rotateZ(angle)
..translate(-rect.center.dx, -rect.center.dy);
final transformedRect = MatrixUtils.transformRect(matrix, rect);
final points = [
Offset(transformedRect.left, 0), Offset(transformedRect.left, size.height),
Offset(0, transformedRect.top), Offset(size.width, transformedRect.top),
Offset(transformedRect.right, 0), Offset(transformedRect.right, size.height),
Offset(0, transformedRect.bottom), Offset(size.width, transformedRect.bottom),
];
canvas.drawPoints(PointMode.lines, points, Paint());
}
}
class Sizer {
final String id;
final Alignment alignment;
final Map<String, double> dependents;
Offset center;
double angleAdjustment;
Sizer(this.id, this.alignment, this.dependents);
}
The result :
what I am trying to achieve :
Here, I have a list. a = [92,93,94,95,81,66,51,36..];
I just want to move my colored cell's container according to the list index with animation.
To understand my question better, in the given image, I want to animate that cell container which is located at index 92, according to a list(a).
While we know the box size, we can use getPosition() method to position the circle.
Offset getPosition(int index) {
assert(boxWidth != null, "init boxWidth inside layoutBuilder");
final dx = index <= crossAxisCount
? index * boxWidth!
: (index % crossAxisCount) * boxWidth!;
final dy = index <= crossAxisCount
? 0.0
: (index / crossAxisCount).floor() * boxWidth!;
return Offset(dx, dy);
}
Use like
AnimatedPositioned(
duration: const Duration(milliseconds: 400),
left: getPosition(currentPosition).dx,
top: getPosition(currentPosition).dy,
child: Container(
alignment: Alignment.center,
width: constraints.maxWidth / crossAxisCount,
height: constraints.maxWidth / crossAxisCount,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.cyanAccent,
),
),
),
Full Snippet On dartpad
I want to add multiple sliders in one slider. If you're not clear about what I'm asking please refer the below image
I want these three squares to be sliding and get the values of them.
I did some searching and could not find any flutter widget or a plugin that has the support.
I tried to use a stack and use multiple Slider widgets at the same location but it is also not working. (I know it's not a good approach.)
How can I make this happen. To have multiple sliders on the same line and get the values.
Any help or ideas are very much appreciated.
Using Stack with three sliders did not work because it was being overlapped.
I have made this Slider3X of being curious. There are few things need to fix here, start and end points missing some fractional position.
Code on Gist, dart pad
class Slider3x extends StatefulWidget {
const Slider3x({
Key? key,
required this.onSliderUpdate,
this.size = const Size(5, 10),
this.min = 0,
this.max = 1.0,
this.colorX = Colors.green,
this.colorY = Colors.blue,
this.colorZ = Colors.redAccent,
}) : super(key: key);
final Function(double? x, double? y, double? z) onSliderUpdate;
///size of moveable 3x point 😅, forgot the name maybe thumbs
final Size size;
final double? min;
final double? max;
final Color colorX;
final Color colorY;
final Color colorZ;
#override
State<Slider3x> createState() => _Slider3xState();
}
class _Slider3xState extends State<Slider3x> {
/// three slider position
double? x;
double? y;
double? z;
final double tapSpacesArea = .05;
// currect active slider , help to prevent overlLAp while sliding
int activeSliderNumber = 0;
//* Update sldier
void _updateSlider(double dx, double maxWidth) {
final tapPosition = dx;
//* update logic
if (tapPosition <= 0 || tapPosition >= maxWidth) {
return;
}
//* update on UI based on slider number
if (activeSliderNumber == 0) {
setState(() {
x = tapPosition;
});
} else if (activeSliderNumber == 1) {
setState(() {
y = tapPosition;
});
} else if (activeSliderNumber == 2) {
setState(() {
z = tapPosition;
});
}
//pass value on main widget
widget.onSliderUpdate(
dp(_generateSliderValue(maxWidth: maxWidth, x: x!)),
dp(_generateSliderValue(maxWidth: maxWidth, x: y!)),
dp(_generateSliderValue(maxWidth: maxWidth, x: z!)),
);
}
//round number
double dp(double val, {int places = 2}) {
num mod = pow(10.0, places);
return ((val * mod).round().toDouble() / mod);
}
//* calculate slider value
double _generateSliderValue({
required double maxWidth,
required double x,
}) {
// x is slider original position on width:maxWidth
return (widget.max! - widget.min!) * (x / maxWidth) + widget.min!;
}
//* select ActiveSlider, fixed overLap issue
//* slider Selector logic
void _selectSlider({
required double maxWidth,
required double tapPosition,
}) {
final maxArea = maxWidth * tapSpacesArea;
if ((tapPosition - x!).abs() < maxArea) {
setState(() {
activeSliderNumber = 0;
});
} else if ((tapPosition - y!).abs() < maxArea) {
setState(() {
activeSliderNumber = 1;
});
} else if ((tapPosition - z!).abs() < maxArea) {
setState(() {
activeSliderNumber = 2;
});
}
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 50,
child: LayoutBuilder(builder: (context, constraints) {
final maxWidth = constraints.maxWidth - 10;
x = x ?? 0;
y = y ?? constraints.maxWidth / 2;
z = z ?? maxWidth;
return Stack(
alignment: Alignment.center,
children: [
Positioned(
left: x,
child: Container(
height: activeSliderNumber == 0
? widget.size.height * 1.5
: widget.size.height,
width: widget.size.width,
color: widget.colorX,
),
),
//* paint Y
Positioned(
left: y,
child: Container(
height: activeSliderNumber == 1
? widget.size.height * 1.5
: widget.size.height,
width: widget.size.width,
color: widget.colorY,
),
),
//* paint z
Positioned(
left: z,
child: Container(
height: activeSliderNumber == 2
? widget.size.height * 1.5
: widget.size.height,
width: widget.size.width,
color: widget.colorZ,
),
),
const Divider(
endIndent: 10,
),
GestureDetector(
onTapDown: (details) => _selectSlider(
maxWidth: maxWidth,
tapPosition: details.localPosition.dx),
onPanUpdate: (details) =>
_updateSlider(details.localPosition.dx, maxWidth),
),
],
);
}),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.min.toString(),
),
Text(
widget.max.toString(),
),
],
)
],
),
);
}
}
I am trying to set any widget to screen at any position so if user open app in other devices the widget must should remain at that give position , for example if I set widget on 1/4 part of the screen then it should be the same in every device . I tested in simulator from Iphone 8 to Ipad 8th gen.
Below is my code I am using Positioned.fromRect and passing Offset(dx,dy). I also tried MediaQuery but all in vain . Please guide me even if you find my question stupid.
Reference app Story click or post maker app with pre built in templates.
This is simple constructor.
FlutterSimpleStickerImage(
this.image, {
Key key,
this.width,
this.height,
this.viewport,
this.minScale = 1.0,
this.maxScale = 2.0,
this.onTapRemove,
}) : super(key: key);
Widget image;
final double width;
final double height;
final Size viewport;
final double minScale;
final double maxScale;
A class for positioning widget in stack the Position.fromRect()
class _FlutterSimpleStickerImageState extends State<FlutterSimpleStickerImage> {
_FlutterSimpleStickerImageState();
double _scale = 1.0;
double _previousScale = 1.0;
Offset _previousOffset = Offset(0, 0);
Offset _startingFocalPoint = Offset(0, 0);
Offset _offset = Offset(0, 0);
double _rotation = 0.0;
double _previousRotation = 0.0;
bool _isSelected = false;
#override
void dispose() {
super.dispose();
_offset = Offset(0, 0);
_scale = 1.0;
}
#override
Widget build(BuildContext context) {
double sizewidth=183;
double sizeheight=0;
return Positioned.fromRect(
rect: Rect.fromPoints(Offset(sizewidth, sizeheight),Offset(sizewidth , sizeheight )),
child: Container(
child: Stack(
children: <Widget>[
Center(
child: Transform(
transform: Matrix4.diagonal3(Vector3(_scale, _scale, _scale)),
// ..setRotationZ(_rotation),
alignment: FractionalOffset.center,
child: GestureDetector(
onScaleStart: (ScaleStartDetails details) {
_startingFocalPoint = Offset(sizewidth,sizeheight);
_previousOffset = Offset(sizewidth,sizeheight);
_previousRotation = _rotation;
_previousScale = _scale;
// print(
// "begin - focal : ${details.focalPoint}, local : ${details.localFocalPoint}");
},
onScaleUpdate: (ScaleUpdateDetails details) {
_scale = min(
max(_previousScale * details.scale, widget.minScale),
widget.maxScale);
_rotation = details.rotation;
final Offset normalizedOffset =
(_startingFocalPoint - _previousOffset) /
_previousScale;
Offset __offset =
details.focalPoint - (normalizedOffset * _scale);
__offset = Offset(max(__offset.dx, -widget.width),
max(__offset.dy, -widget.height));
__offset = Offset(min(__offset.dx, widget.viewport.width),
min(__offset.dy, widget.viewport.height));
setState(() {
_offset = __offset;
// print("move - $_offset, scale : $_scale");
});
},
onTap: () {
setState(() {
_isSelected = !_isSelected;
});
},
onTapCancel: () {
setState(() {
_isSelected = false;
});
},
onDoubleTap: () {
setState(() {
_scale = 1.0;
});
},
onLongPress: (){
setState(() {
widget.image=Container(height: 100,width: 100,color: Color.fromRGBO(255, 150, 0, 1.0),);
});
},
child: Container(child: widget.image),
),
),
),
_isSelected
? Positioned(
top: 12,
right: 12,
width: 24,
height: 24,
child: Container(
child: IconButton(
padding: EdgeInsets.zero,
icon: Icon(Icons.remove_circle),
color: Color.fromRGBO(255, 150, 0, 1.0),
onPressed: () {
print('tapped remove sticker');
if (this.widget.onTapRemove != null) {
this.widget.onTapRemove(this.widget);
}
},
),
),
)
: Container(),
],
),
),
);
}
void hideRemoveButton() {
setState(() {
_isSelected = false;
});
}
}