hocvietcode.com
  • Trang chủ
  • Học lập trình
    • Lập trình C/C++
    • Lập trình HTML
    • Lập trình Javascript
      • Javascript cơ bản
      • ReactJS framework
      • AngularJS framework
      • Typescript cơ bản
      • Angular
    • Lập trình Mobile
      • Lập Trình Dart Cơ Bản
        • Dart Flutter Framework
    • Cơ sở dữ liệu
      • MySQL – MariaDB
      • Micrsoft SQL Server
      • Extensible Markup Language (XML)
      • JSON
    • Lập trình PHP
      • Lập trình PHP cơ bản
      • Laravel Framework
    • Lập trình Java
      • Java Cơ bản
    • Cấu trúc dữ liệu và giải thuật
    • Lập Trình C# Cơ Bản
    • Machine Learning
  • WORDPRESS
    • WordPress cơ bản
    • WordPress nâng cao
    • Chia sẻ WordPress
  • Kiến thức hệ thống
    • Microsoft Azure
    • Docker
    • Linux
  • Chia sẻ IT
    • Tin học văn phòng
      • Microsoft Word
      • Microsoft Excel
    • Marketing
      • Google Adwords
      • Facebook Ads
      • Kiến thức khác
    • Chia sẻ phần mềm
    • Review công nghệ
    • Công cụ – tiện ích
      • Kiểm tra bàn phím online
      • Kiểm tra webcam online
Đăng nhập
  • Đăng nhập / Đăng ký

Please enter key search to display results.

Home
  • Dart Flutter Framework
Tạo kiểu và Tạo ứng dụng đáp ứng trong Flutter

Tạo kiểu và Tạo ứng dụng đáp ứng trong Flutter

  • 11-06-2024
  • Toanngo92
  • 0 Comments

Mục lục

  • Tạo kiểu trong Flutter
    • Tạo chủ đề cho ứng dụng trong Flutter
    • Ví dụ về giao diện người dùng (UI)
    • Tạo kiểu cho một Widget cụ thể trong Flutter
    • a. Văn bản (Text)
    • b. Container:
    • c. RaisedButton:
  • Chuyển đổi giữa các giao diện trong Flutter
    • Tạo giao diện tối trong Flutter
    • Tạo giao diện sáng trong Flutter
    • Chuyển đổi giữa giao diện tối và sáng trong Flutter
  • Ứng dụng Flutter Responsive
    • Xây dựng Lớp: Flutter
    • MediaQuery.of() Phương thức hàm xây dựng
  • Các Tiện ích để Xây Dựng Giao Diện Đáp ứng trong Flutter
    • Aspect Ratio
    • CustomSingleChildLayout
    • CustomMultiChildLayout
    • FittedBox
    • MediaQueryData
      • Insets và Padding
    • OrientationBuilder

Tạo kiểu trong Flutter

Tạo kiểu là một yêu cầu thiết yếu cho bất kỳ ứng dụng nào. Một giao diện người dùng đẹp có thể thu hút rất nhiều người dùng.

Flutter cung cấp nhiều phương pháp tạo kiểu và tùy chọn để tạo kiểu cho toàn bộ chủ đề của ứng dụng.

Tạo chủ đề cho ứng dụng trong Flutter

Tạo chủ đề cho ứng dụng trong Flutter rất đơn giản. MaterialApp trong main.dart là thành phần bọc toàn bộ ứng dụng và nó có một tham số gọi là theme nơi các nhà phát triển có thể chỉ định chủ đề cho toàn bộ ứng dụng. Bất kỳ thay đổi nào ở đây sẽ được phản ánh xuyên suốt ứng dụng, do đó ngăn chặn mã trùng lặp. Đoạn mã ví dụ 1 cho thấy tham số chủ đề cho main.dart được tự động tạo của một ứng dụng mẫu.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Hello, Flutter!',
            ),
          ],
        ),
      ),
    );
  }
}
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Styling Demo',
      // theme
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: StylingExample(),
    );
  }
}

Ví dụ về giao diện người dùng (UI)

Đoạn bên dưới cho thấy một ví dụ về một giao diện người dùng đơn giản. Đây là lớp StylingExample() được tham chiếu trong main.dart.

Ở đây, văn bản, biểu tượng, nút, thanh trượt và hộp kiểm được sử dụng mà không có bất kỳ thuộc tính tạo kiểu nào. Mặc định, màu chủ đạo sẽ là màu xanh lam. Điều này có nghĩa là tất cả các widget được tạo mà không có kiểu sẽ có màu xanh lam.

