Created
October 17, 2023 19:50
-
-
Save Piinks/1d6cbd0ac83ac401628f0fc82b37afd2 to your computer and use it in GitHub Desktop.
Repro Customer Issue
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 BugExample()); | |
} | |
class BugExample extends StatelessWidget { | |
const BugExample(); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
home: Scaffold( | |
backgroundColor: Colors.grey, | |
body: KeyboardAwareDraggableScrollableSheet( | |
builder: (_, controller) => SingleChildScrollView( | |
controller: controller, | |
child: Container( | |
color: Colors.white, | |
child: Column( | |
children: [ | |
TextField(), | |
Text('one'), | |
Text('two'), | |
Text('three'), | |
Container(width: 50, height: 50, color: Colors.red), | |
Text('four'), | |
Text('five'), | |
Text('six'), | |
Container(width: 50, height: 50, color: Colors.green), | |
Text('seven'), | |
Text('eight'), | |
Text('nine'), | |
Container(width: 50, height: 50, color: Colors.blue), | |
Text('ten'), | |
Text('eleven'), | |
Text('twelve'), | |
], | |
), | |
), | |
), | |
), | |
), | |
); | |
} | |
} | |
class KeyboardAwareDraggableScrollableSheet extends StatefulWidget { | |
const KeyboardAwareDraggableScrollableSheet({ | |
super.key, | |
required this.builder, | |
}); | |
final ScrollableWidgetBuilder builder; | |
@override | |
State<KeyboardAwareDraggableScrollableSheet> createState() => | |
_KeyboardAwareDraggableScrollableSheetState(); | |
} | |
class _KeyboardAwareDraggableScrollableSheetState | |
extends State<KeyboardAwareDraggableScrollableSheet> { | |
var _virtualKeyboardUp = false; | |
var _previousPosition = 1.0; | |
late DraggableScrollableController _draggableScrollableController; | |
late ScrollController _draggableSheetScrollController; | |
@override | |
void initState() { | |
super.initState(); | |
_draggableScrollableController = DraggableScrollableController(); | |
} | |
void _updateLayoutForVirtualKeyboard( | |
BuildContext context, | |
BoxConstraints constraints, | |
) { | |
final bottom = MediaQuery.of(context).viewInsets.bottom; | |
final keyboardCurrentlyUp = bottom > 0; | |
if (_virtualKeyboardUp != keyboardCurrentlyUp) { | |
_virtualKeyboardUp = keyboardCurrentlyUp; | |
WidgetsBinding.instance.addPostFrameCallback((_) { | |
late double targetSize; | |
final sheetSize = _draggableScrollableController.isAttached | |
? _draggableScrollableController.size | |
: 0.5; | |
final scrollPosition = _draggableScrollableController.isAttached | |
? _draggableSheetScrollController.position.pixels | |
: 0; | |
if (_virtualKeyboardUp) { | |
targetSize = 1.0; | |
_previousPosition = sheetSize; | |
} else if (scrollPosition == 0) { | |
targetSize = _previousPosition; | |
} else { | |
return; | |
} | |
if (_draggableScrollableController.isAttached) { | |
_draggableScrollableController.animateTo( | |
targetSize, | |
duration: const Duration(milliseconds: 200), | |
curve: Curves.easeOut, | |
); | |
} | |
}); | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
return LayoutBuilder( | |
builder: (context, constraints) { | |
_updateLayoutForVirtualKeyboard(context, constraints); | |
return DraggableScrollableSheet( | |
controller: _draggableScrollableController, | |
builder: (context, controller) { | |
_draggableSheetScrollController = controller; | |
final child = widget.builder(context, controller); | |
return Padding( | |
padding: EdgeInsetsDirectional.only( | |
top: MediaQuery.of(context).viewInsets.top, | |
bottom: MediaQuery.of(context).viewInsets.bottom, | |
), | |
child: child, | |
); | |
}, | |
); | |
}, | |
); | |
} | |
} |
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
// This is a basic Flutter widget test. | |
// | |
// To perform an interaction with a widget in your test, use the WidgetTester | |
// utility in the flutter_test package. For example, you can send tap and scroll | |
// gestures. You can also use WidgetTester to find child widgets in the widget | |
// tree, read text, and verify that the values of widget properties are correct. | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_test/flutter_test.dart'; | |
import 'package:triage_october/main.dart'; | |
void main() { | |
final keyboardHeight = ValueNotifier<double>(0); | |
Future<void> simulateKeyboardUp(WidgetTester tester) async { | |
keyboardHeight.value = 150; | |
await tester.pumpAndSettle(); | |
} | |
Future<void> simulateKeyboardDown(WidgetTester tester) async { | |
await tester.pumpAndSettle(); | |
} | |
testWidgets('Repro', (WidgetTester tester) async { | |
tester.view | |
..physicalSize = const Size(300, 400) | |
..devicePixelRatio = 1.0; | |
final app = MaterialApp( | |
home: Scaffold( | |
body: VirtualKeyboardSimulator( | |
keyboardHeight: keyboardHeight, | |
child: Container( | |
alignment: Alignment.bottomRight, | |
child: Stack( | |
children: [ | |
Container(color: Colors.grey), | |
KeyboardAwareDraggableScrollableSheet( | |
builder: (_, controller) => SingleChildScrollView( | |
controller: controller, | |
child: Container( | |
color: Colors.white, | |
child: Column( | |
children: [ | |
const Text('one'), | |
const Text('two'), | |
const Text('three'), | |
Container(width: 50, height: 50, color: Colors.red), | |
const Text('four'), | |
const Text('five'), | |
const Text('six'), | |
Container(width: 50, height: 50, color: Colors.green), | |
const Text('seven'), | |
const Text('eight'), | |
const Text('nine'), | |
Container(width: 50, height: 50, color: Colors.blue), | |
const Text('ten'), | |
const Text('eleven'), | |
const Text('twelve'), | |
], | |
), | |
), | |
), | |
), | |
], | |
), | |
), | |
), | |
), | |
); | |
await tester.pumpWidget(app); | |
await expectLater( | |
find.byType(MaterialApp), | |
matchesGoldenFile('1_bottom_sheet_default_state.png'), | |
); | |
await simulateKeyboardUp(tester); | |
await expectLater( | |
find.byType(MaterialApp), | |
matchesGoldenFile( | |
'2_bottom_sheet_with_keyboard_up.png', | |
), | |
); | |
// Scroll down to reveal the element 'seven'. | |
await tester.scrollUntilVisible(find.text('seven'), 5.0); | |
await tester.pumpAndSettle(); | |
await expectLater( | |
find.byType(MaterialApp), | |
matchesGoldenFile( | |
'3_bottom_sheet_scrolled_down_with_keyboard_up.png', | |
), | |
); | |
await simulateKeyboardDown(tester); | |
// Because the user scrolled down, the sheet will stay up when the | |
// keyboard goes down. | |
await expectLater( | |
find.byType(MaterialApp), | |
matchesGoldenFile('4_bottom_sheet_scrolled_down.png'), | |
); | |
}); | |
} | |
class VirtualKeyboardSimulator extends StatelessWidget { | |
const VirtualKeyboardSimulator({ | |
super.key, | |
required this.keyboardHeight, | |
required this.child, | |
}); | |
final Widget child; | |
final ValueNotifier<double> keyboardHeight; | |
Widget _keyboard() { | |
final rows = ['qwertyuiop', 'asdfghjkl', 'zxcvbnm']; | |
return Column( | |
children: [ | |
const Text('Virtual Keyboard'), | |
for (String row in rows) | |
Center( | |
child: Row( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
for (var j = 0; j < row.length; j++) | |
Padding( | |
padding: const EdgeInsets.symmetric( | |
horizontal: 2.0, | |
vertical: 3.0, | |
), | |
child: Container( | |
width: 21, | |
height: 21, | |
color: Colors.grey[200], | |
child: Center( | |
child: Text( | |
row.substring(j, j + 1), | |
), | |
), | |
), | |
), | |
], | |
), | |
), | |
], | |
); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return ValueListenableBuilder<double>( | |
valueListenable: keyboardHeight, | |
builder: (context, value, _) => MediaQuery( | |
data: MediaQueryData( | |
viewInsets: EdgeInsets.only(bottom: value), | |
), | |
child: Stack( | |
children: [ | |
child, | |
Align( | |
alignment: Alignment.bottomCenter, | |
child: Container( | |
color: Colors.grey[100], | |
height: value, | |
child: ClipRect( | |
child: OverflowBox( | |
maxHeight: double.infinity, | |
maxWidth: double.infinity, | |
alignment: Alignment.topCenter, | |
child: _keyboard(), | |
), | |
), | |
), | |
), | |
], | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment