flutter + getx 搭建项目架构
pub global activete get_cli flutter pub global activete get_cli
使用get_cli 命令行 1.初始化项目 get init
2.创建页面命令 get create page:tab
3.创建底部导航栏 tab
js
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/tabs_controller.dart';
class TabsView extends GetView<TabsController> {
const TabsView({super.key});
@override
Widget build(BuildContext context) {
// 使用 Obx 包装整个界面以响应状态变化
return Obx(() => Scaffold(
// 主体部分使用 PageView 实现页面切换
body: PageView(
controller: controller.pageController, // 使用控制器中的 PageController
physics: const NeverScrollableScrollPhysics(), // 禁止用户手动滑动页面,只能通过底部导航栏切换
children: controller.pages, // 页面列表,来自控制器中的 pages 数组
// 当页面改变时的回调函数
onPageChanged: (index) {
controller.setCurrentIndex(index); // 更新当前选中的索引
},
),
// 底部导航栏
bottomNavigationBar: BottomNavigationBar(
fixedColor: Colors.red, // 选中项的颜色
currentIndex: controller.currentIndex.value, // 当前选中的索引
type: BottomNavigationBarType.fixed, // 固定类型,当底部有4个或以上菜单时需要配置此参数
// 点击底部导航项时的回调
onTap: (index) {
controller.setCurrentIndex(index); // 更新控制器中的当前索引
controller.pageController.jumpToPage(index); // 跳转到对应的页面
},
// 底部导航项列表
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home), // 图标
label: '首页', // 标签文字
),
BottomNavigationBarItem(
icon: Icon(Icons.category), // 图标
label: '分类', // 标签文字
),
BottomNavigationBarItem(
icon: Icon(Icons.room_service), // 图标
label: '服务', // 标签文字
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart), // 图标
label: '购物车', // 标签文字
),
BottomNavigationBarItem(
icon: Icon(Icons.person), // 图标
label: '用户', // 标签文字
),
]
)
),
);
}
}