import 'package:flutter/material.dart';

class StylingExample extends StatelessWidget {
  const StylingExample({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('App Bar'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(
            'Heading 4',
            style: Theme.of(context).textTheme.headline4,
          ),
          Slider(value: 0, onChanged: (s) {}),
          Icon(Icons.collections_sharp),
          Checkbox(value: true, onChanged: (s) {}),
          TextButton(onPressed: () {}, child: const Text('Text Button')),
          ElevatedButton(onPressed: () {}, child: const Text('Elevated Button')),
        ],
      ),
    );
  }
}

Hình bên dưới cho thấy kết quả của widget StylingExample.

Trong ví dụ trên, chúng ta có một giao diện người dùng đơn giản với các thành phần mặc định theo chủ đề màu xanh lam. Tất cả các thành phần như thanh trượt, biểu tượng, hộp kiểm, nút văn bản, và nút nổi đều sẽ có màu chủ đạo theo chủ đề đã thiết lập trong ThemeData.

Tạo kiểu cho một Widget cụ thể trong Flutter

a. Văn bản (Text)

Văn bản có thể được tạo kiểu bằng cách sử dụng phương thức TextStyle để thay đổi các thuộc tính như màu sắc, màu nền, kích thước chữ, độ đậm chữ, chiều cao dòng, khoảng cách giữa các từ/chữ cái, gạch dưới, kiểu và nhiều thuộc tính khác.

Cú pháp của TextStyle như sau:

Text(
  'New Text',
  style: TextStyle(
    fontSize: 30,
    fontWeight: FontWeight.w600,
    color: Colors.teal,
    height: 1.5,
    wordSpacing: 2,
    letterSpacing: 2,
    backgroundColor: Colors.yellow,
  ),
)

Đoạn mã bên dưới minh họa cách sử dụng phương thức TextStyle.

Text(
  'New Text',
  style: TextStyle(
    fontSize: 30,
    fontWeight: FontWeight.w600,
    color: Colors.teal,
    height: 1.5,
    wordSpacing: 2,
    letterSpacing: 2,
    backgroundColor: Colors.yellow,
  ),
)

Hình bên dưới minh họa kết quả của văn bản đã được tạo kiểu.

b. Container:

Container có thuộc tính decoration có thể được sử dụng để chỉ định viền, borderRadius, bóng đổ (shadow), gradient, hình ảnh, và nhiều hơn nữa.

Cú pháp cho decoration như sau:

Decoration? decoration,

Một Container đơn giản với borderRadius, boxShadow, và border được tạo trong Đoạn mã bên dưới đây.

Container(
  height: 100,
  width: 100,
  decoration: BoxDecoration(
    // màu sắc
    color: Colors.orange,
    // border radius
    borderRadius: BorderRadius.circular(10),
    // border với độ dày 5
    border: Border.all(color: Colors.orange.shade900, width: 5),
    // bóng đổ cho container
    boxShadow: [
      BoxShadow(
        // offset nơi bóng đổ nên rơi
        offset: Offset(5, 10),
        // màu bóng đổ
        color: Colors.grey,
        // bán kính mờ
        blurRadius: 5,
        // bán kính lan tỏa
        spreadRadius: 1,
      ),
    ],
  ),
)

Hình bên dưới hiển thị kết quả của việc thực thi Đoạn mã trên.

Lưu ý: Nếu sử dụng thuộc tính decoration, thì màu sắc phải được chỉ định bên trong BoxDecoration, nếu không sẽ gây ra lỗi.

c. RaisedButton:

RaisedButton đã bị khai tử trong Flutter và không nên sử dụng nữa. Thay vào đó, có thể sử dụng ElevatedButton.

Dưới đây là các thuộc tính của ElevatedButton:

ButtonStyle styleFrom({
  Color? primary,
  Color? onPrimary,
  Color? onSurface,
  Color? shadowColor,
  Color? surfaceTintColor,
  double? elevation,
  TextStyle? textStyle,
  EdgeInsetsGeometry? padding,
  Size? minimumSize,
  Size? fixedSize,
  Size? maximumSize,
  BorderSide? side,
  OutlinedBorder? shape,
  MouseCursor? enabledMouseCursor,
  MouseCursor? disabledMouseCursor,
  VisualDensity? visualDensity,
  MaterialTapTargetSize? tapTargetSize,
  Duration? animationDuration,
  bool? enableFeedback,
  AlignmentGeometry? alignment,
  InteractiveInkFeatureFactory? splashFactory,
})

