| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/material.dart'; |
| |
| class PictureCachePage extends StatelessWidget { |
| const PictureCachePage({super.key}); |
| |
| static const List<String> kTabNames = <String>['1', '2', '3', '4', '5']; |
| |
| @override |
| Widget build(BuildContext context) { |
| return DefaultTabController( |
| length: kTabNames.length, // This is the number of tabs. |
| child: Scaffold( |
| appBar: AppBar( |
| title: const Text('Picture Cache'), |
| // pinned: true, |
| // expandedHeight: 50.0, |
| // forceElevated: innerBoxIsScrolled, |
| bottom: TabBar( |
| tabs: kTabNames.map((String name) => Tab(text: name)).toList(), |
| ), |
| ), |
| body: TabBarView( |
| key: const Key('tabbar_view'), // this key is used by the driver test |
| children: kTabNames.map((String name) { |
| return SafeArea( |
| top: false, |
| bottom: false, |
| child: Builder( |
| builder: (BuildContext context) { |
| return ListView.builder( |
| itemBuilder: (BuildContext context, int index) => ListItem(index: index), |
| ); |
| }, |
| ), |
| ); |
| }).toList(), |
| ), |
| ), |
| ); |
| } |
| } |
| |
| class ListItem extends StatelessWidget { |
| const ListItem({super.key, required this.index}); |
| |
| final int index; |
| |
| static const String kMockChineseTitle = '复杂的中文标题?复杂的中文标题!'; |
| static const String kMockName = '李耳123456'; |
| static const int kMockCount = 999; |
| |
| @override |
| Widget build(BuildContext context) { |
| final List<Widget> contents = <Widget>[ |
| const SizedBox( |
| height: 15, |
| ), |
| _buildUserInfo(), |
| const SizedBox( |
| height: 10, |
| ), |
| ]; |
| if (index % 3 != 0) { |
| contents.add(_buildImageContent()); |
| } else { |
| contents.addAll(<Widget>[ |
| Padding( |
| padding: const EdgeInsets.only(left: 40, right: 15), |
| child: _buildContentText(), |
| ), |
| const SizedBox( |
| height: 10, |
| ), |
| Padding( |
| padding: const EdgeInsets.only(left: 40, right: 15), |
| child: _buildBottomRow(), |
| ), |
| ]); |
| } |
| contents.addAll(<Widget>[ |
| const SizedBox( |
| height: 13, |
| ), |
| buildDivider(0.5, const EdgeInsets.only(left: 40, right: 15)), |
| ]); |
| return MaterialButton( |
| onPressed: () {}, |
| padding: EdgeInsets.zero, |
| child: Column( |
| mainAxisSize: MainAxisSize.min, |
| crossAxisAlignment: CrossAxisAlignment.start, |
| children: contents, |
| ), |
| ); |
| } |
| |
| Text _buildRankText() { |
| return Text( |
| (index + 1).toString(), |
| style: TextStyle( |
| fontSize: 15, |
| color: index + 1 <= 3 ? const Color(0xFFE5645F) : Colors.black, |
| fontWeight: FontWeight.bold, |
| ), |
| ); |
| } |
| |
| Widget _buildImageContent() { |
| return Row( |
| children: <Widget>[ |
| const SizedBox( |
| width: 40, |
| ), |
| Expanded( |
| child: Column( |
| mainAxisSize: MainAxisSize.min, |
| crossAxisAlignment: CrossAxisAlignment.start, |
| children: <Widget>[ |
| Padding( |
| padding: const EdgeInsets.only(right: 30), |
| child: _buildContentText(), |
| ), |
| const SizedBox( |
| height: 10, |
| ), |
| _buildBottomRow(), |
| ], |
| ), |
| ), |
| Image.asset( |
| index.isEven ? 'food/butternut_squash_soup.png' : 'food/cherry_pie.png', |
| package: 'flutter_gallery_assets', |
| fit: BoxFit.cover, |
| width: 110, |
| height: 70, |
| ), |
| const SizedBox( |
| width: 15, |
| ), |
| ], |
| ); |
| } |
| |
| Widget _buildContentText() { |
| return const Text( |
| kMockChineseTitle, |
| style: TextStyle( |
| fontSize: 16, |
| ), |
| maxLines: 2, |
| overflow: TextOverflow.ellipsis, |
| ); |
| } |
| |
| Widget _buildBottomRow() { |
| return Row( |
| children: <Widget>[ |
| Container( |
| padding: const EdgeInsets.symmetric( |
| horizontal: 7, |
| ), |
| height: 16, |
| alignment: Alignment.center, |
| decoration: BoxDecoration( |
| borderRadius: BorderRadius.circular(8), |
| color: const Color(0xFFFBEEEE), |
| ), |
| child: Row( |
| children: <Widget>[ |
| const SizedBox( |
| width: 3, |
| ), |
| Text( |
| 'hot:${_convertCountToStr(kMockCount)}', |
| style: const TextStyle( |
| color: Color(0xFFE5645F), |
| fontSize: 11, |
| ), |
| ), |
| ], |
| ), |
| ), |
| const SizedBox( |
| width: 9, |
| ), |
| const Text( |
| 'ans:$kMockCount', |
| style: TextStyle( |
| color: Color(0xFF999999), |
| fontSize: 11, |
| ), |
| ), |
| const SizedBox( |
| width: 9, |
| ), |
| const Text( |
| 'like:$kMockCount', |
| style: TextStyle( |
| color: Color(0xFF999999), |
| fontSize: 11, |
| ), |
| ), |
| ], |
| ); |
| } |
| |
| String _convertCountToStr(int count) { |
| if (count < 10000) { |
| return count.toString(); |
| } else if (count < 100000) { |
| return '${(count / 10000).toStringAsPrecision(2)}w'; |
| } else { |
| return '${(count / 10000).floor()}w'; |
| } |
| } |
| |
| Widget _buildUserInfo() { |
| return GestureDetector( |
| onTap: () {}, |
| child: Row( |
| children: <Widget>[ |
| Container( |
| width: 40, alignment: Alignment.center, child: _buildRankText()), |
| const CircleAvatar( |
| radius: 11.5, |
| ), |
| const SizedBox( |
| width: 6, |
| ), |
| ConstrainedBox( |
| constraints: const BoxConstraints(maxWidth: 250), |
| child: const Text( |
| kMockName, |
| maxLines: 1, |
| overflow: TextOverflow.ellipsis, |
| style: TextStyle( |
| fontSize: 14, |
| fontWeight: FontWeight.bold, |
| ), |
| ), |
| ), |
| const SizedBox( |
| width: 4, |
| ), |
| const SizedBox( |
| width: 15, |
| ), |
| ], |
| ), |
| ); |
| } |
| |
| Widget buildDivider(double height, EdgeInsets padding) { |
| return Container( |
| padding: padding, |
| height: height, |
| color: const Color(0xFFF5F5F5), |
| ); |
| } |
| } |