不同终端屏幕适配方案,以及自定义适配类
flutter_screenutil 屏幕适配方案,用于屏幕大小和字体大小的插件,
自定义适配类
js
import 'package:flutter_screenutil/flutter_screenutil.dart';
class ScreenAdapter{
static width(num v){
return v.w;
}
static height(num v){
return v.h;
}
static fontSize(num v){
return v.sp;
}
static getScreenWidth(){
// return ScreenUtil().screenWidth;
return 1.sw;
}
static getScreenHeight (){
// return ScreenUtil().screenHeight;
return 1.sh;
}
static getStatusBarHeight(){
return ScreenUtil().statusBarHeight;
//return 1.sh;
}
}
在main.dart 中使用
js
// 导入 Flutter Material Design 组件库
import 'package:flutter/material.dart';
// 导入系统 UI 控制包,用于设置状态栏样式
import 'package:flutter/services.dart';
// 导入屏幕适配工具包,用于响应式设计
import 'package:flutter_screenutil/flutter_screenutil.dart';
// 导入 GetX 状态管理包
import 'package:get/get.dart';
// 导入应用路由页面配置
import 'app/routes/app_pages.dart';
/// 应用程序入口点
void main() {
// 配置透明的状态栏样式
SystemUiOverlayStyle systemUiOverlayStyle = const SystemUiOverlayStyle(
statusBarColor: Colors.transparent // 设置状态栏背景为透明
);
// 应用系统 UI 样式配置
SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
runApp(
// 屏幕适配初始化包装器
ScreenUtilInit(
designSize: const Size(1080, 2400), // 设计稿尺寸,宽度1080px,高度2400px
minTextAdapt: true, // 最小文本适配,确保文本在不同屏幕密度下可读性
splitScreenMode: true, // 分屏模式支持
builder: (context, child) {
// GetX Material 应用程序主入口
return GetMaterialApp(
title: "商场", // 应用标题
initialRoute: AppPages.INITIAL, // 初始路由页面,从 AppPages 获取
getPages: AppPages.routes, // 路由页面列表,从 AppPages 获取
);
},
)
);
}
透明状态栏,透明顶部导航栏,首页导航布局
flutter 透明状态栏设置
js
void main() {
// 配置透明的状态栏样式
SystemUiOverlayStyle systemUiOverlayStyle = const SystemUiOverlayStyle(
statusBarColor: Colors.transparent // 设置状态栏背景为透明
);
// 应用系统 UI 样式配置
SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
flutter 透明顶部导航 通过backgroudcolor:Colors.transparent 结合 elevation:0 可以实现透明导航,要实现透明浮动导航的话需要使用定位
js
// 顶部导航栏组件
Widget _appBar() {
return Positioned(
top: 0,
left: 0,
right: 0,
child: Obx(() => AppBar(
// 根据 flag 状态控制左侧图标显示
leading: controller.flag.value
? const Text("") // flag 为 true 时显示空白占位
: const Icon(
ItyingFonts.xiaomi, // flag 为 false 时显示小米图标
color: Colors.white,
),
// 根据 flag 状态调整 leading 宽度
leadingWidth: controller.flag.value
? ScreenAdapter.width(40) // flag 为 true 时较窄
: ScreenAdapter.width(140), // flag 为 false 时较宽
// 中间搜索框组件
title: InkWell(
child: AnimatedContainer(
// 根据 flag 状态动态调整搜索框宽度
width: controller.flag.value
? ScreenAdapter.width(800) // flag 为 true 时较宽
: ScreenAdapter.width(620), // flag 为 false 时较窄
height: ScreenAdapter.height(96), // 固定高度
decoration: BoxDecoration(
color: const Color.fromARGB(230, 252, 243, 236), // 搜索框背景色
borderRadius: BorderRadius.circular(30), // 圆角
),
duration: const Duration(milliseconds: 600), // 动画持续时间
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.fromLTRB(
ScreenAdapter.width(34), 0, ScreenAdapter.width(10), 0),
child: const Icon(Icons.search), // 搜索图标
),
Text("手机",
style: TextStyle(
color: Colors.black54, // 文字颜色
fontSize: ScreenAdapter.fontSize(32))) // 字体大小
],
),
),
// 点击搜索框跳转到搜索页面
onTap: (){
Get.toNamed("/search");
},
),
centerTitle: true, // 标题居中
// 根据 flag 状态设置 AppBar 背景色
backgroundColor:
controller.flag.value ? Colors.white : Colors.transparent,
elevation: 0, // 去除阴影
// 右侧操作按钮
actions: [
IconButton(
onPressed: () {}, // 二维码按钮点击事件
icon: Icon(
Icons.qr_code, // 二维码图标
// 根据 flag 状态设置图标颜色
color:
controller.flag.value ? Colors.black87 : Colors.white,
)),
IconButton(
onPressed: () {}, // 消息按钮点击事件
icon: Icon(Icons.message, // 消息图标
// 根据 flag 状态设置图标颜色
color: controller.flag.value
? Colors.black87
: Colors.white))
],
)),
);
}
在controller中
js
/// 状态标志位,用于控制UI元素的显示状态(如顶部导航栏透明度等)
RxBool flag = false.obs;
/// 滚动控制器,用于监听首页滚动事件
final ScrollController scrollController = ScrollController();
/// 控制器初始化方法
/// 在这里设置滚动监听器并加载所有首页数据
@override
void onInit() {
super.onInit();
// 添加滚动监听器,用于根据滚动位置改变UI状态
scrollController.addListener(() {
// 当滚动位置超过10像素时,改变flag状态为true
if (scrollController.position.pixels > 10) {
if (flag.value == false) {
print("position");
flag.value = true;
update(); // 更新UI
}
}
// 当滚动位置回到10像素以内时,改变flag状态为false
if (scrollController.position.pixels < 10) {
if (flag.value == true) {
print("position");
flag.value = false;
update(); // 更新UI
}
}
});


轮播图 flutter_swiper_view: ^1.1.8 # 轮播
js
// 顶部主轮播图
SizedBox(
width: ScreenAdapter.width(1080),
height: ScreenAdapter.height(682),
child: Obx(() => Swiper(
itemBuilder: (context, index) {
// 构造轮播图图片 URL
String picUrl="https://xiaomi.itying.com/${controller.swiperList[index].pic}";
return Image.network(
picUrl.replaceAll("\\", "/"), // 处理路径分隔符
fit: BoxFit.fill, // 填充模式
);
},
itemCount:controller.swiperList.length, // 轮播图数量
pagination: const SwiperPagination(
builder: SwiperPagination.rect // 矩形分页指示器
),
autoplay:true, // 自动播放
loop:true, // 循环播放
)),
),
js
{
"result": [
{
"_id": "6332b1beb1ba6105c889734f",
"title": "redmi k40S",
"status": "1",
"pic": "public\\upload\\woudSGBv9MYfp01_sEILWG3s.png",
"url": "12",
"position": 2
},
{
"_id": "6332b1dcb1ba6105c8897350",
"title": "MIX Fold2",
"status": "1",
"pic": "public\\upload\\fWneGqwSQaBpJMt2WYLpbG8E.png",
"url": "23",
"position": 2
},
{
"_id": "6332b1f5b1ba6105c8897351",
"title": "全能扫拖机器人",
"status": "1",
"pic": "public\\upload\\K4-G_kiT90fftfBo0tZpYSSC.png",
"url": "23",
"position": 2
}
]
}
json 字符串生成模型类 autocode.icu/jsontodart
js
class FocusModel {
List<FocusItemModel>? result;
FocusModel({this.result});
FocusModel.fromJson(Map<String, dynamic> json) {
if (json['result'] != null) {
result = <FocusItemModel>[];
json['result'].forEach((v) {
result?.add(FocusItemModel.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
if (result != null) {
data['result'] = result?.map((v) => v.toJson()).toList();
}
return data;
}
}
class FocusItemModel {
String? sId;
String? title;
String? status;
String? pic;
String? url;
FocusItemModel({this.sId, this.title, this.status, this.pic, this.url});
FocusItemModel.fromJson(Map<String, dynamic> json) {
sId = json['_id'];
title = json['title'];
status = json['status'];
pic = json['pic'];
url = json['url'];
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['_id'] = sId;
data['title'] = title;
data['status'] = status;
data['pic'] = pic;
data['url'] = url;
return data;
}
}
在controller 请求
js
/// 获取热销轮播图数据
/// 通过position=2参数获取特定位置的轮播图
/// API地址: https://miapp.itying.com/api/focus?position=2
getSellingSwiperData() async {
try {
// 发起网络请求获取热销轮播图数据
var response = await Dio().get("https://miapp.itying.com/api/focus?position=2");
// 将返回的JSON数据转换为FocusModel对象
var sellingSwiper = FocusModel.fromJson(response.data);
// 更新最佳销售轮播图数据列表
bestSellingSwiperList.value = sellingSwiper.result!;
// 通知UI更新
update();
} catch (e) {
// 错误处理
print("获取热销轮播图数据失败: $e");
}
}

分类导航
