Last active
October 5, 2022 13:21
-
-
Save sorgfal/217301cc4ba15123c3aad2a79d28c902 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:flutter/material.dart'; | |
| void main() { | |
| runApp(const Myapp()); | |
| } | |
| class Myapp extends StatelessWidget { | |
| const Myapp({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return MaterialApp( | |
| home: MyHome(), | |
| ); | |
| } | |
| } | |
| class MyHome extends StatefulWidget { | |
| const MyHome({super.key}); | |
| @override | |
| State<MyHome> createState() => _MyHomeState(); | |
| } | |
| class _MyHomeState extends State<MyHome> with TickerProviderStateMixin { | |
| late final AnimatedLinkedAppBarBottomSheet showingState; | |
| @override | |
| void initState() { | |
| super.initState(); | |
| showingState = AnimatedLinkedAppBarBottomSheet(vsync: this); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| return Scaffold( | |
| body: LinkedAppBarBottomSheet( | |
| showingState: showingState, | |
| hiddenTopBarHeight: kToolbarHeight, | |
| topBar: Container( | |
| height: kToolbarHeight * 2, | |
| color: Colors.cyan, | |
| ), | |
| topBarHeight: kToolbarHeight * 2, | |
| bottomSheetHeight: 400, | |
| bottomSheet: Container( | |
| height: 400, | |
| color: Colors.blue, | |
| child: ListView( | |
| children: [ | |
| for (var i = 0; i < 10; i++) | |
| ListTile( | |
| title: Text('Number $i'), | |
| ) | |
| ], | |
| )), | |
| child: ListView.builder( | |
| itemBuilder: ((context, index) => ListTile( | |
| title: Text(index.toString()), | |
| )), | |
| )), | |
| ); | |
| } | |
| } | |
| class AnimatedLinkedAppBarBottomSheet extends AnimationController { | |
| AnimatedLinkedAppBarBottomSheet({required super.vsync}) | |
| : super(duration: Duration(milliseconds: 300)); | |
| setHideStatus(double v) { | |
| if (value >= 0 && value <= 1) { | |
| value += v; | |
| } | |
| } | |
| endMotion() { | |
| if (value > .5) { | |
| animateTo(1); | |
| } | |
| if (value < .5) { | |
| animateTo(0); | |
| } | |
| } | |
| } | |
| class LinkedAppBarBottomSheet extends StatefulWidget { | |
| /// То что будет под барами | |
| final Widget child; | |
| /// Высота верхней полоcки, которая будет видима в скрытом состоянии | |
| final double hiddenTopBarHeight; | |
| /// Высота верхней полоcки, которая будет видима в открытом состоянии | |
| final double topBarHeight; | |
| /// Высота нижнего щита, который будет видим в открытом состоянии | |
| final double bottomSheetHeight; | |
| /// Виджет верхней полоски | |
| final Widget topBar; | |
| /// Виджет нищнего листа | |
| final Widget bottomSheet; | |
| /// Высота полоски, которая будет видна снизу и за которую можно тянуть | |
| final double bottomDraggableSheetHeight; | |
| final AnimatedLinkedAppBarBottomSheet showingState; | |
| const LinkedAppBarBottomSheet({ | |
| super.key, | |
| required this.child, | |
| required this.topBar, | |
| required this.bottomSheet, | |
| required this.topBarHeight, | |
| required this.bottomSheetHeight, | |
| required this.showingState, | |
| required this.hiddenTopBarHeight, | |
| this.bottomDraggableSheetHeight = 10, | |
| }); | |
| @override | |
| State<LinkedAppBarBottomSheet> createState() => | |
| _LinkedAppBarBottomSheetState(); | |
| } | |
| class _LinkedAppBarBottomSheetState extends State<LinkedAppBarBottomSheet> { | |
| onPanEnd(DragEndDetails ded) { | |
| widget.showingState.endMotion(); | |
| } | |
| onPanUpdate(DragUpdateDetails dud) { | |
| var diffKoef = dud.delta.dy / (widget.bottomSheetHeight); | |
| _updateValue(diffKoef); | |
| } | |
| _updateValue(double diff) { | |
| widget.showingState.setHideStatus(diff); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| var bottomBaseYOffset = | |
| MediaQuery.of(context).size.height - widget.bottomSheetHeight; | |
| return Stack( | |
| children: [ | |
| widget.child, | |
| AnimatedBuilder( | |
| animation: widget.showingState, | |
| builder: (context, child) => Transform.translate( | |
| offset: Offset( | |
| 0, | |
| (bottomBaseYOffset - | |
| (widget.bottomDraggableSheetHeight * | |
| widget.showingState.value) + | |
| widget.bottomSheetHeight * widget.showingState.value)), | |
| child: GestureDetector( | |
| onPanEnd: onPanEnd, | |
| onPanUpdate: onPanUpdate, | |
| child: Opacity( | |
| opacity: 1 - (0.5 * widget.showingState.value), | |
| child: widget.bottomSheet)), | |
| ), | |
| ), | |
| AnimatedBuilder( | |
| animation: widget.showingState, | |
| builder: (context, child) => Transform.translate( | |
| offset: Offset( | |
| 0, | |
| ((-widget.topBarHeight + widget.hiddenTopBarHeight) * | |
| widget.showingState.value)), | |
| child: widget.topBar, | |
| ), | |
| ), | |
| ], | |
| ); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment