diff --git a/assets/images/placeholder.webp b/assets/images/placeholder.webp new file mode 100644 index 00000000..0b27014f Binary files /dev/null and b/assets/images/placeholder.webp differ diff --git a/lib/const/resource.dart b/lib/const/resource.dart index 9773b63e..45cbb900 100644 --- a/lib/const/resource.dart +++ b/lib/const/resource.dart @@ -530,6 +530,10 @@ class R { static const String ASSETS_IMAGES_PHONE_LOGO_PNG = 'assets/images/phone_logo.png'; + /// ![preview](file:///Users/akufe/Documents/akuCommunity/assets/images/placeholder.webp) + static const String ASSETS_IMAGES_PLACEHOLDER_WEBP = + 'assets/images/placeholder.webp'; + /// ![preview](file:///Users/akufe/Documents/akuCommunity/assets/images/white.png) static const String ASSETS_IMAGES_WHITE_PNG = 'assets/images/white.png'; diff --git a/lib/model/community/community_topic_model.dart b/lib/model/community/community_topic_model.dart index 6508ff3c..cc029304 100644 --- a/lib/model/community/community_topic_model.dart +++ b/lib/model/community/community_topic_model.dart @@ -14,6 +14,14 @@ class CommunityTopicModel { List headSculptureImgUrl; List gambitThemeCommentVoList; + String get firstImg { + var firstImg = ''; + if (imgUrls?.isNotEmpty ?? false) { + firstImg = imgUrls?.first?.url ?? ''; + } + return firstImg; + } + CommunityTopicModel( {this.id, this.createId, diff --git a/lib/pages/goods_manage_page/goods_manage_page.dart b/lib/pages/goods_manage_page/goods_manage_page.dart index f42b194f..1cacd960 100644 --- a/lib/pages/goods_manage_page/goods_manage_page.dart +++ b/lib/pages/goods_manage_page/goods_manage_page.dart @@ -53,7 +53,7 @@ class _GoodsManagePageState extends State { margin: EdgeInsets.only(right: 20.w), child: ClipRRect( child: FadeInImage.assetNetwork( - placeholder: R.ASSETS_IMAGES_LOGO_PNG, + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, image: API.image( model.imgUrls.isEmpty ? '' : model.imgUrls.first.url))), ), diff --git a/lib/ui/community/activity/activity_card.dart b/lib/ui/community/activity/activity_card.dart index 6683eca4..4e79ecb4 100644 --- a/lib/ui/community/activity/activity_card.dart +++ b/lib/ui/community/activity/activity_card.dart @@ -48,7 +48,7 @@ class ActivityCard extends StatelessWidget { child: Material( color: Colors.grey, child: FadeInImage.assetNetwork( - placeholder: R.ASSETS_IMAGES_LOGO_PNG, + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, image: API.image(firstPath), height: 210.w, width: double.infinity, diff --git a/lib/ui/community/activity/activity_detail_page.dart b/lib/ui/community/activity/activity_detail_page.dart index f8e9efcb..4a3d2ca1 100644 --- a/lib/ui/community/activity/activity_detail_page.dart +++ b/lib/ui/community/activity/activity_detail_page.dart @@ -119,7 +119,7 @@ class _ActivityDetailPageState extends State { ), clipBehavior: Clip.antiAlias, child: FadeInImage.assetNetwork( - placeholder: R.ASSETS_IMAGES_LOGO_PNG, + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, image: e.url, ), ), diff --git a/lib/ui/community/activity/activity_people_list_page.dart b/lib/ui/community/activity/activity_people_list_page.dart index fafaccfe..5edc6558 100644 --- a/lib/ui/community/activity/activity_people_list_page.dart +++ b/lib/ui/community/activity/activity_people_list_page.dart @@ -50,7 +50,7 @@ class _ActivityPeopleListPageState extends State { 96.hb, 20.wb, FadeInImage.assetNetwork( - placeholder: R.ASSETS_IMAGES_LOGO_PNG, + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, image: API.image(model.imgUrl.first.url), height: 60.w, width: 60.w, diff --git a/lib/ui/community/community_views/topic/topic_community_view.dart b/lib/ui/community/community_views/topic/topic_community_view.dart index a1e4190c..22a08746 100644 --- a/lib/ui/community/community_views/topic/topic_community_view.dart +++ b/lib/ui/community/community_views/topic/topic_community_view.dart @@ -21,55 +21,55 @@ class _TopicCommunityViewState extends State EasyRefreshController _refreshController = EasyRefreshController(); _buildItem(CommunityTopicModel model) { - var firstImg = ''; - if (model?.imgUrls?.isNotEmpty ?? false) { - firstImg = model?.imgUrls?.first?.url ?? ''; - } return MaterialButton( padding: EdgeInsets.symmetric(horizontal: 53.w, vertical: 20.w), onPressed: () { - Get.to(TopicDetailPage(id: model.id)); + Get.to(TopicDetailPage(model: model)); }, child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.w), - color: Colors.black12, - ), - child: Stack( - children: [ - FadeInImage.assetNetwork( - placeholder: R.ASSETS_IMAGES_LOGO_PNG, - image: API.image(firstImg), - height: 160.w, - width: 250.w, - ), - Positioned( - bottom: 0, - left: 0, - right: 0, - child: ClipRRect( - borderRadius: BorderRadius.vertical( - bottom: Radius.circular(8.w), - ), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), - //TODO 等待后端接口补充话题摘要 - // model.summary - child: ('#${''}') - .text - .center - .size(28.sp) - .white - .make() - .material(color: Colors.black26), + Hero( + tag: "${model.firstImg}_${model.id}", + child: Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.w), + color: Colors.black12, + ), + child: Stack( + children: [ + FadeInImage.assetNetwork( + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, + image: API.image(model.firstImg), + height: 160.w, + width: 250.w, + fit: BoxFit.cover, + ), + Positioned( + bottom: 0, + left: 0, + right: 0, + child: ClipRRect( + borderRadius: BorderRadius.vertical( + bottom: Radius.circular(8.w), + ), + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), + //TODO 等待后端接口补充话题摘要 + // model.summary + child: ('#${''}') + .text + .center + .size(28.sp) + .white + .make() + .material(color: Colors.black26), + ), ), ), - ), - ], + ], + ), ), ), 12.wb, diff --git a/lib/ui/community/community_views/topic/topic_detail_page.dart b/lib/ui/community/community_views/topic/topic_detail_page.dart index 0f0efcd1..32dd8457 100644 --- a/lib/ui/community/community_views/topic/topic_detail_page.dart +++ b/lib/ui/community/community_views/topic/topic_detail_page.dart @@ -1,10 +1,12 @@ -import 'package:akuCommunity/ui/community/community_views/topic/topic_scrollable_text.dart'; +import 'package:akuCommunity/model/community/community_topic_model.dart'; +import 'package:akuCommunity/ui/community/community_views/topic/topic_sliver_header.dart'; import 'package:akuCommunity/utils/headers.dart'; import 'package:flutter/material.dart'; class TopicDetailPage extends StatefulWidget { - final int id; - TopicDetailPage({Key key, @required this.id}) : super(key: key); + final CommunityTopicModel model; + + TopicDetailPage({Key key, this.model}) : super(key: key); @override _TopicDetailPageState createState() => _TopicDetailPageState(); @@ -16,17 +18,14 @@ class _TopicDetailPageState extends State { return Scaffold( body: CustomScrollView( slivers: [ - SliverAppBar( - expandedHeight: 500.w, - backgroundColor: Colors.transparent, - elevation: 0, - pinned: true, - flexibleSpace: FlexibleSpaceBar( - title: TopicScrollableText(title: '#TEST'), - titlePadding: EdgeInsets.zero, - collapseMode: CollapseMode.pin, - background: Container(color: Colors.red), + SliverPersistentHeader( + delegate: TopicSliverHeader( + id: widget.model.id, + title: 'TEST', + imgPath: widget.model.firstImg, + subTitle: widget.model.content, ), + pinned: true, ), SliverToBoxAdapter( child: 40000.hb, diff --git a/lib/ui/community/community_views/topic/topic_scrollable_text.dart b/lib/ui/community/community_views/topic/topic_scrollable_text.dart deleted file mode 100644 index bb23f6e0..00000000 --- a/lib/ui/community/community_views/topic/topic_scrollable_text.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:akuCommunity/utils/headers.dart'; -import 'package:flutter/material.dart'; - -class TopicScrollableText extends StatefulWidget { - final String title; - TopicScrollableText({Key key, @required this.title}) : super(key: key); - - @override - _TopicScrollableTextState createState() => _TopicScrollableTextState(); -} - -class _TopicScrollableTextState extends State { - ScrollPosition _scrollPosition; - - _positionListener() { - setState(() {}); - } - - @override - void dispose() { - _scrollPosition?.removeListener(_positionListener); - super.dispose(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _scrollPosition = Scrollable.of(context)?.position; - _scrollPosition?.addListener(_positionListener); - } - - double get offset { - if (_scrollPosition.pixels >= 500.w) return 1; - if (_scrollPosition.pixels < 500.w && _scrollPosition.pixels >= 0) { - return _scrollPosition.pixels / 500.w; - } else - return 0; - } - - @override - Widget build(BuildContext context) { - return Padding( - padding: EdgeInsets.only(bottom: 202.w - offset * 160.w), - child: Text(widget.title), - ); - } -} diff --git a/lib/ui/community/community_views/topic/topic_sliver_header.dart b/lib/ui/community/community_views/topic/topic_sliver_header.dart new file mode 100644 index 00000000..8a27ebd2 --- /dev/null +++ b/lib/ui/community/community_views/topic/topic_sliver_header.dart @@ -0,0 +1,114 @@ +import 'package:akuCommunity/constants/api.dart'; +import 'package:akuCommunity/utils/headers.dart'; +import 'package:akuCommunity/widget/bee_back_button.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class TopicSliverHeader extends SliverPersistentHeaderDelegate { + final String imgPath; + final String title; + final String subTitle; + final int id; + + TopicSliverHeader({ + this.imgPath, + this.title, + this.subTitle, + @required this.id, + }); + + _buildOverlay(double shrinkOffset) { + return Positioned( + left: 0, + right: 0, + top: 0, + bottom: 0, + child: Material( + color: Colors.white.withOpacity(0 + 0.5 * _offset(shrinkOffset)), + ), + ); + } + + _buildBackButton() { + return Positioned( + left: 0, + top: ScreenUtil().statusBarHeight, + child: BeeBackButton().material( + color: Colors.transparent, + clipBehavior: Clip.antiAlias, + borderRadius: BorderRadius.circular(24), + ), + ); + } + + _buildTitle(double shrinkOffset) { + return Positioned( + bottom: 202.w - 195.w * _filterOffset(shrinkOffset), + left: 32.w + (95.w - 32.w) * _offset(shrinkOffset), + child: '#$title'.text.bold.size(52.sp).make(), + ); + } + + _buildSubTitle(double shrinkOffset) { + return Positioned( + bottom: 104.w - 104.w * _offset(shrinkOffset) * 2, + left: 32.w, + child: Opacity( + opacity: 1 - _offset(shrinkOffset), + child: subTitle.text.size(24.sp).make(), + ), + ); + } + + @override + Widget build( + BuildContext context, double shrinkOffset, bool overlapsContent) { + return Container( + color: Colors.white, + child: Stack( + fit: StackFit.expand, + children: [ + Hero( + tag: "$imgPath\_$id", + child: FadeInImage.assetNetwork( + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, + image: API.image(imgPath), + fit: BoxFit.cover, + ), + ), + _buildOverlay(shrinkOffset), + _buildBackButton(), + _buildTitle(shrinkOffset), + _buildSubTitle(shrinkOffset), + ], + ), + ); + } + + double _offset(double shrinkOffset) { + if (shrinkOffset <= 0) + return 0; + else if (shrinkOffset > 0 && shrinkOffset <= maxExtent) + return shrinkOffset / maxExtent; + else + return 1; + } + + double _filterOffset(double shrinkOffset) { + var offset = _offset(shrinkOffset); + if (offset <= 0) return 0; + if (offset < 0.7) return offset / 0.7; + return 1; + } + + @override + double get maxExtent => 460.w + ScreenUtil().statusBarHeight; + + @override + double get minExtent => 48 + ScreenUtil().statusBarHeight; + + @override + bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { + return true; + } +} diff --git a/lib/ui/community/community_views/widgets/chat_card.dart b/lib/ui/community/community_views/widgets/chat_card.dart new file mode 100644 index 00000000..f22fa476 --- /dev/null +++ b/lib/ui/community/community_views/widgets/chat_card.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +class ChatCard extends StatefulWidget { + final String name; + final String title; + ChatCard({Key key, this.name, this.title}) : super(key: key); + + @override + _ChatCardState createState() => _ChatCardState(); +} + +class _ChatCardState extends State { + @override + Widget build(BuildContext context) { + return Container(); + } +} diff --git a/lib/ui/community/notice/notice_card.dart b/lib/ui/community/notice/notice_card.dart index f2ad8dd0..c8f1b50a 100644 --- a/lib/ui/community/notice/notice_card.dart +++ b/lib/ui/community/notice/notice_card.dart @@ -96,7 +96,7 @@ class NoticeCard extends StatelessWidget { borderRadius: BorderRadius.circular(8.w), ), child: FadeInImage.assetNetwork( - placeholder: R.ASSETS_IMAGES_LOGO_PNG, + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, image: API.image(model.imgUrls.first.url), width: 152.w, height: 152.w, diff --git a/lib/ui/community/notice/notice_detail_page.dart b/lib/ui/community/notice/notice_detail_page.dart index fe3dd637..f15f55bb 100644 --- a/lib/ui/community/notice/notice_detail_page.dart +++ b/lib/ui/community/notice/notice_detail_page.dart @@ -99,7 +99,7 @@ class _NoticeDetailPageState extends State { color: Colors.black12, ), child: FadeInImage.assetNetwork( - placeholder: R.ASSETS_IMAGES_LOGO_PNG, + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, image: API.image(e.url), fit: BoxFit.cover, ), diff --git a/lib/widget/others/stack_avatar.dart b/lib/widget/others/stack_avatar.dart index ad2209e2..05662077 100644 --- a/lib/widget/others/stack_avatar.dart +++ b/lib/widget/others/stack_avatar.dart @@ -32,7 +32,7 @@ class StackAvatar extends StatelessWidget { child: FadeInImage.assetNetwork( height: 44.w, width: 44.w, - placeholder: R.ASSETS_IMAGES_LOGO_PNG, + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, image: API.image(avatars[index]), ), ), diff --git a/lib/widget/picker/bee_image_preview.dart b/lib/widget/picker/bee_image_preview.dart index 43a43499..3c70c36b 100644 --- a/lib/widget/picker/bee_image_preview.dart +++ b/lib/widget/picker/bee_image_preview.dart @@ -33,7 +33,7 @@ class _BeeImagePreviewState extends State { return Hero( tag: widget.path, child: FadeInImage.assetNetwork( - placeholder: R.ASSETS_IMAGES_LOGO_PNG, + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, image: API.image(widget.path), ), ); diff --git a/lib/widget/views/bee_grid_image_view.dart b/lib/widget/views/bee_grid_image_view.dart index f61e74e6..49df7e41 100644 --- a/lib/widget/views/bee_grid_image_view.dart +++ b/lib/widget/views/bee_grid_image_view.dart @@ -44,7 +44,7 @@ class BeeGridImageView extends StatelessWidget { child: FadeInImage.assetNetwork( height: 184.w, width: 184.w, - placeholder: R.ASSETS_IMAGES_LOGO_PNG, + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, image: API.image(urls[index]), fit: BoxFit.cover, ), diff --git a/lib/widget/views/horizontal_image_view.dart b/lib/widget/views/horizontal_image_view.dart index d273143b..5f34eb21 100644 --- a/lib/widget/views/horizontal_image_view.dart +++ b/lib/widget/views/horizontal_image_view.dart @@ -43,7 +43,7 @@ class HorizontalImageView extends StatelessWidget { child: FadeInImage.assetNetwork( height: 184.w, width: 184.w, - placeholder: R.ASSETS_IMAGES_LOGO_PNG, + placeholder: R.ASSETS_IMAGES_PLACEHOLDER_WEBP, image: API.image(urls[index]), fit: BoxFit.cover, ),