home_page.dart 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. import 'package:after_layout/after_layout.dart';
  2. import 'package:flutter/material.dart';
  3. class HomePage extends StatelessWidget {
  4. const HomePage({Key? key}) : super(key: key);
  5. @override
  6. Widget build(BuildContext context) {
  7. double rpx = MediaQuery.of(context).size.width / 750;
  8. return Scaffold(
  9. body: Container(
  10. child: HomeMain(
  11. rpx: rpx,
  12. ),
  13. ),
  14. );
  15. }
  16. }
  17. class HomeMain extends StatefulWidget {
  18. HomeMain({Key? key, required this.rpx}) : super(key: key);
  19. final double rpx;
  20. _HomeMainState createState() => _HomeMainState();
  21. }
  22. class _HomeMainState extends State<HomeMain> with TickerProviderStateMixin {
  23. double extraPicHeight = 0;
  24. late BoxFit fitType;
  25. double prevDy = 0;
  26. double rpx = 0;
  27. late AnimationController animationController;
  28. late Animation<double> anim;
  29. late TabController tabController;
  30. double expanedHeight = 300;
  31. @override
  32. void initState() {
  33. super.initState();
  34. tabController = TabController(vsync: this, length: 3);
  35. prevDy = 0;
  36. fitType = BoxFit.fitWidth;
  37. animationController =
  38. AnimationController(vsync: this, duration: Duration(milliseconds: 300));
  39. anim = Tween(begin: 0.0, end: 0.0).animate(animationController);
  40. }
  41. updatePicHeight(changed) {
  42. if (prevDy == 0) {
  43. prevDy = changed;
  44. }
  45. extraPicHeight += changed - prevDy;
  46. if (extraPicHeight >= 200 * widget.rpx) {
  47. fitType = BoxFit.fitHeight;
  48. } else {
  49. fitType = BoxFit.fitWidth;
  50. }
  51. setState(() {
  52. prevDy = changed;
  53. extraPicHeight = extraPicHeight;
  54. fitType = fitType;
  55. });
  56. }
  57. updateExpandedHeight(height) {
  58. setState(() {
  59. expanedHeight = height;
  60. });
  61. }
  62. runAnimate() {
  63. setState(() {
  64. anim = Tween(begin: extraPicHeight, end: 0.0).animate(animationController)
  65. ..addListener(() {
  66. if (extraPicHeight >= widget.rpx * 200) {
  67. fitType = BoxFit.fitHeight;
  68. } else {
  69. fitType = BoxFit.fitWidth;
  70. }
  71. setState(() {
  72. extraPicHeight = anim.value;
  73. fitType = fitType;
  74. });
  75. });
  76. prevDy = 0;
  77. });
  78. }
  79. @override
  80. Widget build(BuildContext context) {
  81. double rpx = MediaQuery.of(context).size.width / 750;
  82. return Listener(
  83. onPointerMove: (result) {
  84. updatePicHeight(result.position.dy);
  85. },
  86. onPointerUp: (_) {
  87. runAnimate();
  88. animationController.forward(from: 0);
  89. },
  90. child: CustomScrollView(
  91. physics: ClampingScrollPhysics(),
  92. slivers: <Widget>[
  93. SliverAppBar(
  94. pinned: true,
  95. floating: true,
  96. actions: <Widget>[
  97. IconButton(
  98. icon: Icon(Icons.search),
  99. onPressed: () {},
  100. ),
  101. IconButton(
  102. icon: Icon(Icons.more_vert),
  103. onPressed: () {},
  104. ),
  105. ],
  106. leading: IconButton(
  107. icon: Icon(Icons.arrow_back),
  108. onPressed: () {},
  109. ),
  110. bottom: PreferredSize(
  111. preferredSize: Size.fromHeight(50),
  112. child: TabBar(
  113. controller: tabController,
  114. tabs: <Widget>[
  115. Text("作品 91"),
  116. Text("动态 91"),
  117. Text("喜欢 91"),
  118. ],
  119. )),
  120. // expandedHeight: 510 * rpx + extraPicHeight,
  121. expandedHeight: expanedHeight + extraPicHeight,
  122. flexibleSpace: Container(
  123. child: TopBarWithCallback(
  124. extraPicHeight: extraPicHeight,
  125. fitType: fitType,
  126. updateHeight: updateExpandedHeight,
  127. ),
  128. ),
  129. ),
  130. SliverList(
  131. delegate: SliverChildBuilderDelegate((context, index) {
  132. return Container(
  133. height: 30,
  134. alignment: Alignment.centerLeft,
  135. color: Colors.blueAccent,
  136. child: Text("This is itm $index"),
  137. margin: EdgeInsets.symmetric(
  138. horizontal: 20 * rpx, vertical: 10 * rpx),
  139. );
  140. }, childCount: 80),
  141. )
  142. ],
  143. ));
  144. }
  145. }
  146. class TopBarWithCallback extends StatefulWidget {
  147. TopBarWithCallback(
  148. {Key? key,
  149. required this.extraPicHeight,
  150. required this.fitType,
  151. required this.updateHeight})
  152. : super(key: key);
  153. final double extraPicHeight;
  154. final BoxFit fitType;
  155. final Function(double) updateHeight;
  156. _TopBarWithCallbackState createState() => _TopBarWithCallbackState();
  157. }
  158. class _TopBarWithCallbackState extends State<TopBarWithCallback>
  159. with AfterLayoutMixin {
  160. @override
  161. Widget build(BuildContext context) {
  162. return Container(
  163. child: SliverTopBar(
  164. extraPicHeight: widget.extraPicHeight,
  165. fitType: widget.fitType,
  166. ),
  167. );
  168. }
  169. @override
  170. void afterFirstLayout(BuildContext context) {
  171. RenderObject? box = context.findRenderObject();
  172. // double height =
  173. // box.getMaxIntrinsicHeight(MediaQuery.of(context).size.width);
  174. // widget.updateHeight(height);
  175. }
  176. }
  177. class SliverTopBar extends StatelessWidget {
  178. const SliverTopBar(
  179. {Key? key, required this.extraPicHeight, required this.fitType})
  180. : super(key: key);
  181. final double extraPicHeight;
  182. final BoxFit fitType;
  183. @override
  184. Widget build(BuildContext context) {
  185. double rpx = MediaQuery.of(context).size.width / 750;
  186. return Stack(
  187. children: [
  188. Column(
  189. mainAxisSize: MainAxisSize.min,
  190. children: [
  191. Image.asset(
  192. "assets/images/temple.jpg",
  193. width: 750 * rpx,
  194. height: 300 * rpx + extraPicHeight,
  195. fit: fitType,
  196. ),
  197. Container(
  198. padding: EdgeInsets.only(top: 20 * rpx),
  199. height: 120 * rpx,
  200. child: Row(
  201. mainAxisAlignment: MainAxisAlignment.end,
  202. children: [
  203. Container(
  204. height: 80 * rpx,
  205. width: 330 * rpx,
  206. child: ElevatedButton(
  207. style: ButtonStyle(
  208. foregroundColor: MaterialStateProperty.all(Color(0xffdc3254))
  209. ),
  210. child: Text(
  211. "+关注",
  212. style: TextStyle(
  213. fontSize: 30 * rpx,
  214. color: Colors.white,
  215. letterSpacing: 3 * rpx),
  216. ),
  217. onPressed: () {},
  218. )),
  219. SizedBox(
  220. width: 10 * rpx,
  221. ),
  222. Container(
  223. decoration: BoxDecoration(
  224. borderRadius: BorderRadius.circular(2),
  225. color: Color(0xff3b3c49),
  226. ),
  227. height: 80 * rpx,
  228. child: IconButton(
  229. icon: Center(
  230. child: Icon(
  231. Icons.arrow_drop_down,
  232. color: Colors.white,
  233. size: 50 * rpx,
  234. )),
  235. onPressed: () {},
  236. ),
  237. ),
  238. SizedBox(
  239. width: 30 * rpx,
  240. )
  241. ],
  242. ),
  243. ),
  244. SizedBox(
  245. height: 100 * rpx,
  246. ),
  247. Container(
  248. width: 750 * rpx,
  249. padding: EdgeInsets.symmetric(horizontal: 30 * rpx),
  250. child: Column(
  251. crossAxisAlignment: CrossAxisAlignment.start,
  252. children: [
  253. Text(
  254. "马友发",
  255. style: TextStyle(
  256. fontSize: 55 * rpx,
  257. color: Colors.white,
  258. fontWeight: FontWeight.bold),
  259. ),
  260. Text("抖音号:1234567",
  261. style: TextStyle(
  262. fontSize: 27 * rpx,
  263. color: Colors.white,
  264. )),
  265. SizedBox(
  266. height: 15 * rpx,
  267. )
  268. ],
  269. )),
  270. Padding(
  271. padding: EdgeInsets.symmetric(horizontal: 20 * rpx),
  272. child: Divider(
  273. color: Colors.grey[700],
  274. ),
  275. ),
  276. Container(
  277. padding: EdgeInsets.symmetric(horizontal: 20 * rpx),
  278. child: Row(
  279. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  280. children: [
  281. Row(
  282. children: [
  283. Icon(
  284. Icons.shop,
  285. color: Color(0xffeacd3f),
  286. ),
  287. Text(
  288. "商品橱窗",
  289. style: TextStyle(color: Color(0xffeacd3f)),
  290. )
  291. ],
  292. ),
  293. Icon(Icons.keyboard_arrow_right, color: Color(0xffeacd3f))
  294. ],
  295. )),
  296. Padding(
  297. padding: EdgeInsets.symmetric(horizontal: 20 * rpx),
  298. child: Divider(
  299. color: Colors.grey[700],
  300. ),
  301. ),
  302. Container(
  303. padding: EdgeInsets.symmetric(horizontal: 20 * rpx),
  304. height: 100 * rpx,
  305. width: 750 * rpx,
  306. child: Text(
  307. "爱神的箭发;黑色大力开发哈的\n阿萨德饭还是电话费拉开始的计划发",
  308. style: TextStyle(color: Colors.white, fontSize: 30 * rpx),
  309. ),
  310. ),
  311. Container(
  312. padding: EdgeInsets.symmetric(
  313. horizontal: 20 * rpx, vertical: 10 * rpx),
  314. child: Row(
  315. children: [
  316. Tag(
  317. text: "深圳",
  318. ),
  319. Tag(
  320. text: "世界之窗",
  321. ),
  322. Tag(
  323. text: "深圳大学",
  324. )
  325. ],
  326. ),
  327. ),
  328. Container(
  329. padding: EdgeInsets.symmetric(
  330. horizontal: 20 * rpx, vertical: 30 * rpx),
  331. child: Row(
  332. children: [
  333. NumWithDesc(
  334. numm: "100.2w",
  335. desc: "获赞",
  336. ),
  337. NumWithDesc(
  338. numm: "15",
  339. desc: "关注",
  340. ),
  341. NumWithDesc(
  342. numm: "10.8w",
  343. desc: "粉丝",
  344. ),
  345. ],
  346. ),
  347. )
  348. ],
  349. ),
  350. Positioned(
  351. top: 250 * rpx + extraPicHeight,
  352. left: 30 * rpx,
  353. child: Container(
  354. decoration: BoxDecoration(
  355. color: Theme.of(context).primaryColor,
  356. borderRadius: BorderRadius.circular(220 * rpx)),
  357. width: 220 * rpx,
  358. height: 220 * rpx,
  359. padding: EdgeInsets.all(10 * rpx),
  360. child: CircleAvatar(
  361. backgroundImage: NetworkImage(
  362. "https://pic2.zhimg.com/v2-a88cd7618933272ca681f86398e6240d_xll.jpg"))),
  363. )
  364. ],
  365. );
  366. }
  367. }
  368. class Tag extends StatelessWidget {
  369. const Tag({Key? key, required this.text}) : super(key: key);
  370. final String text;
  371. @override
  372. Widget build(BuildContext context) {
  373. double rpx = MediaQuery.of(context).size.width / 750;
  374. return Container(
  375. child: Text(
  376. text,
  377. style: TextStyle(fontSize: 26 * rpx, color: Color(0xff64626e)),
  378. ),
  379. color: Color(0xff3b3c49),
  380. padding: EdgeInsets.all(10 * rpx),
  381. margin: EdgeInsets.only(right: 10 * rpx),
  382. );
  383. }
  384. }
  385. class NumWithDesc extends StatelessWidget {
  386. const NumWithDesc({Key? key, required this.numm, required this.desc})
  387. : super(key: key);
  388. final String numm;
  389. final String desc;
  390. @override
  391. Widget build(BuildContext context) {
  392. double rpx = MediaQuery.of(context).size.width / 750;
  393. double textSize = 35 * rpx;
  394. return Padding(
  395. padding: EdgeInsets.only(right: 20 * rpx),
  396. child: Row(
  397. children: [
  398. Text(
  399. numm,
  400. style: TextStyle(
  401. fontSize: textSize,
  402. color: Colors.white,
  403. fontWeight: FontWeight.bold),
  404. ),
  405. SizedBox(
  406. width: 10 * rpx,
  407. ),
  408. Text(desc,
  409. style: TextStyle(fontSize: textSize, color: Color(0xff3b3c49)))
  410. ],
  411. ));
  412. }
  413. }
  414. // import 'package:flutter/material.dart';
  415. // class SelfHomePage extends StatelessWidget {
  416. // const SelfHomePage({Key? key}) : super(key: key);
  417. // @override
  418. // Widget build(BuildContext context) {
  419. // return Scaffold(
  420. // body: CustomScrollView(
  421. // physics: ClampingScrollPhysics(),
  422. // slivers: <Widget>[
  423. // SliverAppBar(
  424. // leading: IconButton(
  425. // icon: Icon(Icons.arrow_back),
  426. // onPressed: () {},
  427. // ),
  428. // floating: true,
  429. // pinned: false,
  430. // snap: true,
  431. // expandedHeight: 250,
  432. // flexibleSpace: FlexibleSpaceBar(
  433. // title: Text("This is Sliver App Bar"),
  434. // background: Image.asset("assets/images/temple.jpg",height: 250,fit: BoxFit.fitWidth,),
  435. // ),
  436. // ),
  437. // SliverList(delegate: SliverChildBuilderDelegate((context,index){
  438. // return Container(child: Text("This is item $index",style: TextStyle(fontSize: 20),),color: Colors.redAccent,);
  439. // },))
  440. // ],
  441. // ),
  442. // );
  443. // }
  444. // }