fix(auth): 登录页靠上排列并支持外部失焦

This commit is contained in:
Zhou Weidong committed 2026-10-23 01:10:59 +08:00
1 parent 6318ca24ec
commit f3d64f6fb5
2 files changed
+27 -5

No files matched your search

+23 -5
View File
@@ -40,9 +40,9 @@ const double _buttonRadius = 25;
const double _errorOpacity = 0.10; const double _errorOpacity = 0.10;
const double _errorBorderOpacity = 0.28; const double _errorBorderOpacity = 0.28;
const double _enterSlideDistance = 16; const double _enterSlideDistance = 16;
const double _topContentPadding = 64; const double _topContentPadding = 56;
const double _bottomContentPadding = 28; const double _bottomContentPadding = 28;
const double _compactTopContentPadding = 48; const double _compactTopContentPadding = 40;
const double _compactHeightBreakpoint = 720; const double _compactHeightBreakpoint = 720;
const double _compactBrandGap = 16; const double _compactBrandGap = 16;
const double _glowSize = 280; const double _glowSize = 280;
@@ -159,6 +159,19 @@ class _AuthPageState extends State<AuthPage> {
} }
} }
/// 点在当前邮箱或密码框之外时取消焦点。
void _releaseFieldFocus(PointerDownEvent event) {
final focus = FocusManager.instance.primaryFocus;
if (focus != _emailFocus && focus != _passwordFocus) return;
final renderObject = focus?.context?.findRenderObject();
if (renderObject is! RenderBox || !renderObject.hasSize) {
focus?.unfocus();
return;
}
final bounds = renderObject.localToGlobal(Offset.zero) & renderObject.size;
if (!bounds.contains(event.position)) focus?.unfocus();
}
void _scheduleRevealFocusedField() { void _scheduleRevealFocusedField() {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) _revealFocusedField(); if (mounted) _revealFocusedField();
@@ -325,7 +338,10 @@ class _AuthPageState extends State<AuthPage> {
effectiveKeyboardInset(context, _keyboardInset); effectiveKeyboardInset(context, _keyboardInset);
final available = constraints.maxHeight - top - bottom; final available = constraints.maxHeight - top - bottom;
final minHeight = available > 0 ? available : 0.0; final minHeight = available > 0 ? available : 0.0;
return AutofillGroup( return Listener(
behavior: HitTestBehavior.translucent,
onPointerDown: _releaseFieldFocus,
child: AutofillGroup(
child: SingleChildScrollView( child: SingleChildScrollView(
key: const Key('auth-scroll'), key: const Key('auth-scroll'),
controller: _scrollController, controller: _scrollController,
@@ -339,7 +355,8 @@ class _AuthPageState extends State<AuthPage> {
), ),
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints(minHeight: minHeight), constraints: BoxConstraints(minHeight: minHeight),
child: Center( child: Align(
alignment: Alignment.topCenter,
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints( constraints: const BoxConstraints(
maxWidth: _contentMaxWidth, maxWidth: _contentMaxWidth,
@@ -349,6 +366,7 @@ class _AuthPageState extends State<AuthPage> {
), ),
), ),
), ),
),
); );
}, },
), ),
@@ -410,7 +428,7 @@ class _AuthPageState extends State<AuthPage> {
Widget _landing(AppLocalizations l10n) => Column( Widget _landing(AppLocalizations l10n) => Column(
key: const Key('auth-landing'), key: const Key('auth-landing'),
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Center( Center(
+4
View File
@@ -52,6 +52,10 @@ void main() {
expect(find.byKey(const Key('auth-entry-phone')), findsOneWidget); expect(find.byKey(const Key('auth-entry-phone')), findsOneWidget);
expect(find.byKey(const Key('auth-entry-email')), findsOneWidget); expect(find.byKey(const Key('auth-entry-email')), findsOneWidget);
expect(find.byKey(const Key('auth-legal')), findsOneWidget); expect(find.byKey(const Key('auth-legal')), findsOneWidget);
expect(
tester.getTopLeft(find.byKey(const Key('auth-landing'))).dy,
lessThan(80),
);
await tester.tap(find.byKey(const Key('auth-entry-phone'))); await tester.tap(find.byKey(const Key('auth-entry-phone')));
await tester.pumpAndSettle(); await tester.pumpAndSettle();