You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现Flutter登录应用的响应式布局?适配各类屏幕

Fixing Responsive Login Screen for All Flutter Device Sizes

Hey there! I see your login screen works great on the simulator but breaks on smaller phones—this is super common when using hard-coded fixed values for sizes, fonts, and dimensions. Let's refactor your code to make it fully responsive so it adapts smoothly to any screen size.

Key Issues in Your Current Code

  • Hard-coded values like minWidth: 400.0 (way too wide for small screens)
  • Fixed font sizes that don't scale with screen size
  • Fixed image height that might take up too much space on small devices
  • Unnecessary nested Row + Expanded wrappers that complicate the layout

Refactored Responsive Code

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: "Service",
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: LoginScreen(),
    );
  }
}

class LoginScreen extends StatefulWidget {
  const LoginScreen({super.key});

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  void printSomething() {
    print("Something was printed");
  }

  @override
  Widget build(BuildContext context) {
    // Get screen dimensions for responsive calculations
    final screenSize = MediaQuery.of(context).size;
    final screenWidth = screenSize.width;
    final screenHeight = screenSize.height;

    return Scaffold(
      body: SingleChildScrollView(
        padding: EdgeInsets.symmetric(horizontal: screenWidth * 0.05),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Spacer to center content vertically
            SizedBox(height: screenHeight * 0.1),
            // Responsive logo
            Image.asset(
              'assets/logo.png',
              height: screenHeight * 0.2, // 20% of screen height
              fit: BoxFit.contain,
            ),
            SizedBox(height: screenHeight * 0.05),
            // Title section
            Text(
              "Please login using your credentials",
              textAlign: TextAlign.center,
              style: TextStyle(
                fontSize: screenWidth * 0.05, // 5% of screen width
                fontWeight: FontWeight.bold,
              ),
            ),
            SizedBox(height: screenHeight * 0.05),
            // Username TextField
            TextField(
              autocorrect: false,
              controller: _usernameController,
              maxLines: 1,
              decoration: const InputDecoration(
                hintText: "Username",
                icon: Icon(Icons.person),
              ),
              style: TextStyle(
                fontSize: screenWidth * 0.045, // 4.5% of screen width
                color: Colors.black,
              ),
            ),
            SizedBox(height: screenHeight * 0.02),
            // Password TextField
            TextField(
              autocorrect: false,
              obscureText: true,
              controller: _passwordController,
              maxLines: 1,
              decoration: const InputDecoration(
                hintText: "Password",
                icon: Icon(Icons.vpn_key),
              ),
              style: TextStyle(
                fontSize: screenWidth * 0.045,
                color: Colors.black,
              ),
            ),
            SizedBox(height: screenHeight * 0.05),
            // Sign In Button
            MaterialButton(
              child: Text(
                "Sign In",
                style: TextStyle(
                  color: Colors.white,
                  fontSize: screenWidth * 0.045,
                ),
              ),
              onPressed: printSomething,
              height: screenHeight * 0.07, // 7% of screen height
              minWidth: double.infinity, // Takes full available width
              color: Colors.blueAccent,
            ),
            SizedBox(height: screenHeight * 0.02),
            // Sign Up Button
            MaterialButton(
              child: Text(
                "Sign Up",
                style: TextStyle(
                  color: Colors.white,
                  fontSize: screenWidth * 0.045,
                ),
              ),
              onPressed: null,
              height: screenHeight * 0.07,
              minWidth: double.infinity,
              color: Colors.blueAccent,
            ),
            SizedBox(height: screenHeight * 0.1),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _usernameController.dispose();
    _passwordController.dispose();
    super.dispose();
  }
}

What Changed & Why

  1. Separated Login Screen into Stateful Widget: Makes code cleaner and follows best practices (properly disposing text controllers to avoid memory leaks).
  2. Used MediaQuery for Dynamic Sizing: All dimensions are calculated as percentages of the screen width/height, so they scale perfectly on any device—no more fixed values that break on small screens.
  3. Replaced ListView with SingleChildScrollView: Ensures content scrolls on very small screens where the entire UI can't fit vertically, preventing overflow errors.
  4. Removed Unnecessary Nested Layouts: Got rid of redundant Row + Expanded wrappers—Column with CrossAxisAlignment.stretch is simpler and more effective for full-width components.
  5. Responsive Font Sizes: Fonts scale based on screen width, so they're readable on both small phones and large tablets without manual adjustments.
  6. Consistent Vertical Spacing: Used percentage-based SizedBox heights to keep spacing proportional across all device sizes.

Bonus Tips

  • For even better font scaling, consider using the auto_size_text package to automatically resize text that doesn't fit its container.
  • Test on multiple emulators/simulators with different screen sizes (from small phones to tablets) to ensure everything looks consistent.
  • Define text styles in your app's ThemeData to keep styles consistent across all screens instead of setting them individually on each widget.

内容的提问来源于stack exchange,提问作者Nayana Rajapaksha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:53:51