在滚动列表中,我在SOF中发现的这个已实现的应用程序中,在隐藏floating action button
时会调整大小CircularNotchedRectangle
和BottomAppBar
的原因
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: WorkoutDetailsPage(Workout()),
);
}
}
class Exercise {
String name;
Exercise({@required name}) {
this.name = name;
}
}
class Workout {
String name = "my name";
}
class WorkoutDetailsPage extends StatefulWidget {
Workout _workout = Workout();
WorkoutDetailsPage(this._workout);
@override
_WorkoutDetailsPageState createState() => _WorkoutDetailsPageState();
}
class _WorkoutDetailsPageState extends State<WorkoutDetailsPage> {
final List<Exercise> exercises = [
Exercise(name: "Push Ups"),
Exercise(name: "Bench press"),
Exercise(name: "Pull ups"),
Exercise(name: "Press ups"),
Exercise(name: "Crunches"),
Exercise(name: "Sit ups"),
Exercise(name: "BIceps curl"),
Exercise(name: "Something else"),
Exercise(name: "Push Ups"),
Exercise(name: "Bench press"),
Exercise(name: "Pull ups"),
Exercise(name: "Press ups"),
Exercise(name: "Crunches"),
Exercise(name: "Sit ups"),
Exercise(name: "BIceps curl"),
Exercise(name: "Something else"),
Exercise(name: "Push Ups"),
Exercise(name: "Bench press"),
Exercise(name: "Pull ups"),
];
ScrollController _hideButtonController;
bool _isVisible = true;
@override
void initState() {
super.initState();
_isVisible = true;
_hideButtonController = new ScrollController();
_hideButtonController.addListener(() {
print("listener");
if (_hideButtonController.position.userScrollDirection == ScrollDirection.reverse) {
setState(() {
_isVisible = false;
print("**** $_isVisible up");
});
}
if (_hideButtonController.position.userScrollDirection == ScrollDirection.forward) {
setState(() {
_isVisible = true;
print("**** $_isVisible down");
});
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButtonAnimator: FloatingActionButtonAnimator.scaling,
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: _isVisible
? FloatingActionButton(
backgroundColor: Colors.blue,
elevation: 12,
onPressed: () {},
)
: null,
bottomNavigationBar: AnimatedContainer(
duration: Duration(milliseconds: 200),
height: _isVisible ? 60 : 0.0,
child: BottomAppBar(
elevation: 8,
shape: CircularNotchedRectangle(),
color: Colors.blue,
child: Container(
height: 60,
child: Row(
children: <Widget>[Text("data")],
),
),
),
),
body: CustomScrollView(
controller: _hideButtonController,
slivers: <Widget>[
SliverAppBar(
expandedHeight: kToolbarHeight,
pinned: true,
floating: true,
snap: true,
flexibleSpace: FlexibleSpaceBar(
title: Text(widget._workout.name),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
buildSliverListItem, childCount: exercises.length
),
),
],
),
);
}
Widget buildSliverListItem(BuildContext context, int index) {
return Center(
child: ListTile(
title: Text(exercises[index].name),
),
);
}
}
我该如何解决?我测试过将BottomAppBar
放在Stack
上,但这没用
答案 0 :(得分:3)
如果您不想调整FloatingActionButton
的大小,只需创建自己的FloatingActionButtonAnimator
(对代码进行了一些更改),请检查以下内容:
@override
void initState() {
super.initState();
_isVisible = true;
_hideButtonController = new ScrollController();
_hideButtonController.addListener(() {
//print("listener");
if (_hideButtonController.position.userScrollDirection ==
ScrollDirection.reverse) {
if (_isVisible)
setState(() {
_isVisible = false;
//print("**** $_isVisible up");
});
}
if (_hideButtonController.position.userScrollDirection ==
ScrollDirection.forward) {
if (!_isVisible)
setState(() {
_isVisible = true;
//print("**** $_isVisible down");
});
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButtonAnimator: MyFabAnimation(),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.red,
elevation: 12,
onPressed: () {},
),
bottomNavigationBar: AnimatedContainer(
duration: Duration(milliseconds: 200),
height: _isVisible ? 60 : 0.0,
child: BottomAppBar(
elevation: 8,
shape: CircularNotchedRectangle(),
color: Colors.blue,
child: Container(
height: 60,
child: Row(
children: <Widget>[Text("data")],
),
),
),
),
body: CustomScrollView(
controller: _hideButtonController,
slivers: <Widget>[
SliverAppBar(
expandedHeight: kToolbarHeight,
pinned: true,
floating: true,
snap: true,
flexibleSpace: FlexibleSpaceBar(
title: Text(widget._workout.name),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(buildSliverListItem,
childCount: exercises.length),
),
],
),
);
}
这是您的FloatingActionButton
的自定义动画:
double minValue = double.maxFinite;
class MyFabAnimation extends FloatingActionButtonAnimator {
@override
Offset getOffset({Offset begin, Offset end, double progress}) {
if (minValue == double.maxFinite) {
minValue = end.dy;
} else {
if (begin.dy < minValue) minValue = begin.dy;
}
double difference = end.dy - minValue;
return Offset(end.dx, end.dy + (difference * 1.8));
}
@override
Animation<double> getRotationAnimation({Animation<double> parent}) {
return Tween<double>(begin: 1.0, end: 1.0).animate(parent);
}
@override
Animation<double> getScaleAnimation({Animation<double> parent}) {
const Curve curve = Interval(0.5, 1.0, curve: Curves.ease);
return _AnimationSwap<double>(
ReverseAnimation(parent.drive(CurveTween(curve: curve.flipped))),
parent.drive(CurveTween(curve: curve)),
parent,
0.5,
);
}
}
class _AnimationSwap<T> extends CompoundAnimation<T> {
_AnimationSwap(
Animation<T> first, Animation<T> next, this.parent, this.swapThreshold)
: super(first: first, next: next);
final Animation<double> parent;
final double swapThreshold;
@override
T get value => parent.value < swapThreshold ? first.value : next.value;
}
答案 1 :(得分:1)
输出:
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
AnimationController _controller;
Tween<Offset> _tween = Tween(begin: Offset(0, 0), end: Offset(0, 1.5));
bool _visible = true;
Duration _duration = Duration(milliseconds: 500);
Curve _curve = Curves.linear;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: _duration,
);
_controller.addListener(() {
value = _tween.evaluate(_controller).dy * 100;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
floatingActionButton: FloatingActionButton(onPressed: _animate,),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButtonAnimator: MyAnimator(),
bottomNavigationBar: SlideTransition(
position: _tween.animate(_controller),
child: AnimatedContainer(
duration: _duration,
curve: _curve,
height: _visible ? 100 : 0,
child: BottomAppBar(color: Colors.blue, shape: CircularNotchedRectangle()),
),
),
);
}
void _animate() async {
if (_controller.isDismissed)
_controller.forward();
else if (_controller.isCompleted) _controller.reverse();
_visible = !_visible;
setState(() {});
}
}
double value = 0;
class MyAnimator extends FloatingActionButtonAnimator {
@override
Offset getOffset({Offset begin, Offset end, double progress}) {
Offset offset = Offset(begin.dx, begin.dy + value/2);
return offset;
}
@override
Animation<double> getRotationAnimation({Animation<double> parent}) {
return parent;
}
@override
Animation<double> getScaleAnimation({Animation<double> parent}) {
return parent;
}
}