Đoạn mã bên dưới và Hình tiếp theo cho thấy ví dụ và kết quả cho ElevatedButton.

ElevatedButton(
  onPressed: () {},
  child: Text("Button"),
  style: ElevatedButton.styleFrom(
    // màu nút
    primary: Colors.amber.shade700,
    // hình dạng và border radius
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(20),
    ),
    // để chỉ định kích thước cố định cho nút
    fixedSize: Size(100, 100),
  ),
)

Chuyển đổi giữa các giao diện trong Flutter

Nhiều ứng dụng hiện nay có tùy chọn chuyển đổi giữa giao diện sáng và tối. Một số ứng dụng thậm chí còn có tùy chọn đặt giao diện tùy chỉnh. Người dùng nên cảm thấy thoải mái khi sử dụng ứng dụng theo cách họ muốn. Các giao diện trong Flutter cung cấp một cách để đặt màu sắc tùy chỉnh, phông chữ, kích thước và viền cho nhiều widget, và sẽ được áp dụng cho toàn bộ ứng dụng.

Cũng có thể tạo các giao diện tùy chỉnh theo yêu cầu.

Tạo giao diện tối trong Flutter

Bước 1: Tạo một tệp lớp mới gọi là AppTheme nơi các giao diện có thể được chỉ định. Tạo một biến tĩnh mới gọi là darkTheme. Tham khảo Đoạn mã bên dưới.

class AppTheme {
  static ThemeData darkTheme = ThemeData();
}

Bước 2: Gọi theme bên trong MaterialApp. Đoạn mã bên dưới cho thấy cách gọi theme bên trong MaterialApp trong tệp main.dart.

MaterialApp(
  darkTheme: AppTheme.darkTheme,
  home: StylingExample(),
)

Đoạn mã tiếp theo cho thấy cách tạo kiểu giao diện tối cho ứng dụng Flutter.

class AppTheme {
  static ThemeData darkTheme = ThemeData(
    // Màu nền scaffold
    scaffoldBackgroundColor: Colors.black54,
    // Giao diện app bar
    appBarTheme: AppBarTheme(color: Colors.purple),
    // Giao diện elevated button
    elevatedButtonTheme: ElevatedButtonThemeData(
      style: ElevatedButton.styleFrom(primary: Colors.red),
    ),
    // Giao diện icon
    iconTheme: IconThemeData(color: Colors.white),
    // Giao diện text - heading 4
    textTheme: TextTheme(
      headline4: TextStyle(color: Colors.white70, fontWeight: FontWeight.w500),
    ),
  );
}

Tạo giao diện sáng trong Flutter

Bước 1: Làm theo các bước tương tự khi tạo giao diện tối để tạo giao diện sáng trong cùng lớp. Đoạn mã bên dưới cho thấy cách tạo Giao diện Sáng.

class AppTheme {
  static ThemeData lightTheme = ThemeData(
    // Màu nền scaffold
    scaffoldBackgroundColor: Colors.white,
    // Giao diện app bar
    appBarTheme: AppBarTheme(color: Colors.indigo),
    // Giao diện elevated button
    elevatedButtonTheme: ElevatedButtonThemeData(
      style: ElevatedButton.styleFrom(primary: Colors.red),
    ),
    // Giao diện text - heading 4
    textTheme: TextTheme(
      headline4: TextStyle(color: Colors.blueGrey, fontWeight: FontWeight.w500),
    ),
  );
}

Bước 2: Bên trong MaterialApp, áp dụng giao diện sáng như sau:

MaterialApp(
  theme: AppTheme.lightTheme,
)

Chuyển đổi giữa giao diện tối và sáng trong Flutter

Bước 1: Để chuyển đổi giữa các giao diện, tạo một nút mà khi nhấn sẽ chuyển đổi giao diện. Có hai giao diện được định nghĩa trong MaterialApp. Thêm một thuộc tính khác gọi là themeMode và thay đổi lớp AppTheme bằng cách mở rộng ChangeNotifier. Tham khảo Đoạn mã dưới đây. Đây là một tệp mới gọi là apptheme.dart.

Bước 2: Tạo một biến boolean để chuyển đổi giữa các giao diện tối và sáng, sau đó là một hàm để thay đổi giao diện và thông báo cho các listener.

class AppTheme extends ChangeNotifier {
  bool _isDarkTheme = true;

