import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:keyboard/base/base_view.dart'; import 'package:keyboard/module/character/content/character_group_content_view.dart'; import 'package:keyboard/resource/string.gen.dart'; import '../../resource/assets.gen.dart'; import 'character_controller.dart'; class CharacterView extends BaseView { const CharacterView({super.key}); @override backgroundColor() { return Colors.transparent; } @override Widget buildBody(BuildContext context) { return Scaffold( backgroundColor: Color(0xFFF6F5FA), body: Stack( children: [ Builder( builder: (context) { return Column( children: [ Expanded( child: NestedScrollView( headerSliverBuilder: (context, innerBoxIsScrolled) { return [ SliverPersistentHeader( pinned: true, delegate: CharacterHeaderDelegate( expandedHeight: 380.h, //调整照片位置 minHeight: 270.h, bottomWidget: _bottomAppBar(), onTap: controller.clickMyKeyboard, ), ), ]; }, body: _pages(), ), ), ], ); }, ), ], ), ); } /// **自定义 bottomAppBar** Widget _bottomAppBar() { return Column( children: [ Stack( children: [ Column( children: [ SizedBox(height: 31.h), Container( decoration: ShapeDecoration( gradient: LinearGradient( begin: Alignment(0.50, -0.00), end: Alignment(0.50, 1.00), colors: [Color(0xFFEAE5FF), Color(0xFFF5F4F9)], ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(20.r), topRight: Radius.circular(20.r), ), ), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ // 定义按钮与人设之间的间距 SizedBox(height: 53.h), // 人设市场标识和下拉框 _marketSignAndDropDown(), SizedBox(height: 15.h), _tabBar(), ], ), ), ], ), Positioned( top: 0, left: 0, child: _customizeButton(onTap: controller.clickCustomCharacter)), ], ), ], ); } // 人设市场标识和下拉框 Widget _marketSignAndDropDown() { return Padding( padding: EdgeInsets.symmetric(horizontal: 16.w), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Assets.images.iconCharacterMarket.image( width: 73.w, height: 25.h, ), Obx(() { return DropdownButton( // hint: Text(''), underline: Container(height: 0), style: TextStyle( color: Colors.black.withAlpha(102), fontSize: 14.sp, fontWeight: FontWeight.w400, ), icon: Assets.images.iconCharacterArrowDown.image( width: 20.r, height: 20.r, ), value: controller.currentKeyboardInfo.value.name, onChanged: (String? newValue) { controller.switchKeyboard(newValue); }, items: List.generate( controller.keyboardInfoList.length, (index) { String? value = controller.keyboardInfoList[index].name; return DropdownMenuItem( value: value, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Padding( padding: EdgeInsets.symmetric( vertical: 8, ), child: Text( value ?? "", style: TextStyle( color: Colors.black.withAlpha(204), fontSize: 14.sp, fontWeight: FontWeight.w400, ), ), ), if (index != controller.keyboardInfoList.length - 1) Divider( color: Color(0xFFF6F6F6), thickness: 1, height: 1, ), ], ), ); }, ), ); }), ], ), ); } // 定制按钮 Widget _customizeButton({required VoidCallback onTap}) { return GestureDetector( onTap: onTap, child: Container( margin: EdgeInsets.only(left: 16.w), width: 220.w, height: 56.h, padding: EdgeInsets.symmetric(horizontal: 10.w), decoration: ShapeDecoration( color: const Color(0xFF121212), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(40.r), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Assets.images.iconCharacterCustomized.image( width: 36.r, height: 36.r, ), SizedBox(width: 8.w), Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( StringName.goCustomizeCharacter, textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 16.sp, fontWeight: FontWeight.w500, ), ), Text( StringName.goCustomizeCharacterDesc, style: TextStyle( color: Color(0xFFF5F4F9), fontSize: 11.sp, fontWeight: FontWeight.w400, ), ), ], ), Container( margin: EdgeInsets.only(left: 16.w), width: 24.r, height: 24.r, decoration: ShapeDecoration( color: Colors.white, shape: OvalBorder(), ), child: Assets.images.iconCharacterArrowRight.image( width: 16.r, height: 16.r, ), ), ], ), ), ); } /// **TabBar** Widget _tabBar() { return Obx(() { if (controller.characterGroupList.isEmpty) { return const SizedBox.shrink(); } return TabBar( controller: controller.tabController.value, dividerHeight: 0, tabAlignment: TabAlignment.start, isScrollable: true, padding: EdgeInsets.symmetric(horizontal: 12.w), labelPadding: EdgeInsets.symmetric(horizontal: 4.w), indicator: const BoxDecoration(), onTap: (index) => controller.onTabChanged(index), tabs: List.generate(controller.characterGroupList.length, (index) { var e = controller.characterGroupList[index]; bool isSelected = index == controller.currentTabBarIndex.value; return Column( children: [ Container( width: 80.w, height: isSelected ? 38.h : 32.h, padding: isSelected ?EdgeInsets.only(bottom: 4.h) :EdgeInsets.zero, decoration: isSelected ? BoxDecoration( borderRadius: BorderRadius.circular(36.r), image: DecorationImage( image: Assets.images.iconCharacterGroupSelected.provider(), fit: BoxFit.fill, ), ) : BoxDecoration( color: Colors.white.withAlpha(204), borderRadius: BorderRadius.circular(36.r), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ if (e.iconUrl != null) CachedNetworkImage( imageUrl: e.iconUrl!, width: 20.r, height: 20.r, ), Text( e.name ?? "", style: TextStyle( color: isSelected ? Colors.black : Colors.black.withAlpha(104), fontSize: 14.sp, fontWeight: FontWeight.w500, ), ), ], ), ), !isSelected? SizedBox(height: 4.h):SizedBox(), ], ); }), ); }); } Widget _pages() { return Obx(() { if (controller.characterGroupList.isEmpty) { return const Center(child: CircularProgressIndicator()); } return PageView( controller: controller.pageController, onPageChanged: (index) { controller.onPageChanged(index); }, children: controller.characterGroupList.map((group) { return CharacterGroupContentView(); }).toList(), ); }); } } /// **🔹 可伸缩的 class CharacterHeaderDelegate extends SliverPersistentHeaderDelegate { final double expandedHeight; final double minHeight; final Widget bottomWidget; final VoidCallback onTap; CharacterHeaderDelegate({ required this.expandedHeight, required this.minHeight, required this.bottomWidget, required this.onTap, }); @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent, ) { final currentVisibleHeight = (expandedHeight - shrinkOffset).clamp( minHeight, expandedHeight, ); final opacity = 1 - currentVisibleHeight / expandedHeight; return Stack( // clipBehavior: Clip.none, children: [ Positioned( top: 0, left: 0, right: 0, child: Image.asset( Assets.images.bgCharacterBoyBanner.path, width: double.infinity, fit: BoxFit.fill, alignment: Alignment.topCenter, ), ), // 遮罩层 Positioned(用于控制背景的可见性) Positioned( top: 0, left: 0, right: 0, height: currentVisibleHeight, child: Opacity(opacity: opacity, child: Container(color: Colors.purple.shade700)), ), Positioned(bottom: 0, left: 0, right: 0, child: bottomWidget), // 我的键盘按钮 myKeyboardButton(onTap: onTap), ], ); } @override double get maxExtent => expandedHeight; @override double get minExtent => minHeight; @override bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) => true; } //我的键盘按钮 Widget myKeyboardButton({required VoidCallback onTap}) { return Positioned( top: 0, child: SafeArea( child: GestureDetector( onTap: onTap, child: Container( margin: EdgeInsets.symmetric(horizontal: 16.w), width: 96.w, height: 32.h, padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4), decoration: ShapeDecoration( color: Colors.white.withValues(alpha: 153), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, spacing: 4.r, children: [ Container( width: 24.r, height: 24.r, clipBehavior: Clip.antiAlias, decoration: BoxDecoration(), child: Assets.images.iconCharacterKeyboard.image( width: 24.r, height: 24.r, ), ), Text( StringName.myKeyboard, textAlign: TextAlign.center, style: TextStyle( color: Colors.black.withAlpha(204), fontSize: 14.sp, fontWeight: FontWeight.w400, ), ), ], ), ), ), ), ); }