style: 调整搜索结果两列布局
This commit is contained in:
1 parent
0319f8a6a8
commit
8637f5da21
6 files changed
+124
-9
No files matched your search
@@ -112,6 +112,7 @@ abstract final class AppColors {
|
||||
static const textTertiary = Color(0xFF8E8E93);
|
||||
static const textTabInactive = Color(0xFFB0B0B0);
|
||||
static const textFilterIcon = Color(0xFF7A7A7E);
|
||||
static const searchResultMeta = Color(0xFF9E9E9E);
|
||||
|
||||
/// 原生开屏与冷启动过渡底色。
|
||||
static const splashInk = ink;
|
||||
|
||||
@@ -62,6 +62,12 @@ abstract final class AppDimens {
|
||||
static const double searchHeight = 40;
|
||||
static const double searchRadius = 8;
|
||||
static const double searchPlaceholderFont = 13;
|
||||
static const double searchResultGap = 12;
|
||||
static const double searchResultRowGap = 16;
|
||||
static const double searchResultTitleGap = 8;
|
||||
static const double searchResultMetaGap = 6;
|
||||
static const double searchResultMetaFont = 12;
|
||||
static const double searchResultTextExtent = 68;
|
||||
static const double navDot = 3;
|
||||
static const double glassBlur = 24;
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ import '../../core/theme/app_dimens.dart';
|
||||
import '../../core/theme/app_theme.dart';
|
||||
import '../../core/widgets/empty_state.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../home/widgets/home_feed_card.dart';
|
||||
import '../player/open_player.dart';
|
||||
import 'discover_binding.dart';
|
||||
import 'discover_logic.dart';
|
||||
import 'widgets/search_result_card.dart';
|
||||
|
||||
class SearchPage extends StatefulWidget {
|
||||
const SearchPage({super.key});
|
||||
@@ -222,11 +222,11 @@ class _SearchPageState extends State<SearchPage> {
|
||||
final width =
|
||||
(constraints.maxWidth -
|
||||
AppDimens.feedPageHorizontal * 2 -
|
||||
AppDimens.homeGridGap * 2) /
|
||||
3;
|
||||
AppDimens.searchResultGap) /
|
||||
2;
|
||||
final itemExtent =
|
||||
width / AppDimens.cardCoverAspectRatio +
|
||||
AppDimens.homeCardBodyExtent;
|
||||
AppDimens.searchResultTextExtent;
|
||||
return GridView.builder(
|
||||
key: const Key('search-results-grid'),
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
@@ -236,15 +236,15 @@ class _SearchPageState extends State<SearchPage> {
|
||||
AppDimens.spaceXl,
|
||||
),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 3,
|
||||
crossAxisSpacing: AppDimens.homeGridGap,
|
||||
mainAxisSpacing: AppDimens.homeGridRowGap,
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: AppDimens.searchResultGap,
|
||||
mainAxisSpacing: AppDimens.searchResultRowGap,
|
||||
mainAxisExtent: itemExtent,
|
||||
),
|
||||
itemCount: _logic.searchResults.length,
|
||||
itemBuilder: (context, index) {
|
||||
final drama = _logic.searchResults[index];
|
||||
return HomeFeedCard(
|
||||
return SearchResultCard(
|
||||
drama: drama,
|
||||
onTap: () => unawaited(playDramaFromCatalog(context, drama)),
|
||||
);
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../core/data/models/drama.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/theme/app_dimens.dart';
|
||||
import '../../../core/widgets/cover_play_count.dart';
|
||||
import '../../../core/widgets/remote_image.dart';
|
||||
|
||||
class SearchResultCard extends StatelessWidget {
|
||||
const SearchResultCard({super.key, required this.drama, required this.onTap});
|
||||
|
||||
final Drama drama;
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final tags = _tags();
|
||||
return Material(
|
||||
key: Key('search-result-card-${drama.id}'),
|
||||
color: AppColors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardCoverRadius),
|
||||
onTap: onTap,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardCoverRadius),
|
||||
child: AspectRatio(
|
||||
key: Key('search-result-cover-${drama.id}'),
|
||||
aspectRatio: AppDimens.cardCoverAspectRatio,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
RemoteImage(
|
||||
drama.posterUrl,
|
||||
fit: BoxFit.cover,
|
||||
showFallbackIcon: true,
|
||||
fallbackColor: AppColors.contentSurface,
|
||||
),
|
||||
const Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: CoverBottomScrim(),
|
||||
),
|
||||
Positioned(
|
||||
right: AppDimens.cardPlayCountRight,
|
||||
bottom: AppDimens.cardPlayCountBottom,
|
||||
child: CoverPlayCount(
|
||||
key: Key('search-result-views-${drama.id}'),
|
||||
count: drama.viewCount,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppDimens.searchResultTitleGap),
|
||||
Text(
|
||||
drama.title,
|
||||
key: Key('search-result-title-${drama.id}'),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.left,
|
||||
style: const TextStyle(
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: AppDimens.cardTitleFont,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: AppDimens.cardTitleLineHeight,
|
||||
),
|
||||
),
|
||||
if (tags.isNotEmpty) ...[
|
||||
const SizedBox(height: AppDimens.searchResultMetaGap),
|
||||
Text(
|
||||
tags.join(' | '),
|
||||
key: Key('search-result-tags-${drama.id}'),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.left,
|
||||
style: const TextStyle(
|
||||
color: AppColors.searchResultMeta,
|
||||
fontSize: AppDimens.searchResultMetaFont,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<String> _tags() {
|
||||
final seen = <String>{};
|
||||
return [drama.genre, drama.category]
|
||||
.expand((value) => value.split(RegExp(r'[,/、·]')))
|
||||
.map((value) => value.trim())
|
||||
.where((value) => value.isNotEmpty && seen.add(value))
|
||||
.take(3)
|
||||
.toList(growable: false);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user