flutter-app 样板代码

此仓库是一个用于轻松创建 flutter 应用程序的样板代码。它基于 GetX。关于 GetX 的更多信息请点击这里。该应用程序已设置好可与 retrofit、dio、json_annotation、intl_utils 和 shimmer 配合使用。

入门

  1. 安装 Flutter SDK。需要 Flutter 2.0。
  2. 在 Android Studio 中安装插件
  3. 克隆存储库。
  4. 运行 flutter pub get
  5. 运行 flutter pub run intl_utils:generate
  6. 运行 flutter pub run build_runner build --delete-conflicting-outputs
  7. 运行应用程序。

文件结构

assets
└───font
└───image
    └───2.0x
    └───3.0x

libs
└───common
│   └───app_colors.dart
│   └───app_dimens.dart
│   └───app_images.dart
│   └───app_shadows.dart
│   └───app_text_styles.dart
│   └───app_themes.dart
└───configs
│   └───app_configs.dart
└───database
│   └───secure_storage_helper.dart
│   └───shared_preferences_helper.dart
│   └─── ...
└───l10n
└───models
│   └───entities
│   │   └───user_entity.dart
│   │   └─── ...
│   └───enums
│   │   └───load_status.dart
│   │   └─── ...
│   └───params
│   │   └───sign_up_param.dart
│   │   └─── ...
│   └───response
│       └───array_response.dart
│       └───object_response.dart
└───networks
│   └───api_client.dart
│   └───api_interceptors.dart
│   └───api_util.dart
└───router
│   └───route_config.dart
└───services
│   └───api
│   └───store
│   └───auth_service.dart
│   └───cache_service.dart
│   └───setting_service.dart
└───ui
│   └───commons
│   │   └───app_bottom_sheet.dart
│   │   └───app_dialog.dart
│   │   └───app_snackbar.dart
│   │   └───...
│   └───pages
│   │   └───splash
│   │   │   └───splash_logic.dart
│   │   │   └───splash_state.dart
│   │   │   └───splash_view.dart
│   │   └───...
│   └───widget
│       └───appbar
│       └───buttons
│       │   └───app_button.dart
│       │   └───app_icon_button.dart
│       │   └───...
│       └───images
│       │   └───app_cache_image.dart
│       │   └───app_circle_avatar.dart
│       └───textfields
│       └───shimmer
│       └───...
└───utils
│   └───date_utils.dart
│   └───file_utils.dart
│   └───logger.dart
│   └───utils.dart
└───main.dart

main.dart

程序的“入口点”。
通常,main.dart 包含 AppMaterial,但此仓库使用 GetMaterialApp,它有一个默认的 MaterialApp 作为子组件。

assets

此文件夹用于存放字体和图像等静态资源。

通用

配置

此文件夹包含您的应用程序的配置。

数据库

l10n

此文件夹包含所有本地化字符串。 查看更多

模型

网络

路由

此文件夹包含路由导航。

services

此文件夹包含所有 GetxService 或任何无法从内存中移除的服务。

UI

utils

如何使用

创建屏幕。

所有屏幕都应创建在 ui/pages 文件夹中。
使用 GetX 插件创建新屏幕。

示例:MovieSection

逻辑: movies_section_logic.dart

class MoviesSectionLogic extends GetxController {
  final state = MoviesSectionState();
  final apiService = Get.find<ApiService>();

  void fetchInitialMovies() async {
    state.loadMovieStatus.value = LoadStatus.loading;
    try {
      final result = await apiService.getMovies(page: 1);
      state.loadMovieStatus.value = LoadStatus.success;
      state.movies.value = result.results;
      state.page.value = result.page;
      state.totalPages.value = result.totalPages;
    } catch (e) {
      state.loadMovieStatus.value = LoadStatus.failure;
    }
  }
  ...
}

状态: movies_section_state.dart

class MoviesSectionState {
  final loadMovieStatus = LoadStatus.initial.obs;
  final movies = <MovieEntity>[].obs;
  final page = 1.obs;
  final totalResults = 0.obs;
  final totalPages = 0.obs;
  ...
}

视图: movies_section_view.dart

class MoviesSectionPage extends StatefulWidget {...}

class _MoviesSectionPageState extends State<MoviesSectionPage> {
  final MoviesSectionLogic logic = Get.put(MoviesSectionLogic());
  final MoviesSectionState state = Get.find<MoviesSectionLogic>().state;
  
  @override
  Widget build(BuildContext context) {
    return Obx(() {
      if (state.loadMovieStatus.value == LoadStatus.loading) {
        return _buildLoadingList();
      } else if (state.loadMovieStatus.value == LoadStatus.failure) {
        return Container();
      } else {
        return _buildSuccessList(
          state.movies,
          showLoadingMore: !state.hasReachedMax,
        );
      }
    });
  }
}

创建 API 服务。

  1. lib/models/entities 文件夹中创建实体对象。
    例如:movie_entity.dart
import 'package:json_annotation/json_annotation.dart';

part 'movie_entity.g.dart';

@JsonSerializable()
class MovieEntity {
  @JsonKey()
  String? title;
  ...
    
  factory MovieEntity.fromJson(Map<String, dynamic> json) => _$MovieEntityFromJson(json);
  Map<String, dynamic> toJson() => _$MovieEntityToJson(this);
}

类必须具有 @JsonSerializable() 以供生成器使用。请阅读 json_serializable

  1. 在文件 lib/networks/api_client.dart 中定义和生成您的 API。
    例如:GET movies
  /// Movie
  @GET("/3/discover/movie")
  Future<ArrayResponse<MovieEntity>> getMovies(@Query('api_key') String apiKey, @Query('page') int page);

注意:使用 ArrayResponseObjectResponse 进行通用响应。

  1. 需要运行命令行
flutter pub run build_runner build --delete-conflicting-outputs
  1. lib/services/api 文件夹中为您的功能创建 API 服务文件。
    例如:movies_api.dart
part of 'api_service.dart';

extension MovieApiService on ApiService {
  Future<ArrayResponse<MovieEntity>> getMovies({int page = 1}) async {
    return _apiClient.getMovies(MovieAPIConfig.APIKey, page);
  }
}

之后,将 part 'auth_api.dart'; 添加到 services/api/api_service

  1. 您可以在屏幕的逻辑中调用 API。
    例如
  final apiService = Get.find<ApiService>();
  final result = await apiService.getMovies(page: 1);

支持多主题和多语言

有关更多详细信息,请参见 SettingService 类。

其他

Logger

logger.d("message"); //"? DEBUG: message"
logger.i("message"); //"? INFO: message"
logger.e("message"); //"❤️ ERROR: message"
logger.log("very very very long message");

Snackbar

AppSnackbar.showInfo(message: 'Info');
AppSnackbar.showWarning(message: 'Warning');
AppSnackbar.showError(message: 'Error');

对话框

AppDialog.defaultDialog(
          message: "An error happened. Please check your connection!",
          textConfirm: "Retry",
          onConfirm: () {
            //Do something
          },
);

调用 API 时的按钮 UI

return Obx(() {
    return Container(
        padding: EdgeInsets.symmetric(horizontal: 20),
        child: AppTintButton(
          title: 'Sign In',
          onPressed: _signIn,
          isLoading: state.signInStatus.value == LoadStatus.loading,
        ),
    );
});

GitHub

https://github.com/newwavesolutions/flutter-app-getx