  ThemeMode get currentTheme => _isDarkTheme ? ThemeMode.dark : ThemeMode.light;

  void toggleTheme() {
    _isDarkTheme = !_isDarkTheme;
    notifyListeners();
  }
}

Bước 3: Tạo một thể hiện toàn cục cho AppTheme trong tệp main.dart như sau:

final AppTheme appTheme = AppTheme();

Bước 4: Bây giờ, xác định các giao diện này trong MaterialApp trong main.dart. Thay đổi MyApp thành một StatefulWidget. Trong initState, thêm một trình nghe cho appTheme, để việc thay đổi chủ đề sẽ được cập nhật ngay lập tức. Tham khảo đoạn mã bên dưới.

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    // Thêm một trình nghe
    appTheme.addListener(() {
      setState(() {});
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    // Cập nhật giao diện dựa trên chủ đề hiện tại
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Styling Demo',
      // Chủ đề
      theme: AppTheme.lightTheme,
      darkTheme: AppTheme.darkTheme,
      // Chế độ chủ đề
      themeMode: appTheme.currentTheme,
      home: StylingExample(),
    );
  }
}

Bước 5: Cuối cùng, tạo một nút để chuyển đổi chủ đề. Trong appBar của StylingExample, thêm một IconButton và cung cấp hàm toggleTheme. Tham khảo mã đoạn mã bên dưới.

actions: [
  IconButton(
    onPressed: () {
      appTheme.toggleTheme();
    },
    icon: Icon(Icons.brightness_4),
  ),
],

Với các bước trên, bạn đã tạo được khả năng chuyển đổi giữa các chủ đề sáng và tối khi người dùng nhấn vào nút.

Ứng dụng Flutter Responsive

Flutter là một framework đa nền tảng có thể được sử dụng để xây dựng ứng dụng từ các đồng hồ thông minh đến các TV lớn. Trong những trường hợp này, không thể sử dụng cùng một thiết kế và bố cục. Các bố cục và thiết kế phải được thay đổi để phù hợp với kích thước màn hình. Flutter cung cấp một số widget thông qua đó, tính đáng tin cậy có thể được đạt được.

Dưới đây là các bước để đạt được tính đáng tin cậy trong một ứng dụng Flutter:

Bước 1: Để ứng dụng Flutter hỗ trợ tất cả các hướng, thêm mã được cung cấp trong đoạn mã bên dưới vào phần build của MyApp() từ main.dart.

import 'package:flutter/services.dart';

SystemChrome.setPreferredOrientations([
  DeviceOrientation.landscapeLeft,
  DeviceOrientation.landscapeRight,
  DeviceOrientation.portraitDown,
  DeviceOrientation.portraitUp,
]);

Bước 2: Sử dụng setPreferredOrientations, chỉ định danh sách các hướng mà thiết bị nên hỗ trợ. Ví dụ, nếu ứng dụng chỉ hoạt động trong chế độ ngang, chỉ định hai tùy chọn này:

DeviceOrientation.landscapeLeft
DeviceOrientation.landscapeRight

Tương tự, sử dụng các tùy chọn dọc nếu ứng dụng cần hỗ trợ chế độ dọc.

Xây dựng Lớp: Flutter

Sử dụng LayoutBuilder, có thể xác định maxHeight và maxWidth của Widget.

Trong Đoạn mã bên dưới, hai LayoutBuilder được xác định bên trong một Row. Widget Expanded có thể được sử dụng để phân bổ không gian tối đa. Bên trong các layout builders này, một widget Text được triển khai để hiển thị chiều rộng tối đa mà widget đó chiếm.

Hình ảnh bên dưới cho thấy việc sử dụng LayoutBuilder.

Scaffold(
  appBar: AppBar(),
  body: Row(
    children: [
      // Widget 1
      Expanded(
        child: LayoutBuilder(
          builder: (context, constraints) => Container(
            color: Colors.yellow.shade200,
            child: Center(
              child: Text('Widget width\n' + constraints.maxWidth.toStringAsFixed(2)),
            ),
          ),
        ),
      ),
      // Widget 2
      Expanded(
        flex: 2,
        child: LayoutBuilder(
          builder: (context, constraints) => Container(
            color: Colors.teal,
            child: Center(
              child: Text('Widget width\n' + constraints.maxWidth.toStringAsFixed(2)),
            ),
          ),
        ),
      ),
    ],
  ),
);

MediaQuery.of() Phương thức hàm xây dựng

