You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
9.9 KiB
200 lines
9.9 KiB
1 year ago
|
import 'dart:async';
|
||
|
import 'dart:convert';
|
||
|
import 'dart:math';
|
||
|
|
||
|
import 'package:flutter/cupertino.dart';
|
||
|
import 'package:flutter/material.dart';
|
||
|
import 'package:flutter/foundation.dart';
|
||
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||
|
import 'package:medicine_app/request_util.dart';
|
||
|
import 'package:medicine_app/search_page.dart';
|
||
|
import 'package:medicine_app/slide_page_route.dart';
|
||
|
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||
|
|
||
|
import 'medicine_detail_page.dart';
|
||
|
|
||
|
class HomePage extends StatefulWidget {
|
||
|
HomePage({Key? key}) : super(key: key);
|
||
|
|
||
|
@override
|
||
|
_HomePageState createState() => _HomePageState();
|
||
|
}
|
||
|
|
||
|
class _HomePageState extends State<HomePage> {
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
return Scaffold(
|
||
|
appBar: AppBar(
|
||
|
backgroundColor: Theme.of(context).accentColor,
|
||
|
elevation: 2,
|
||
|
shadowColor: Theme.of(context).shadowColor,
|
||
|
toolbarHeight: 50,
|
||
|
title: TextButton(
|
||
|
child: Row(
|
||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||
|
children: [
|
||
|
Icon(
|
||
|
Icons.search_sharp,
|
||
|
size: 17,
|
||
|
),
|
||
|
Text('搜索')
|
||
|
],
|
||
|
),
|
||
|
style: ButtonStyle(
|
||
|
foregroundColor: MaterialStateProperty.all(Colors.grey.shade500),
|
||
|
shadowColor: MaterialStateProperty.all(Colors.transparent),
|
||
|
overlayColor: MaterialStateProperty.all(Colors.transparent),
|
||
|
minimumSize: MaterialStateProperty.all(Size.fromHeight(32)),
|
||
|
backgroundColor: MaterialStateProperty.all(Colors.white24.withOpacity(0.80)),
|
||
|
textStyle: MaterialStateProperty.all(TextStyle(fontSize: 13, letterSpacing: 2)),
|
||
|
shape: MaterialStateProperty.all(
|
||
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)),
|
||
|
),
|
||
|
),
|
||
|
onPressed: () => Navigator.of(context).push(SlidePageRoute(builder: SearchMedicinePage())),
|
||
|
),
|
||
|
),
|
||
|
body: FutureBuilder(future: Future.sync(() {
|
||
|
return Request.getDio().get('/medicine/outlines');
|
||
|
}), builder: (BuildContext context, snapshot) {
|
||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||
|
Map data = json.decode(snapshot.data.toString());
|
||
|
final List<dynamic> medicineList = data['data'];
|
||
|
return ListView.builder(
|
||
|
cacheExtent: 10,
|
||
|
padding: EdgeInsets.only(bottom: 30),
|
||
|
itemCount: medicineList.length + 1,
|
||
|
itemBuilder: (BuildContext context, int index) {
|
||
|
if (index < medicineList.length) {
|
||
|
final Map medicine = medicineList[index];
|
||
|
final List<dynamic> medicineDetails = medicine['details'];
|
||
|
return Card(
|
||
|
color: Colors.grey[10],
|
||
|
shadowColor: Colors.grey[50],
|
||
|
elevation: 0,
|
||
|
shape: RoundedRectangleBorder(
|
||
|
borderRadius: BorderRadius.circular(15),
|
||
|
),
|
||
|
borderOnForeground: false,
|
||
|
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
||
|
// 外边距
|
||
|
child: Container(
|
||
|
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
||
|
height: 250,
|
||
|
child: Column(
|
||
|
children: [
|
||
|
Expanded(
|
||
|
flex: 1,
|
||
|
child: ListTile(
|
||
|
title: Text(
|
||
|
"${medicine['name']}",
|
||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||
|
)),
|
||
|
),
|
||
|
Expanded(
|
||
|
flex: 3,
|
||
|
child: Builder(builder: (context) {
|
||
|
final int pageCount = (medicineDetails.length / 6).ceil();
|
||
|
final int maxPageCount = medicineDetails.length;
|
||
|
final controller = PageController();
|
||
|
return Padding(
|
||
|
padding: EdgeInsets.only(bottom: 3),
|
||
|
child: Stack(
|
||
|
alignment: Alignment.bottomCenter,
|
||
|
children: [
|
||
|
SmoothPageIndicator(
|
||
|
controller: controller, // PageController
|
||
|
count: pageCount,
|
||
|
effect: WormEffect(dotWidth: 7, dotHeight: 7)),
|
||
|
PageView(
|
||
|
children: List.generate(pageCount, (index) {
|
||
|
return GridView.count(
|
||
|
physics: const NeverScrollableScrollPhysics(),
|
||
|
crossAxisCount: 3,
|
||
|
mainAxisSpacing: 20,
|
||
|
crossAxisSpacing: 35,
|
||
|
padding: EdgeInsets.symmetric(
|
||
|
horizontal: 30,
|
||
|
),
|
||
|
children: medicineDetails
|
||
|
.sublist(index * 6, min((index + 1) * 6, maxPageCount))
|
||
|
.map((e) {
|
||
|
return GestureDetector(
|
||
|
onTap: () {
|
||
|
Navigator.of(context).push(SlidePageRoute(
|
||
|
builder: MedicineDetailPage(name: "${e['text']}"),
|
||
|
));
|
||
|
},
|
||
|
child: Column(
|
||
|
children: [
|
||
|
Expanded(
|
||
|
flex: 2,
|
||
|
child: null != e['icon']
|
||
|
? CircleAvatar(
|
||
|
backgroundColor:
|
||
|
Theme.of(context).secondaryHeaderColor,
|
||
|
backgroundImage: Image.network(
|
||
|
e['icon'],
|
||
|
fit: BoxFit.cover,
|
||
|
loadingBuilder: (context, child, loadingProgress) {
|
||
|
if (loadingProgress == null) {
|
||
|
return child;
|
||
|
} else {
|
||
|
return Icon(Icons.downloading_outlined);
|
||
|
}
|
||
|
},
|
||
|
).image,
|
||
|
radius: 50,
|
||
|
)
|
||
|
: CircleAvatar(
|
||
|
backgroundColor:
|
||
|
Theme.of(context).secondaryHeaderColor,
|
||
|
)),
|
||
|
Expanded(
|
||
|
flex: 1,
|
||
|
child: Text(
|
||
|
'${e['text']}',
|
||
|
style: TextStyle(
|
||
|
fontSize: 13,
|
||
|
fontWeight: FontWeight.w400,
|
||
|
color: Colors.black.withAlpha(170)),
|
||
|
),
|
||
|
)
|
||
|
],
|
||
|
),
|
||
|
);
|
||
|
}).toList());
|
||
|
}).toList(),
|
||
|
controller: controller,
|
||
|
)
|
||
|
],
|
||
|
),
|
||
|
);
|
||
|
}))
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
} else {
|
||
|
return Container(
|
||
|
alignment: Alignment.center,
|
||
|
child: Text(
|
||
|
'- 没有更多了 -',
|
||
|
style: TextStyle(color: Colors.grey),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
});
|
||
|
} else {
|
||
|
return Center(
|
||
|
child: SpinKitFadingCircle(
|
||
|
color: Theme.of(context).primaryColor,
|
||
|
size: 32,
|
||
|
));
|
||
|
}
|
||
|
}),
|
||
|
);
|
||
|
}
|
||
|
}
|