提交 9edfad5a authored 作者: yueweilu's avatar yueweilu

图书馆界面

上级 4d5b9597
...@@ -25,6 +25,10 @@ apply plugin: 'com.android.application' ...@@ -25,6 +25,10 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android { android {
namespace "com.zijin.book.flutter_book" namespace "com.zijin.book.flutter_book"
compileSdkVersion flutter.compileSdkVersion compileSdkVersion flutter.compileSdkVersion
...@@ -45,13 +49,38 @@ android { ...@@ -45,13 +49,38 @@ android {
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
} }
signingConfigs {
// release {
// keyAlias keystoreProperties['keyAlias']
// keyPassword keystoreProperties['keyPassword']
// storeFile file(keystoreProperties['storeFile'])
// storePassword keystoreProperties['storePassword']
// }
release{
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
debug{
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
buildTypes { buildTypes {
debug {
signingConfig signingConfigs.release
}
release { release {
// TODO: Add your own signing config for the release build. // TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works. // Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug signingConfig signingConfigs.release
} }
} }
} }
......
part of library; part of library;
class LibraryController extends GetxController with GetSingleTickerProviderStateMixin{
late TabController tabController = TabController(length:7, vsync: this);
@override
void onInit() {
super.onInit();
}
}
\ No newline at end of file
library library; library library;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_book/theme.dart';
import 'package:flutter_book/utils/index.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:ionicons/ionicons.dart'; import 'package:ionicons/ionicons.dart';
import '../../widgets/index.dart';
import '../course/index.dart';
import '../study/index.dart'; import '../study/index.dart';
...@@ -11,3 +16,5 @@ import '../study/index.dart'; ...@@ -11,3 +16,5 @@ import '../study/index.dart';
part 'view.dart'; part 'view.dart';
part 'controller.dart'; part 'controller.dart';
part 'widgets/cell.dart'; part 'widgets/cell.dart';
part 'widgets/content.dart';
part 'widgets/subject.dart';
\ No newline at end of file
...@@ -9,145 +9,78 @@ class LibraryPage extends StatefulWidget { ...@@ -9,145 +9,78 @@ class LibraryPage extends StatefulWidget {
class _LibraryPageState extends State<LibraryPage> with AutomaticKeepAliveClientMixin,SingleTickerProviderStateMixin{ class _LibraryPageState extends State<LibraryPage> with AutomaticKeepAliveClientMixin,SingleTickerProviderStateMixin{
List<String> _tabTag = ['全部','职业证书','人文艺术','财经管理'];
List<Tab> get _tabs {
return _tabTag.map<Tab>((item) => Tab(text: item,)).toList();
}
@override
void initState() {
_tabController = TabController(length:4, vsync: this);
super.initState();
}
late TabController _tabController;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return GetBuilder<LibraryController>(
init: LibraryController(),
builder: (controller) => Scaffold(
appBar: AppBar( appBar: AppBar(
title: Container( title: const Text('图书馆'),
color: Colors.limeAccent,
height: 40,
),
// leading: TextField(
//
// style: TextStyle(
// color: Colors.cyan
// ),
// decoration: InputDecoration(
// hintText: '请输入手机号',
// prefixIcon: Icon(Icons.search),
// border:InputBorder.none,
// enabledBorder: InputBorder.none,
// focusedBorder: InputBorder.none
// // contentPadding: EdgeInsets.symmetric(vertical: 16.0),
// ),
// ),
actions: [ actions: [
IconButton( IconButton(
color: Colors.cyan, icon: const Icon(Icons.search_rounded),
icon: const Icon(Icons.message),
tooltip: 'Open shopping cart',
onPressed: () {
},
),
IconButton(
color: Colors.cyan,
icon: const Icon(Icons.refresh),
tooltip: 'Open shopping cart',
onPressed: () {
},
),
],
),
body: Container(
margin: EdgeInsets.all(10),
child: SingleChildScrollView(
child: Column(
children: [
Container(
color: Colors.cyan,
height: 150,
margin: EdgeInsets.only(bottom: 10),
),
HomeCard(title: '人气推荐1',),
HomeCard(title: '人气推荐2',),
HomeCard(title: '人气推荐3',),
HomeCard(title: '人气推荐4',)
],
)
),
),
);
}
/// 列表
Widget createListView(){
return ListView.builder(
itemBuilder: (BuildContext context, int index){
return LibraryCell();
},
itemCount: 2,
);
}
/// 分类
Widget scaffold (){
return Scaffold(
appBar: AppBar(
title: const Text('图书馆',style: TextStyle(
color: Colors.white
),),
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0xFFEE5982),Color(0xFFAB1941)]
)
),
),
actions: [
IconButton(
color: Colors.white,
icon: const Icon(Icons.search),
tooltip: 'Open shopping cart', tooltip: 'Open shopping cart',
onPressed: () { onPressed: () {
}, },
), ),
], ],
bottom: PreferredSize( bottom: PreferredSize(
preferredSize: Size.fromHeight(48), preferredSize: Size.fromHeight(38),
child: Container( child: Container(
color: Colors.white, color: Colors.white,
width: double.infinity, width: double.infinity,
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 0.5,color: Colours.cE5)
),
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
child: TabBar( child: TabBar(
indicator: BoxDecoration( indicator: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.transparent, width: 0.0)), // 将指示器的底边框颜色设置为透明 border: Border(bottom: BorderSide(color: Colors.transparent, width: 0.0)), // 将指示器的底边框颜色设置为透明
color: Colors.lightBlue color: Color(0xFFC0D55).withOpacity(0.08)
), ),
unselectedLabelColor: Colors.grey, labelStyle: TextStyle(color: AppTheme.primary,fontSize: 14,height: 1.5,fontWeight: Fonts.medium),
controller: _tabController, unselectedLabelColor: Colours.c9,
// isScrollable: true, unselectedLabelStyle: TextStyle(color: Colours.c9,fontSize: 14,height: 1.5),
controller: controller.tabController,
isScrollable: true,
tabs: [ tabs: [
Tab(text: '全部'), Tab(text: '全部'),
Tab(text: '职业证书'), Tab(text: '职业证书'),
Tab(text: '人文艺术'), Tab(text: '人文艺术'),
Tab(text: '财经管理'), Tab(text: '财经管理'),
// Tab(text: '待评价'), Tab(text: '待评价'),
// Tab(text: '待评价1'), Tab(text: '待评价1'),
// Tab(text: '待评价2'), Tab(text: '待评价2'),
], ],
), ),
), ),
GestureDetector( GestureDetector(
child: Container( child: Container(
child: Text('分类'), padding: const EdgeInsets.symmetric(horizontal: 10),
alignment: Alignment.center,
// color: Colors.cyan,
height: 38,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 12,
height: 12,
// color: Colors.red,
alignment: Alignment.center,
child: Image.asset(
'assets/images/filter.png',
),
),
Gaps.hGaps5,
const Text('筛选',style: TextStyle(color: Colours.c9,fontSize: 14,height: 1.5),)
],
),
// width: 75,
), ),
) )
], ],
...@@ -155,24 +88,28 @@ class _LibraryPageState extends State<LibraryPage> with AutomaticKeepAliveClient ...@@ -155,24 +88,28 @@ class _LibraryPageState extends State<LibraryPage> with AutomaticKeepAliveClient
), ),
), ),
), ),
),
body: TabBarView( body: TabBarView(
controller: _tabController, controller: controller.tabController,
children: [ children: List.generate(7, (index){
// 第一个分类的内容 return LibraryContentPage();
LibraryCell(), })
// 第二个分类的内容 ),
Center(child: Text('分类2内容')),
// 第三个分类的内容
Center(child: Text('分类3内容')),
Center(child: Text('分类4内容')),
// Center(child: Text('分类5内容')),
// Center(child: Text('分类5内容')),
// Center(child: Text('分类5内容')),
],
), ),
); );
} }
/// 列表
Widget createListView(){
return ListView.builder(
itemBuilder: (BuildContext context, int index){
return LibraryCell();
},
itemCount: 2,
);
}
@override @override
// TODO: implement wantKeepAlive // TODO: implement wantKeepAlive
bool get wantKeepAlive => true; bool get wantKeepAlive => true;
......
...@@ -11,14 +11,19 @@ class _LibraryCellState extends State<LibraryCell> { ...@@ -11,14 +11,19 @@ class _LibraryCellState extends State<LibraryCell> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
padding: EdgeInsets.only(left: 10,top: 20,bottom: 20), padding: const EdgeInsets.only(top: 10),
margin: EdgeInsets.only(top:10,left: 10,right: 10), // color: Colors.red,
child: Stack(
children: [
Container(
padding: EdgeInsets.only(left: 10,top: 10,bottom: 20),
margin: EdgeInsets.only(top:15,left: 10,right: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(8),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.grey.withOpacity(0.5), // 阴影颜色 color: Colours.cC7.withOpacity(0.5), // 阴影颜色
spreadRadius: 2, // 阴影扩散半径 spreadRadius: 2, // 阴影扩散半径
blurRadius: 5, // 阴影模糊半径 blurRadius: 5, // 阴影模糊半径
offset: Offset(0, 2), // 阴影偏移 offset: Offset(0, 2), // 阴影偏移
...@@ -32,9 +37,9 @@ class _LibraryCellState extends State<LibraryCell> { ...@@ -32,9 +37,9 @@ class _LibraryCellState extends State<LibraryCell> {
children: [ children: [
/// 左侧 /// 左侧
Container( Container(
width: 60, width: 100,
height: 80, height: 105,
color: Colors.cyan, color: Colors.red,
), ),
/// 右侧 /// 右侧
Expanded( Expanded(
...@@ -43,26 +48,41 @@ class _LibraryCellState extends State<LibraryCell> { ...@@ -43,26 +48,41 @@ class _LibraryCellState extends State<LibraryCell> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 10,), // SizedBox(height: 10,),
Text('标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题',overflow: TextOverflow.ellipsis,maxLines: 1,), Text('标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题',overflow: TextOverflow.ellipsis,maxLines: 2,style: TextStyle(fontSize: 14,fontWeight: Fonts.medium,height: 1.5,color: Colours.c3),),
SizedBox(height: 10,), SizedBox(height: 4,),
Text('描述描述描述描述描述描述描述描述描述'), Text('威廉·莎士比亚',style: TextStyle(fontSize: 11,color: Colours.c9,height: 1.5),),
Gaps.vGaps15,
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Row( Row(
children: [ children: [
Text('88'), Text('¥88',style: TextStyle(fontSize: 14,height: 1.5,color: AppTheme.primary,fontWeight: Fonts.medium),),
SizedBox(width: 10,), SizedBox(width: 10,),
Text('108',style: TextStyle( Text('108',style: TextStyle(
decoration: TextDecoration.combine([ decoration: TextDecoration.combine([
TextDecoration.lineThrough TextDecoration.lineThrough
]), ]),
decorationColor: Colors.red decorationColor: Colors.red,fontSize: 12,height: 1.5,color: Colours.c9
),), ),),
], ],
), ),
Text('103万人读过') Row(
children: [
Text('103万人读过',style:TextStyle(fontSize: 11,height: 1.5,color: Colours.cC7)),
Gaps.hGaps5,
Container(
width: 20,
height: 20,
// color: Colors.yellow,
child: Image.asset(
'assets/images/unlove.png',
),
)
],
)
], ],
) )
], ],
...@@ -71,6 +91,22 @@ class _LibraryCellState extends State<LibraryCell> { ...@@ -71,6 +91,22 @@ class _LibraryCellState extends State<LibraryCell> {
) )
], ],
), ),
),
Positioned(
left: 20,
top: 0,
bottom: 18,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
color: Colors.cyan,
),
width: 100,
),
),
],
)
); );
} }
} }
part of library;
class LibraryContentPage extends StatefulWidget {
const LibraryContentPage({Key? key}) : super(key: key);
@override
State<LibraryContentPage> createState() => _LibraryContentPageState();
}
class _LibraryContentPageState extends State<LibraryContentPage> {
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
height: 43,
// color: Colors.green,
child: ListView.builder(
scrollDirection:Axis.horizontal ,
itemBuilder: (BuildContext context, int index){
return GestureDetector(
child: BookLibrarySubjectTypeWidget(),
onTap: (){
},
);
},
itemCount: 10,
),
),
Expanded(
child: NestedScrollView(
headerSliverBuilder: (BuildContext context ,bool innerBoxIsScrolled){
return [
SliverList(
delegate: SliverChildListDelegate([
Container(
color: Colors.transparent,
padding: const EdgeInsets.symmetric(horizontal: 10),
child: const BuildBanner(items: ['111','222','333'],),
),
])
)
];
},
body: ListView.builder(
itemCount: 50,
itemBuilder: (BuildContext context, int index) {
return LibraryCell();
},
),
),
),
],
);
}
}
part of library;
class BookLibrarySubjectTypeWidget extends StatefulWidget {
const BookLibrarySubjectTypeWidget({super.key});
// late BookSubjectTypeEntity model;
@override
_BookLibrarySubjectTypeWidgetState createState() => _BookLibrarySubjectTypeWidgetState();
// BookLibrarySubjectTypeWidget(this.model);
}
class _BookLibrarySubjectTypeWidgetState extends State<BookLibrarySubjectTypeWidget> {
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(left: 10),
color: Colors.white,
width: 65,
padding: const EdgeInsets.only(top: 10,bottom: 10),
child: Container(
// padding: EdgeInsets.all(8),
alignment: Alignment.center,
padding: EdgeInsets.only(left: 8,right:8 ),
height: 23,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(12.5)),
border: Border.all(color:AppTheme.primary,width: 0.5,style: BorderStyle.solid),
// color: widget.model.selected == true?Colours.book_app_main:Colors.white,
),
child: Text('最新',style: TextStyle(fontSize: 13,height: 1.5,color: AppTheme.primary,fontWeight: Fonts.medium),)
),
);
}
}
...@@ -19,7 +19,14 @@ class _LoginPageState extends State<LoginPage> { ...@@ -19,7 +19,14 @@ class _LoginPageState extends State<LoginPage> {
init: LoginController(), init: LoginController(),
builder:(controller) => GestureDetector( builder:(controller) => GestureDetector(
onTap: () => Tools.unfocus(), onTap: () => Tools.unfocus(),
child: Container( child: Scaffold(
appBar: CustomAppBar(
systemOverlayStyle: Theme.of(context).brightness == Brightness.light
? SystemUiOverlayStyle.dark
: SystemUiOverlayStyle.light,
backgroundColor: Colors.transparent,
),
body: Container(
color: Colors.white, color: Colors.white,
child: Stack( child: Stack(
children: [ children: [
...@@ -200,6 +207,7 @@ class _LoginPageState extends State<LoginPage> { ...@@ -200,6 +207,7 @@ class _LoginPageState extends State<LoginPage> {
), ),
], ],
), ),
),
) )
), ),
); );
......
...@@ -5,7 +5,7 @@ class MainController extends GetxController { ...@@ -5,7 +5,7 @@ class MainController extends GetxController {
late final PageController pageController; late final PageController pageController;
//默认显示 //默认显示
int currentPage = 0; int currentPage = 1;
@override @override
void onInit() { void onInit() {
......
...@@ -50,11 +50,12 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver{ ...@@ -50,11 +50,12 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver{
builder: (controller) => BottomNavigationBar( builder: (controller) => BottomNavigationBar(
currentIndex:controller.currentPage , currentIndex:controller.currentPage ,
onTap: (page){ onTap: (page){
if (page != 0 && !UserStore.to.isLogin) { // if (page != 1 && !UserStore.to.isLogin) {
context.pushNamed(Routes.login); // context.pushNamed(Routes.login);
} else { // } else {
// controller.pageController.jumpToPage(page);
// }
controller.pageController.jumpToPage(page); controller.pageController.jumpToPage(page);
}
}, },
items: [ items: [
BottomNavigationBarItem( BottomNavigationBarItem(
......
...@@ -13,7 +13,7 @@ class TermsPage extends StatelessWidget { ...@@ -13,7 +13,7 @@ class TermsPage extends StatelessWidget {
), ),
body: InAppWebView( body: InAppWebView(
initialUrlRequest: URLRequest( initialUrlRequest: URLRequest(
url: Uri.parse('http://192.168.11.39:5500/'), url: Uri.parse('https://www.baidu.com/'),
), ),
) )
); );
......
...@@ -24,6 +24,7 @@ class Colours { ...@@ -24,6 +24,7 @@ class Colours {
static const cLine = Color(0xFFF0F0F0); static const cLine = Color(0xFFF0F0F0);
static const cBlue = Color(0xFF2A82D9); static const cBlue = Color(0xFF2A82D9);
static const cE2 = Color(0xFFE2E2E2); static const cE2 = Color(0xFFE2E2E2);
static const cE5 = Color(0xFFE5E5E5);
static const cF2 = Color(0xFFF2F2F2); static const cF2 = Color(0xFFF2F2F2);
static const cF9 = Color(0xFFF9F9F9); static const cF9 = Color(0xFFF9F9F9);
static const cC7 = Color(0xFFC7C7C7); static const cC7 = Color(0xFFC7C7C7);
......
...@@ -23,3 +23,4 @@ part 'app_bar.dart'; ...@@ -23,3 +23,4 @@ part 'app_bar.dart';
part 'input.dart'; part 'input.dart';
part 'button.dart'; part 'button.dart';
part 'pull_scroll_view.dart'; part 'pull_scroll_view.dart';
part 'tab_bar.dart';
\ No newline at end of file
part of widgets;
final double _kTabHeight = 38.w;
class CustomTabBar extends StatefulWidget implements PreferredSizeWidget {
final bool isScrollable;
final List<Tab> tabs;
final TabController? controller;
final void Function(int index)? onTap;
const CustomTabBar({
Key? key,
required this.tabs,
this.controller,
this.onTap,
this.isScrollable = true,
}) : super(key: key);
@override
Size get preferredSize => Size.fromHeight(_kTabHeight);
@override
State<CustomTabBar> createState() => _CustomTabBarState();
}
class _CustomTabBarState extends State<CustomTabBar>
with TickerProviderStateMixin {
final _duration = 250;
final GlobalKey _tabsContainerKey = GlobalKey();
final GlobalKey _tabsParentKey = GlobalKey();
final ScrollController _scrollController = ScrollController();
late AnimationController _animationController;
late List<GlobalKey> _tabKeys;
TabController? _controller;
int _currentIndex = 0;
int _prevIndex = -1;
int _aniIndex = 0;
double _prevAniValue = 0;
late bool _textLTR;
@override
void initState() {
super.initState();
_tabKeys = widget.tabs.map<GlobalKey>((item) => GlobalKey()).toList();
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: _duration),
);
_animationController.value = 1.0;
_animationController.addListener(() {
setState(() {});
});
}
bool get _controllerIsValid => _controller?.animation != null;
@override
void didChangeDependencies() {
super.didChangeDependencies();
assert(debugCheckHasMaterial(context));
_updateTabController();
}
@override
void didUpdateWidget(CustomTabBar oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.controller != oldWidget.controller) {
_updateTabController();
}
if (widget.tabs.length > oldWidget.tabs.length) {
final int delta = widget.tabs.length - oldWidget.tabs.length;
_tabKeys.addAll(List<GlobalKey>.generate(delta, (int n) => GlobalKey()));
} else if (widget.tabs.length < oldWidget.tabs.length) {
_tabKeys.removeRange(widget.tabs.length, oldWidget.tabs.length);
}
}
@override
void dispose() {
if (_controllerIsValid) {
_controller!.animation!.removeListener(_handleTabAnimation);
_controller!.removeListener(_handleController);
}
_controller = null;
_scrollController.dispose();
super.dispose();
}
void _updateTabController() {
final TabController newController =
widget.controller ?? DefaultTabController.of(context);
if (newController == _controller) return;
if (_controllerIsValid) {
_controller?.animation!.removeListener(_handleTabAnimation);
_controller?.removeListener(_handleController);
}
_controller = newController;
_controller?.animation!.addListener(_handleTabAnimation);
_controller?.addListener(_handleController);
_currentIndex = _controller!.index;
}
void _handleController() {
if (_controller!.indexIsChanging) _goToIndex(_controller!.index);
}
Widget _buildTabItem(int index, Tab tab) {
final tabBarTheme = TabBarTheme.of(context);
var animationValue = 0.0;
if (index == _currentIndex) {
animationValue = _animationController.value;
} else if (index == _prevIndex) {
animationValue = 1 - _animationController.value;
} else {
animationValue = 0;
}
final textStyle = TextStyle.lerp(
tabBarTheme.unselectedLabelStyle,
tabBarTheme.labelStyle,
animationValue,
);
final borderColor =
tabBarTheme.labelColor ?? Theme.of(context).colorScheme.primary;
// final boxDecoration = ShapeDecoration.lerp(
// ShapeDecoration(
// color: tabBarTheme.unselectedLabelColor ??
// Theme.of(context).colorScheme.surface,
// shape: StadiumBorder(side: BorderSide(color: borderColor, width: 2.w)),
// ),
// ShapeDecoration(
// color: tabBarTheme.labelColor ?? Theme.of(context).colorScheme.primary,
// shape: StadiumBorder(side: BorderSide(color: borderColor, width: 2.w)),
// ),
// animationValue,
// );
return GestureDetector(
key: _tabKeys[index],
onTap: () {
_controller?.animateTo(index);
widget.onTap?.call(index);
},
child: Container(
color: Colors.cyan,
// margin: EdgeInsets.symmetric(
// horizontal: (tabBarTheme.labelPadding?.horizontal ?? 0) / 2,
// ).copyWith(
// left: index == 0 ? 0 : null,
// right: index == widget.tabs.length - 1 ? 0 : null,
// ),
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: 16.w),
// decoration: boxDecoration,
child: DefaultTextStyle.merge(
style: textStyle,
child: Text(tab.text ?? ''),
),
),
);
}
@override
Widget build(BuildContext context) {
assert(() {
if (_controller!.length != widget.tabs.length) {
throw FlutterError(
"Controller's length property (${_controller!.length}) does not match the "
"number of tabs (${widget.tabs.length}) present in TabBar's tabs property.");
}
return true;
}());
if (_controller!.length == 0) return Container(height: _kTabHeight);
_textLTR = Directionality.of(context).index == 1;
Widget tabsChild = SafeArea(
top: false,
bottom: false,
minimum: const EdgeInsets.symmetric(horizontal: AppTheme.margin),
child: Row(
mainAxisSize: MainAxisSize.min,
children: List.generate(widget.tabs.length, (index) {
var item = _buildTabItem(index, widget.tabs[index]);
if (!widget.isScrollable) item = Expanded(child: item);
return item;
}),
),
);
if (widget.isScrollable) {
tabsChild = SingleChildScrollView(
physics: const BouncingScrollPhysics(),
controller: _scrollController,
scrollDirection: Axis.horizontal,
child: tabsChild,
);
}
return AnimatedBuilder(
animation: _animationController,
key: _tabsParentKey,
builder: (context, child) => SizedBox(
key: _tabsContainerKey,
height: widget.preferredSize.height,
child: child,
),
child: tabsChild,
);
}
_handleTabAnimation() {
_aniIndex = ((_controller!.animation!.value > _prevAniValue)
? _controller!.animation!.value
: _prevAniValue)
.round();
if (!_controller!.indexIsChanging && _aniIndex != _currentIndex) {
_setCurrentIndex(_aniIndex);
}
_prevAniValue = _controller!.animation!.value;
}
_goToIndex(int index) {
if (index != _currentIndex) {
_setCurrentIndex(index);
_controller?.animateTo(index);
}
}
_setCurrentIndex(int index) {
setState(() {
_prevIndex = _currentIndex;
_currentIndex = index;
});
_scrollTo(index);
_triggerAnimation();
}
_triggerAnimation() {
_animationController.reset();
_animationController.forward();
}
_scrollTo(int index) {
if (!widget.isScrollable) return;
final RenderBox tabsContainer =
_tabsContainerKey.currentContext!.findRenderObject() as RenderBox;
final tabsContainerPosition = tabsContainer.localToGlobal(Offset.zero).dx;
final tabsContainerOffset = Offset(-tabsContainerPosition, 0);
double screenWidth = tabsContainer.size.width;
RenderBox renderBox =
_tabKeys[index].currentContext?.findRenderObject() as RenderBox;
double size = renderBox.size.width;
double position = renderBox.localToGlobal(tabsContainerOffset).dx;
double offset = (position + size / 2) - screenWidth / 2;
if (offset < 0) {
renderBox = (_textLTR ? _tabKeys.first : _tabKeys.last)
.currentContext
?.findRenderObject() as RenderBox;
position = renderBox.localToGlobal(tabsContainerOffset).dx;
if (position > offset) offset = position - AppTheme.margin;
} else {
renderBox = (_textLTR ? _tabKeys.last : _tabKeys.first)
.currentContext
?.findRenderObject() as RenderBox;
position = renderBox.localToGlobal(tabsContainerOffset).dx;
size = renderBox.size.width;
if (position + size < screenWidth) screenWidth = position + size;
if (position + size - offset < screenWidth) {
offset = position + size - screenWidth;
if (offset > 0) offset += AppTheme.margin;
}
}
offset *= (_textLTR ? 1 : -1);
_scrollController.animateTo(
offset + _scrollController.offset,
duration: Duration(milliseconds: _duration),
curve: Curves.easeInOut,
);
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论