Trong Flutter, MediaQuery có thể được sử dụng để lấy kích thước (chiều rộng và chiều cao) và hướng (dọc/ngang) của thiết bị. Lưu ý: MediaQuery có thể được sử dụng ở những nơi cần kích thước tổng của màn hình. Trong khi đó, LayoutBuilder có thể được sử dụng ở những nơi cần chiều cao/chiều rộng của một widget cụ thể.

Trong các đoạn mã bên dưới, có thể thấy rằng một container được sử dụng trong một Scaffold và được bọc trong một widget Center. Chiều cao và chiều rộng của Container được xác định bằng MediaQuery, nó sẽ trả về một giá trị double. 0.25 xác định chiều cao của container là 25% của tổng chiều cao. Kết quả trong 2 hình bên dưới cho thấy sự khác biệt khi sử dụng MediaQuery để chỉ định kích thước động cho các hướng.

// Lấy hướng của thiết bị
Orientation orientation = MediaQuery.of(context).orientation;
// Lấy chiều cao của thiết bị
double deviceHeight = MediaQuery.of(context).size.height;
// Lấy chiều rộng của thiết bị
double deviceWidth = MediaQuery.of(context).size.width;
Container(
  height: deviceHeight * 0.25,
  width: deviceWidth * 0.5,
  color: Colors.red,
),

Lưu ý: MediaQuery.of(context) chỉ có thể truy cập từ bên trong phương thức build.

Các Tiện ích để Xây Dựng Giao Diện Đáp ứng trong Flutter

Flutter cung cấp một số tiện ích khác ngoài LayoutBuilder thông qua đó ứng dụng có thể trở nên đáp ứng.

Aspect Ratio

Tỷ lệ khung hình có thể được sử dụng để gán kích thước cụ thể cho một tiện ích con. Tiện ích này trước tiên thử chiều rộng lớn nhất cho phép bởi các ràng buộc bố trí và sau đó quyết định chiều cao bằng cách áp dụng tỷ lệ khung hình đã cho vào chiều rộng.

Tỷ lệ khung hình nên được chỉ định dưới dạng một giá trị double. Tham khảo Đoạn mã bên dưới.

AspectRatio(
  aspectRatio: 16 / 9,
  child: Container(
    color: Colors.amber,
  ),
)

CustomSingleChildLayout

Các tiện ích SingleChildLayout là những tiện ích chỉ cho phép một tiện ích làm tiện ích con của chúng như Container, Align, Center, SizedBox, Positioned, và nhiều tiện ích khác. Một tiện ích con đơn có thể được tạo ra bằng cách sử dụng tiện ích CustomSingleChildLayout. Quan trọng là nhà phát triển phải chỉ định delegate và tiện ích con. Delegate có hai phương thức ghi đè performLayout và shouldRelayout mà cũng có thể được tùy chỉnh theo nhu cầu.

Đoạn mã bên dưới hiển thị cách ghi đè performLayout và shouldLayout mặc định để tùy chỉnh SingleChildLayout.

class MySingleChildDelegate extends SingleChildLayoutDelegate {
  @override
  void performLayout(Size size) {
    // TODO: implement performLayout
  }

  @override
  bool shouldRelayout(covariant SingleChildLayoutDelegate oldDelegate) {
    // TODO: implement shouldRelayout
    throw UnimplementedError();
  }
}

CustomMultiChildLayout

Các tiện ích MultiChildLayout cho phép nhiều tiện ích con. Row, Column, Stack, ListView, và nhiều tiện ích khác có thể được nhấn mạnh như các ví dụ. Sử dụng CustomMultiChildLayourDelegate, có thể tùy chỉnh một tiện ích MultiChild.

Dưới đây là cú pháp cho CustomMultiChildLayout:

CustomMultiChildLayout({
  Key? key,
  required MultiChildLayoutDelegate delegate,
  List<Widget> children = const <Widget>[],
})

Lưu ý rằng các widget con trong widget này cần được đặt bên trong một widget LayoutId, với mỗi con có một ID duy nhất.

FittedBox

FittedBox hạn chế tiện ích con của nó không phát triển vượt quá một giới hạn nhất định. Nó thay đổi tỷ lệ chúng tùy thuộc vào kích thước có sẵn. Đoạn mã bên dưới hiển thị cách thức hoạt động của nó.

Code Snippet 19:

FittedBox(
  child: Container(
    color: Colors.amber,
    child: Text("Fitted Box Container"),
  ),
)

MediaQueryData

