🚪
画面遷移が遅いとWidgetが重なる
💡Tips
美しいグラデーションを使用したログインページのUIを作成して画面遷移をさせてみたのだが、次のページに遷移したときに動きが遅いせいか入力フォームとボタンが重なって見えて違和感を感じた。
なんとかならないか?
いつもは感じなかったのだが、入力フォームのデザインを変えたからだろうか?
入力フォームを角丸にするためにわざわざContainerで囲んでいたのだが、これは正しいのかと思うことがあった?
正規表現のバリデーションを表示したときだとUI崩れることがあった。他の方法でデザイン角丸の入力フォームにした方が良いなと思った。
でやってみたら、対策が必要になった💦
解決策
画面遷移のスピードを早くするために、MaterialPageRouteの遷移時間をカスタマイズして対応した。
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
// カスタム遷移用のルート
class FastPageRoute<T> extends MaterialPageRoute<T> {
FastPageRoute({
required WidgetBuilder builder,
}) : super(
builder: builder,
// 遷移時間を100ミリ秒に短縮(デフォルトは300ミリ秒)
maintainState: true,
);
Duration get transitionDuration => const Duration(milliseconds: 100);
Duration get reverseTransitionDuration => const Duration(milliseconds: 100);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.black,
scaffoldBackgroundColor: Colors.transparent,
appBarTheme: const AppBarTheme(
backgroundColor: Colors.black,
foregroundColor: Colors.white,
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.black,
foregroundColor: Colors.white,
minimumSize: const Size.fromHeight(56),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
),
),
home: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
Color.fromRGBO(253, 219, 146, 1),
Color.fromRGBO(209, 253, 254, 1),
],
),
),
child: const LoginPage(),
),
);
}
}
class LoginPage extends StatelessWidget {
const LoginPage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Gradient App'),
),
body: ListView(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 16.0),
children: [
const SizedBox(height: 16),
const Text(
"メールアドレス",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
const SizedBox(height: 8),
TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'メールアドレス',
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
),
),
),
const SizedBox(height: 24),
const Text(
"パスワード",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
const SizedBox(height: 8),
TextFormField(
obscureText: true,
decoration: InputDecoration(
hintText: 'パスワード',
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
),
),
),
const SizedBox(height: 32),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
FastPageRoute(
builder: (context) => Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
Color.fromRGBO(253, 219, 146, 1),
Color.fromRGBO(209, 253, 254, 1),
],
),
),
child: const NextPage(),
),
),
);
},
child: const Text(
'Login',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
],
),
);
}
}
class NextPage extends StatelessWidget {
const NextPage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Next Page'),
),
body: const Center(
child: Text(
"Next Page",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
),
);
}
}
動作
主な変更点:
-
カスタム遷移ルートの作成
-
FastPageRoute
クラスを作成 - 遷移時間を100ミリ秒に短縮(デフォルトの3分の1)
- 戻る時の遷移時間も同様に短縮
-
-
グラデーション背景の継承
- 次の画面でもグラデーション背景を維持
- 遷移時の見た目の一貫性を保持
これにより、画面遷移がより素早く、スムーズになります。必要に応じて遷移時間(milliseconds: 100
)を調整することができます:
- より速くしたい場合は値を小さく(例:50ms)
- よりアニメーションを感じさせたい場合は値を大きく(例:150ms)
また、アニメーションを完全に無効化したい場合は、以下のような方法も可能です:
Navigator.of(context).pushReplacement(
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => const NextPage(),
transitionDuration: Duration.zero,
reverseTransitionDuration: Duration.zero,
),
);
1秒は早すぎるので3秒が丁度良さそう。
// カスタム遷移用のルート
class FastPageRoute<T> extends MaterialPageRoute<T> {
FastPageRoute({
required super.builder,
}) : super(
maintainState: true,
);
Duration get transitionDuration => const Duration(milliseconds: 300);
Duration get reverseTransitionDuration => const Duration(milliseconds: 300);
}
Discussion