fix(auth): 登录页靠上排列并支持外部失焦
This commit is contained in:
1 parent
6318ca24ec
commit
f3d64f6fb5
2 files changed
+44
-22
No files matched your search
@@ -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,26 +338,31 @@ 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(
|
||||||
child: SingleChildScrollView(
|
behavior: HitTestBehavior.translucent,
|
||||||
key: const Key('auth-scroll'),
|
onPointerDown: _releaseFieldFocus,
|
||||||
controller: _scrollController,
|
child: AutofillGroup(
|
||||||
keyboardDismissBehavior:
|
child: SingleChildScrollView(
|
||||||
ScrollViewKeyboardDismissBehavior.onDrag,
|
key: const Key('auth-scroll'),
|
||||||
padding: EdgeInsets.fromLTRB(
|
controller: _scrollController,
|
||||||
AppDimens.pageHorizontal,
|
keyboardDismissBehavior:
|
||||||
top,
|
ScrollViewKeyboardDismissBehavior.onDrag,
|
||||||
AppDimens.pageHorizontal,
|
padding: EdgeInsets.fromLTRB(
|
||||||
bottom,
|
AppDimens.pageHorizontal,
|
||||||
),
|
top,
|
||||||
child: ConstrainedBox(
|
AppDimens.pageHorizontal,
|
||||||
constraints: BoxConstraints(minHeight: minHeight),
|
bottom,
|
||||||
child: Center(
|
),
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: const BoxConstraints(
|
constraints: BoxConstraints(minHeight: minHeight),
|
||||||
maxWidth: _contentMaxWidth,
|
child: Align(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: _contentMaxWidth,
|
||||||
|
),
|
||||||
|
child: _content(l10n, compact: compact),
|
||||||
),
|
),
|
||||||
child: _content(l10n, compact: compact),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -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(
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in new issue
Block a user