MediaQuery.of(context) bản thân nó là một MediaQueryData sẽ trả về các thông tin về padding, ViewInsets và ViewPadding của màn hình hiện tại. Thông tin này sẽ giúp chúng ta tính toán padding cho các hướng, kích thước màn hình và khi bàn phím xuất hiện. Hình bên dưới phân biệt giữa padding, viewInsets và viewPadding.

Insets và Padding

  • Padding: Khoảng cách bên trong giữa nội dung và viền của một phần tử giao diện.
  • ViewInsets: Khoảng cách bị chèn bởi các yếu tố như bàn phím.
  • ViewPadding: Khoảng cách được thêm vào bởi các phần của hệ thống như thanh trạng thái và thanh điều hướng.

Hình bên dưới: Phân biệt giữa Padding, ViewInsets và ViewPadding

OrientationBuilder

OrientationBuilder có thể được sử dụng để bố trí các widget theo hướng của thiết bị (chân dung hoặc phong cảnh). Đoạn mã bên dưới minh họa việc sử dụng OrientationBuilder. GridView đã được sử dụng, trong đó crossAxisCount và childAspectRatio được điều chỉnh theo hướng. Sẽ có hai widget khi ở chế độ chân dung và ba widget khi ở chế độ phong cảnh như trong hình bên dưới.

Scaffold(
  body: OrientationBuilder(
    builder: (context, orientation) => GridView.builder(
      // gridDelegate là nơi chúng ta chỉ định khoảng cách,
      // số lượng và tỷ lệ khung hình...
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        // thay đổi số lượng theo hướng
        crossAxisCount: orientation == Orientation.portrait ? 2 : 3,
        // thay đổi tỷ lệ khung hình theo hướng
        childAspectRatio: orientation == Orientation.portrait ? 1 : 3,
        mainAxisSpacing: 10,
        crossAxisSpacing: 10,
      ),
      itemBuilder: (context, index) => Container(
        color: Colors.blue,
      ),
    ),
  ),
)

Bài viết liên quan:

REST API trong Flutter
Khái niệm cơ bản về cơ sở dữ liệu với Sqllite và Cơ sở dữ liệu Firebase
FutureBuilder và StreamBuilder trong Flutter
Điều Hướng, Định Tuyến và Bộ Điều Khiển trong Flutter
Quản lý trạng thái và Chèn phụ thuộc trong Flutter
Quản lý trạng thái và Chèn phụ thuộc trong Flutter
Xây dựng ứng dụng Flutter bằng cách sử dụng các Multi Child Layout Widgets
Xây dựng Ứng dụng Flutter Sử dụng Single Child Layout Widgets
Xây dựng Ứng dụng Flutter Sử dụng Widget Độc lập Nền tảng
Xây dựng ứng dụng Flutter bằng nền tảng Widget cụ thể
Applications và Widgets trong Flutter
Giới thiệu về Flutter

THÊM BÌNH LUẬN Cancel reply

Dịch vụ thiết kế Wesbite

NỘI DUNG MỚI CẬP NHẬT

2. PHÂN TÍCH VÀ ĐẶC TẢ HỆ THỐNG

1. TỔNG QUAN KIẾN THỨC THỰC HÀNH TRIỂN KHAI DỰ ÁN CÔNG NGHỆ THÔNG TIN

Hướng dẫn tự cài đặt n8n comunity trên CyberPanel, trỏ tên miền

Mẫu prompt tạo mô tả chi tiết bối cảnh

Một số cải tiến trong ASP.NET Core, Razor Page, Model Binding, Gabbage collection

Giới thiệu

hocvietcode.com là website chia sẻ và cập nhật tin tức công nghệ, chia sẻ kiến thức, kỹ năng. Chúng tôi rất cảm ơn và mong muốn nhận được nhiều phản hồi để có thể phục vụ quý bạn đọc tốt hơn !

Liên hệ quảng cáo: [email protected]

Kết nối với HỌC VIẾT CODE

© hocvietcode.com - Tech888 Co .Ltd since 2019

Đăng nhập

Trở thành một phần của cộng đồng của chúng tôi!
Registration complete. Please check your email.
Đăng nhập bằng google
Đăng kýBạn quên mật khẩu?

Create an account

Welcome! Register for an account
The user name or email address is not correct.
Registration confirmation will be emailed to you.
Log in Lost your password?

Reset password

Recover your password
Password reset email has been sent.
The email could not be sent. Possible reason: your host may have disabled the mail function.
A password will be e-mailed to you.
Log in Register
×