Commit 5f42161c authored by “Icebear”'s avatar “Icebear”

添加TabBar标签栏页面,自定义PageController

parent 83ca9b54
...@@ -19,5 +19,5 @@ class Images{ ...@@ -19,5 +19,5 @@ class Images{
static const ic_sign = "${imagesPath}ic_sign.png"; static const ic_sign = "${imagesPath}ic_sign.png";
static const ic_back_black = "${imagesPath}ic_back_black.png"; static const ic_back_black = "${imagesPath}ic_back_black.png";
static const ic_login_button = "${imagesPath}login_button.png"; static const ic_login_button = "${imagesPath}login_button.png";
static const ic_doctor_avatar = "${imagesPath}ic_doctor_avatar.png";
} }
\ No newline at end of file
...@@ -3,7 +3,6 @@ import 'package:fluttertoast/fluttertoast.dart'; ...@@ -3,7 +3,6 @@ import 'package:fluttertoast/fluttertoast.dart';
import 'package:netrain_flutter_app/xuehao/car_details.dart'; import 'package:netrain_flutter_app/xuehao/car_details.dart';
import 'package:netrain_flutter_app/common/AppColors.dart'; import 'package:netrain_flutter_app/common/AppColors.dart';
import 'package:netrain_flutter_app/xuehao/list_page.dart'; import 'package:netrain_flutter_app/xuehao/list_page.dart';
import 'package:netrain_flutter_app/zhangfeng/TestPage.dart';
import 'laishanqi/Stateful_page.dart'; import 'laishanqi/Stateful_page.dart';
import 'laishanqi/Stateless_page.dart'; import 'laishanqi/Stateless_page.dart';
...@@ -12,10 +11,14 @@ import 'laishanqi/netrain/user/loginPage.dart'; ...@@ -12,10 +11,14 @@ import 'laishanqi/netrain/user/loginPage.dart';
import 'laishanqi/netrain/user/RegisterPage.dart'; import 'laishanqi/netrain/user/RegisterPage.dart';
import 'laishanqi/photo.dart'; import 'laishanqi/photo.dart';
import 'zhangfeng/UserModel.dart'; import 'zhangfeng/UserModel.dart';
import 'zhangfeng/LoginPage.dart';
import 'zhangfeng/CustomTabPage.dart';
import 'zhangfeng/TestPage.dart';
import 'zhangfeng/TabBarPage.dart';
import 'jishuaishuai/student.dart'; import 'jishuaishuai/student.dart';
import 'zhangfeng/LoginPage.dart';
void main() { void main() {
runApp(MyApp()); runApp(MyApp());
...@@ -49,8 +52,9 @@ class MyApp extends StatelessWidget { ...@@ -49,8 +52,9 @@ class MyApp extends StatelessWidget {
"register": (context) => RegisterPage(), "register": (context) => RegisterPage(),
"login": (context) => LoginPage(), "login": (context) => LoginPage(),
"listPage":(context) => List_Page(), "listPage":(context) => List_Page(),
"CustomTabPage":(context) => TabBarPage(),
"LoginRequestPage":(context) => LoginRequestPage(), "LoginRequestPage":(context) => LoginRequestPage(),
"TestPage": (context) => SampleAppPage(), "PageView":(context) => SampleAppPage(),
"main": (context) => mainPage(), "main": (context) => mainPage(),
"student":(context) => jssPageDemo(), "student":(context) => jssPageDemo(),
"car_details":(context) =>CarDetailsPage() "car_details":(context) =>CarDetailsPage()
...@@ -103,7 +107,8 @@ class _RouterNavigatorState extends State<RouterNavigator> { ...@@ -103,7 +107,8 @@ class _RouterNavigatorState extends State<RouterNavigator> {
_item("拍照页面", PhotoApp(), 'photo'), _item("拍照页面", PhotoApp(), 'photo'),
_item("登陆", LoginPage(), 'login'), _item("登陆", LoginPage(), 'login'),
_item("登录网络请求", LoginRequestPage(), 'LoginRequestPage'), _item("登录网络请求", LoginRequestPage(), 'LoginRequestPage'),
_item("zhangfengTest页面",List_Page(),'TestPage'), _item("CustomTabPage",TabBarPage(),'CustomTabPage'),
_item("PageView",SampleAppPage(),'PageView'),
_item("listview页面",List_Page(),'listPage'), _item("listview页面",List_Page(),'listPage'),
_item("jssDemo", jssPageDemo(), 'student') _item("jssDemo", jssPageDemo(), 'student')
], ],
......
import 'package:flutter/material.dart';
import 'package:netrain_flutter_app/common/Images.dart';
import 'CustomUnderlineTabIndicator.dart';
class CustomTabPage extends StatefulWidget{
@override
_CustomTabPageState createState() => _CustomTabPageState();
}
class _CustomTabPageState extends State<CustomTabPage> with TickerProviderStateMixin{
TabController _tabController;
PageController _pageController;
List<String> _titleList = <String>['关注','推荐', '抗疫', '热榜', '精品课', '旅游'];
List widgets = [];
@override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: _titleList.length);
_pageController = PageController();
for (int i = 0; i < 10; i++) {
widgets.add(getRow(i));
}
}
void _changeTab(int index) {
_pageController.animateToPage(index, duration: Duration(milliseconds: 300), curve: Curves.ease);
}
void _onPageChanged(int index) {
_tabController.animateTo(index, duration: Duration(milliseconds: 300));
}
@override
void dispose() {
_pageController.dispose();
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('自定义PageController', style: TextStyle(color: Colors.black54),),
backgroundColor: Colors.white,
brightness: Brightness.light,
elevation: 0,
iconTheme: IconThemeData(
color: Colors.black54
),
),
body: Column(
children: <Widget>[
Container(
width: double.infinity,
color: Colors.white,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 5),
height: 45,
child: TabBar(
labelColor: Colors.blue,
//选中的颜色
labelStyle: TextStyle(color: Colors.white, fontSize: 14),
unselectedLabelColor: Colors.black54,
//未选中的颜色
unselectedLabelStyle: TextStyle(
color: Colors.black54, fontSize: 14),
isScrollable: true,
//自定义indicator样式
indicator: CustomUnderlineTabIndicator(
borderSide: BorderSide(color: Colors.blue,width: 3),
insets: EdgeInsets.only(left: 50,right: 50,top: 0,bottom: -5),
),
controller: _tabController,
onTap: _changeTab,
tabs: _titleList.map((e) => Tab(text: e)).toList(),
),
),
Expanded(
child: PageView.builder(
physics: BouncingScrollPhysics(),
controller: _pageController,
onPageChanged: _onPageChanged,
itemCount: _titleList.length,
itemBuilder: (context, index) {
return PageItemView(index);
}
)
)
],
),
);
}
PageItemView(int index) {
return ListView.builder(
itemCount: widgets.length,
itemBuilder: (BuildContext context, int position) {
return getRow(position);
},
);
}
Widget getRow(int i) {
return GestureDetector(
child: Container(
padding: EdgeInsets.all(16),
child: Row(
children: [
Container(
child: Image(image: AssetImage(Images.ic_doctor_avatar)),
padding: EdgeInsets.only(right: 10),
),
Text("患者 $i"),
],
),
),
onTap: () {
setState(() {
widgets.add(getRow(widgets.length + 1));
print('row $i');
});
},
);
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
///下划线两端圆角的实现,参考UnderlineTabIndicator,修改StrokeCap.square 为 StrokeCap.round
class CustomUnderlineTabIndicator extends Decoration {
/// Create an underline style selected tab indicator.
///
/// The [borderSide] and [insets] arguments must not be null.
const CustomUnderlineTabIndicator({
this.borderSide = const BorderSide(width: 2.0, color: Colors.white),
this.insets = EdgeInsets.zero,
})
: assert(borderSide != null),
assert(insets != null);
/// The color and weight of the horizontal line drawn below the selected tab.
final BorderSide borderSide;
/// Locates the selected tab's underline relative to the tab's boundary.
///
/// The [TabBar.indicatorSize] property can be used to define the
/// tab indicator's bounds in terms of its (centered) tab widget with
/// [TabIndicatorSize.label], or the entire tab with [TabIndicatorSize.tab].
final EdgeInsetsGeometry insets;
@override
Decoration lerpFrom(Decoration a, double t) {
if (a is UnderlineTabIndicator) {
return CustomUnderlineTabIndicator(
borderSide: BorderSide.lerp(a.borderSide, borderSide, t),
insets: EdgeInsetsGeometry.lerp(a.insets, insets, t),
);
}
return super.lerpFrom(a, t);
}
@override
Decoration lerpTo(Decoration b, double t) {
if (b is UnderlineTabIndicator) {
return CustomUnderlineTabIndicator(
borderSide: BorderSide.lerp(borderSide, b.borderSide, t),
insets: EdgeInsetsGeometry.lerp(insets, b.insets, t),
);
}
return super.lerpTo(b, t);
}
@override
_UnderlinePainter createBoxPainter([VoidCallback onChanged]) {
return _UnderlinePainter(this, onChanged);
}
}
class _UnderlinePainter extends BoxPainter {
_UnderlinePainter(this.decoration, VoidCallback onChanged)
: assert(decoration != null),
super(onChanged);
final CustomUnderlineTabIndicator decoration;
BorderSide get borderSide => decoration.borderSide;
EdgeInsetsGeometry get insets => decoration.insets;
Rect _indicatorRectFor(Rect rect, TextDirection textDirection) {
assert(rect != null);
assert(textDirection != null);
final Rect indicator = insets.resolve(textDirection).deflateRect(rect);
return Rect.fromLTWH(
indicator.left,
indicator.bottom - borderSide.width,
indicator.width,
borderSide.width,
);
}
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
assert(configuration != null);
assert(configuration.size != null);
final Rect rect = offset & configuration.size;
final TextDirection textDirection = configuration.textDirection;
final Rect indicator = _indicatorRectFor(rect, textDirection).deflate(decoration.borderSide.width / 2.0);
final Paint paint = decoration.borderSide.toPaint()..strokeCap = StrokeCap.square;
canvas.drawLine(indicator.bottomLeft, indicator.bottomRight, paint);
}
}
\ No newline at end of file
...@@ -79,13 +79,37 @@ class _LoginState extends State<LoginRequestPage> { ...@@ -79,13 +79,37 @@ class _LoginState extends State<LoginRequestPage> {
controller: pwdTextField, controller: pwdTextField,
decoration: InputDecoration(hintText: "请输入密码",border: OutlineInputBorder( decoration: InputDecoration(hintText: "请输入密码",border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0), borderRadius: BorderRadius.circular(30.0),
borderSide: BorderSide()),), borderSide: BorderSide()),
suffixIcon: IconButton(
icon: Icon(
Icons.clear,
color: Colors.black45,
),
onPressed: (){
pwdTextField.clear();
},
)
),
obscureText: true, //是否是密码
), ),
), ),
Container( Container(
padding: EdgeInsets.only(top: 50,left: 16,right: 16), padding: EdgeInsets.only(top: 50,left: 0,right: 0),
decoration: BoxDecoration( child: TextButton(
image: DecorationImage(image: AssetImage(Images.ic_login_button))), child: Stack(
alignment: const Alignment(0.0, 0.0),
children: [
Image.asset(Images.ic_login_button),
Text("登录",style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
)),
],
),
onPressed: _loginAction,
),
), ),
], ],
), ),
......
import 'dart:math';
import 'package:flutter/material.dart';
class ACETabBarIndicator extends Decoration {
// 指示器类型
final ACETabBarIndicatorType type;
// 指示器高度
final double height;
// 定长下划线类型时 指示器宽度
final double lineWidth;
// 指示器颜色
final Color color;
ACETabBarIndicator({this.type, this.height, this.lineWidth, this.color});
@override
BoxPainter createBoxPainter([onChanged]) => _ACETabBarIndicatorPainter(
this, type, height, lineWidth, color, onChanged);
}
class _ACETabBarIndicatorPainter extends BoxPainter {
final ACETabBarIndicator decoration;
ACETabBarIndicatorType type;
double height, lineWidth;
Color color;
_ACETabBarIndicatorPainter(this.decoration, this.type, this.height,
this.lineWidth, this.color, VoidCallback onChanged);
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
Paint _paint = Paint()
..color = color ?? _kIndicatorColor
..style = PaintingStyle.fill
..strokeCap = StrokeCap.round;
double _height = height ?? _kIndicatorHeight;
double _width = lineWidth ?? _kIndicatorWidth;
// final Rect rect = offset & configuration.size;
switch (type) {
case ACETabBarIndicatorType.circle:
canvas.drawCircle(
Offset(offset.dx + (configuration.size.width) / 2,
configuration.size.height - _height),
_height,
_paint);
break;
case ACETabBarIndicatorType.triangle:
if (_height > configuration.size.height) _height = _kIndicatorHeight;
Path _path = Path()
..moveTo(offset.dx + (configuration.size.width) / 2 - _height,
configuration.size.height)
..lineTo(
_height * tan(pi / 6) +
offset.dx +
(configuration.size.width - _height) / 2,
configuration.size.height - _height)
..lineTo(
_height * tan(pi / 6) +
offset.dx +
(configuration.size.width + _height) / 2,
configuration.size.height);
canvas.drawPath(_path, _paint);
break;
case ACETabBarIndicatorType.rrect:
canvas.drawRRect(
RRect.fromRectAndRadius(
Rect.fromLTWH(offset.dx, offset.dy, configuration.size.width,
configuration.size.height),
Radius.circular(_kIndicatorAngle)),
_paint);
break;
case ACETabBarIndicatorType.rrect_inner:
canvas.drawRRect(
RRect.fromRectAndRadius(
Rect.fromLTWH(
offset.dx + height,
height - 1,
configuration.size.width - height * 2,
configuration.size.height - height * 2 - 2),
Radius.circular(_kIndicatorAngle)),
_paint);
break;
case ACETabBarIndicatorType.runderline:
canvas.drawLine(
Offset(offset.dx, configuration.size.height - height / 2),
Offset(offset.dx + configuration.size.width,
configuration.size.height - height / 2),
_paint..strokeWidth = height / 2);
break;
case ACETabBarIndicatorType.runderline_fixed:
if (_width > configuration.size.width)
_width = configuration.size.width / 3;
canvas.drawLine(
Offset(offset.dx + (configuration.size.width - _width) / 2,
configuration.size.height - height / 2),
Offset(offset.dx + (configuration.size.width + _width) / 2,
configuration.size.height - height / 2),
_paint..strokeWidth = height / 2);
break;
}
}
}
enum ACETabBarIndicatorType {
circle, // 实心圆点
triangle, // 上三角
rrect, // 圆角矩形(整个 Tab)
rrect_inner, // 圆角矩形(有内边距)
runderline, // 圆角下划线
runderline_fixed // 定长圆角下划线
}
// 指示器高度
const double _kIndicatorHeight = 6.0;
// 指示器宽度度
const double _kIndicatorWidth = 12.0;
// 指示器圆角
const double _kIndicatorAngle = 10.0;
// 指示器颜色
const Color _kIndicatorColor = Colors.redAccent;
\ No newline at end of file
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'TabBarIndicator.dart';
import 'package:netrain_flutter_app/common/Images.dart';
class TabBarPage extends StatefulWidget {
@override
_TabBarPageState createState() => new _TabBarPageState();
}
class _TabBarPageState extends State<TabBarPage>
with SingleTickerProviderStateMixin {
TabController _tabController;
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
void initState() {
super.initState();
_tabController = new TabController(vsync: this, length: 8);
}
@override
Widget build(BuildContext context) => DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
title: Text('TabBar Page'),
bottom: TabBar(
tabs: <Widget>[
Tab(text: '今日爆款'),
Tab(text: '土货生鲜'),
Tab(text: '会员中心'),
Tab(text: '分类')
],
indicatorColor: Colors.black54,
indicatorSize: TabBarIndicatorSize.label,
isScrollable: true,
)),
body: TabBarView(children: <Widget>[
Center(child: PageItemView(0)),
Center(child: PageItemView(1)),
Center(child: PageItemView(2)),
Center(child: PageItemView(3))
])));
PageItemView(int index) {
return ListView.builder(
itemCount: 10,
itemBuilder: (BuildContext context, int position) {
return getRow(position);
},
);
}
Widget getRow(int i) {
return GestureDetector(
child: Container(
padding: EdgeInsets.all(16),
child: Row(
children: [
Container(
child: Image(image: AssetImage(Images.ic_doctor_avatar)),
padding: EdgeInsets.only(right: 10),
),
Text("患者 $i"),
],
),
),
onTap: () {
setState(() {
print('row $i');
});
},
);
}
// _tabBarView() => TabBarView(
// controller: _tabController,
// physics: NeverScrollableScrollPhysics(),
// // dragStartBehavior: DragStartBehavior.down,
// children: <Widget>[
// Center(child: Text('今日爆款')),
// Center(child: Text('土货生鲜')),
// Center(child: Text('会员中心')),
// Center(child: Text('分类')),
// Center(child: Text('今日爆款')),
// Center(child: Text('土货生鲜')),
// Center(child: Text('会员中心')),
// Center(child: Text('分类'))
// ]);
//
// _tabBarTop() => TabBar(tabs: <Widget>[
// Tab(text: '今日爆款'),
// Tab(text: '土货生鲜'),
// Tab(text: '会员中心'),
// Tab(text: '分类'),
// Tab(text: '今日爆款'),
// Tab(text: '土货生鲜'),
// Tab(text: '会员中心'),
// Tab(text: '分类')
// ], controller: _tabController);
//
// _tabBarBottom() => TabBar(
// indicatorColor: Colors.redAccent,
// indicatorWeight: 4,
// indicatorSize: TabBarIndicatorSize.label,
// indicatorPadding: EdgeInsets.all(5),
// labelColor: Colors.redAccent,
// labelStyle: TextStyle(color: Colors.green, fontSize: 16),
// labelPadding: EdgeInsets.all(4),
// unselectedLabelColor: Colors.white,
// unselectedLabelStyle: TextStyle(color: Colors.purpleAccent, fontSize: 14),
// dragStartBehavior: DragStartBehavior.down,
// indicator: ACETabBarIndicator(),
// isScrollable: true,
// tabs: <Widget>[
// Tab(text: '今日爆款'),
// Tab(text: '土货生鲜'),
// Tab(text: '会员中心'),
// Tab(
// child: Text('分类',
// style: TextStyle(color: Colors.black, fontSize: 18))),
// Tab(text: '今日爆款'),
// Tab(text: '土货生鲜'),
// Tab(text: '会员中心'),
// Tab(text: '分类')
// ],
// controller: _tabController);
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment