Skip to content

Instantly share code, notes, and snippets.

@fabiancrx
Last active September 16, 2021 11:05
Show Gist options
  • Save fabiancrx/47662fda1495ef2172f53f5b98974f04 to your computer and use it in GitHub Desktop.
Save fabiancrx/47662fda1495ef2172f53f5b98974f04 to your computer and use it in GitHub Desktop.
Automatically scroll to widget when focus gained in Flutter
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
/// Given a [focusNode] when it gains focus it will scroll to the widget that is wrapped by [ScrollWhenFocusGained]
/// Useful for when working with forms in which they keyboard can obscure areas of the screen.
/// It also provides a [onFocus] fallback method to be execute if the view could not be scrolled correctly.
///
/// Usage
///```
/// ScrollWhenFocusGained(
/// focusNode: _focusNode,
/// child: TextFormField( focusNode: _focusNode,)
///```
class ScrollWhenFocusGained extends HookWidget {
final VoidCallback? onErrorFocusing;
final FocusNode focusNode;
final Widget child;
final Duration? animationDuration;
const ScrollWhenFocusGained({
Key? key,
this.animationDuration,
this.onErrorFocusing,
required this.child,
required this.focusNode,
}) : super(key: key);
@override
Widget build(BuildContext context) {
late final keyboardVisibilityController = KeyboardVisibilityController();
void _scrollWhenFocusGained([double offset = 40]) {
print('Keyboard visibility direct query: ${keyboardVisibilityController.isVisible}');
if (focusNode.hasPrimaryFocus) {
try {
// Query
// Subscribe
keyboardVisibilityController.onChange.listen((bool visible) {
print('Keyboard visibility update. Is visible: ${visible}');
if (visible) {
Future.delayed(const Duration(milliseconds: 200)).then((value) {
// focusNode.requestFocus();
Scrollable.ensureVisible(
context,
alignment: 0.5,
curve: Curves.decelerate,
duration: animationDuration ?? const Duration(milliseconds: 160),
);
});
}
});
} catch (e) {
print('Could not ensure visibility $e');
if (onErrorFocusing != null) onErrorFocusing!();
}
}
}
useEffect(() {
focusNode.addListener(_scrollWhenFocusGained);
return () => focusNode.removeListener(_scrollWhenFocusGained);
}, []);
return child;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment