fix: 动态数据渲染异常

This commit is contained in:
guozhigq
2023-09-06 22:47:54 +08:00
parent 7f961e998c
commit 4c938ed8aa
6 changed files with 324 additions and 182 deletions

View File

@ -28,6 +28,8 @@ Widget content(item, context, source) {
focusNode: FocusNode(), focusNode: FocusNode(),
selectionControls: MaterialTextSelectionControls(), selectionControls: MaterialTextSelectionControls(),
child: Text.rich( child: Text.rich(
/// fix 默认20px高度
style: const TextStyle(height: 0),
richNode(item, context), richNode(item, context),
maxLines: source == 'detail' ? 999 : 3, maxLines: source == 'detail' ? 999 : 3,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,

View File

@ -41,7 +41,8 @@ class DynamicPanel extends StatelessWidget {
padding: const EdgeInsets.fromLTRB(12, 12, 12, 8), padding: const EdgeInsets.fromLTRB(12, 12, 12, 8),
child: author(item, context), child: author(item, context),
), ),
if (item!.modules!.moduleDynamic!.desc != null) if (item!.modules!.moduleDynamic!.desc != null ||
item!.modules!.moduleDynamic!.major != null)
content(item, context, source), content(item, context, source),
forWard(item, context, _dynamicsController, source), forWard(item, context, _dynamicsController, source),
const SizedBox(height: 2), const SizedBox(height: 2),

View File

@ -44,19 +44,21 @@ Widget forWard(item, context, ctr, source, {floor = 1}) {
], ],
), ),
const SizedBox(height: 2), const SizedBox(height: 2),
if (item.modules.moduleDynamic.topic != null) ...[
Padding( /// fix #话题跟content重复
padding: floor == 2 // if (item.modules.moduleDynamic.topic != null) ...[
? EdgeInsets.zero // Padding(
: const EdgeInsets.only(left: 12, right: 12), // padding: floor == 2
child: GestureDetector( // ? EdgeInsets.zero
child: Text( // : const EdgeInsets.only(left: 12, right: 12),
'#${item.modules.moduleDynamic.topic.name}', // child: GestureDetector(
style: authorStyle, // child: Text(
), // '#${item.modules.moduleDynamic.topic.name}',
), // style: authorStyle,
), // ),
], // ),
// ),
// ],
Text.rich( Text.rich(
richNode(item, context), richNode(item, context),
// 被转发状态(floor=2) 隐藏 // 被转发状态(floor=2) 隐藏
@ -71,6 +73,8 @@ Widget forWard(item, context, ctr, source, {floor = 1}) {
: const EdgeInsets.only(left: 12, right: 12), : const EdgeInsets.only(left: 12, right: 12),
child: picWidget(item, context), child: picWidget(item, context),
), ),
/// 附加内容 商品信息、直播预约等等
if (item.modules.moduleDynamic.additional != null) if (item.modules.moduleDynamic.additional != null)
addWidget( addWidget(
item, item,

View File

@ -8,7 +8,9 @@ Widget picWidget(item, context) {
String type = item.modules.moduleDynamic.major.type; String type = item.modules.moduleDynamic.major.type;
List pictures = []; List pictures = [];
if (type == 'MAJOR_TYPE_OPUS') { if (type == 'MAJOR_TYPE_OPUS') {
pictures = item.modules.moduleDynamic.major.opus.pics; /// fix 图片跟rich_node_panel重复
// pictures = item.modules.moduleDynamic.major.opus.pics;
return const SizedBox();
} }
if (type == 'MAJOR_TYPE_DRAW') { if (type == 'MAJOR_TYPE_DRAW') {
pictures = item.modules.moduleDynamic.major.draw.items; pictures = item.modules.moduleDynamic.major.draw.items;

View File

@ -1,175 +1,307 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/dynamics/result.dart';
// 富文本 // 富文本
InlineSpan richNode(item, context) { InlineSpan richNode(item, context) {
TextStyle authorStyle = final spacer = _VerticalSpaceSpan(0.0);
TextStyle(color: Theme.of(context).colorScheme.primary); try {
List<InlineSpan> spanChilds = []; TextStyle authorStyle =
for (var i in item.modules.moduleDynamic.desc.richTextNodes) { TextStyle(color: Theme.of(context).colorScheme.primary);
if (i.type == 'RICH_TEXT_NODE_TYPE_TEXT') { List<InlineSpan> spanChilds = [];
spanChilds.add( String contentType = 'desc';
TextSpan(text: i.origText, style: const TextStyle(height: 1.65)));
dynamic richTextNodes;
if (item.modules.moduleDynamic.desc != null) {
richTextNodes = item.modules.moduleDynamic.desc.richTextNodes;
} else if (item.modules.moduleDynamic.major != null) {
contentType = 'major';
// 动态页面 richTextNodes 层级可能与主页动态层级不同
richTextNodes =
item.modules.moduleDynamic.major.opus.summary.richTextNodes;
} }
// @用户 if (richTextNodes == null || richTextNodes.isEmpty) {
if (i.type == 'RICH_TEXT_NODE_TYPE_AT') { return spacer;
spanChilds.add( } else {
WidgetSpan( for (var i in richTextNodes) {
alignment: PlaceholderAlignment.middle, if (i.type == 'RICH_TEXT_NODE_TYPE_TEXT') {
child: Row( spanChilds.add(
mainAxisSize: MainAxisSize.min, TextSpan(text: i.origText, style: const TextStyle(height: 1.65)));
children: [ }
GestureDetector( // @用户
onTap: () => Get.toNamed('/member?mid=${i.rid}', if (i.type == 'RICH_TEXT_NODE_TYPE_AT') {
arguments: {'face': null}), spanChilds.add(
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
GestureDetector(
onTap: () => Get.toNamed('/member?mid=${i.rid}',
arguments: {'face': null}),
child: Text(
' ${i.text}',
style: authorStyle,
),
),
],
),
),
);
}
// 话题
if (i.type == 'RICH_TEXT_NODE_TYPE_TOPIC') {
spanChilds.add(
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
onTap: () {},
child: Text( child: Text(
' ${i.text}', '${i.origText}',
style: authorStyle, style: authorStyle,
), ),
), ),
],
),
),
);
}
// 话题
if (i.type == 'RICH_TEXT_NODE_TYPE_TOPIC') {
spanChilds.add(
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
onTap: () {},
child: Text(
'${i.origText}',
style: authorStyle,
), ),
), );
), }
); // 网页链接
} if (i.type == 'RICH_TEXT_NODE_TYPE_WEB') {
// 网页链接 spanChilds.add(
if (i.type == 'RICH_TEXT_NODE_TYPE_WEB') { WidgetSpan(
spanChilds.add( alignment: PlaceholderAlignment.middle,
WidgetSpan( child: Icon(
alignment: PlaceholderAlignment.middle, Icons.link,
child: Icon( size: 20,
Icons.link, color: Theme.of(context).colorScheme.primary,
size: 20, ),
color: Theme.of(context).colorScheme.primary,
),
),
);
spanChilds.add(
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
onTap: () {
Get.toNamed(
'/webview',
parameters: {'url': i.origText, 'type': 'url', 'pageTitle': ''},
);
},
child: Text(
i.text,
style: authorStyle,
), ),
), );
), spanChilds.add(
); WidgetSpan(
} alignment: PlaceholderAlignment.middle,
// 投票 child: GestureDetector(
if (i.type == 'RICH_TEXT_NODE_TYPE_VOTE') { onTap: () {
spanChilds.add( Get.toNamed(
WidgetSpan( '/webview',
alignment: PlaceholderAlignment.middle, parameters: {
child: GestureDetector( 'url': i.origText,
onTap: () { 'type': 'url',
String dynamicId = item.basic['comment_id_str']; 'pageTitle': ''
Get.toNamed( },
'/webview', );
parameters: {
'url':
'https://t.bilibili.com/vote/h5/index/#/result?vote_id=${i.rid}&dynamic_id=$dynamicId&isWeb=1',
'type': 'vote',
'pageTitle': '投票'
}, },
); child: Text(
}, i.text,
child: Text( style: authorStyle,
'投票:${i.text}', ),
style: authorStyle, ),
), ),
), );
), }
); // 投票
} if (i.type == 'RICH_TEXT_NODE_TYPE_VOTE') {
// 表情 spanChilds.add(
if (i.type == 'RICH_TEXT_NODE_TYPE_EMOJI') { WidgetSpan(
spanChilds.add( alignment: PlaceholderAlignment.middle,
WidgetSpan( child: GestureDetector(
child: NetworkImgLayer( onTap: () {
src: i.emoji.iconUrl, String dynamicId = item.basic['comment_id_str'];
type: 'emote', Get.toNamed(
width: i.emoji.size * 20, '/webview',
height: i.emoji.size * 20, parameters: {
), 'url':
), 'https://t.bilibili.com/vote/h5/index/#/result?vote_id=${i.rid}&dynamic_id=$dynamicId&isWeb=1',
); 'type': 'vote',
} 'pageTitle': '投票'
// 抽奖 },
if (i.type == 'RICH_TEXT_NODE_TYPE_LOTTERY') { );
spanChilds.add( },
WidgetSpan( child: Text(
alignment: PlaceholderAlignment.middle, '投票:${i.text}',
child: Icon( style: authorStyle,
Icons.redeem_rounded, ),
size: 16, ),
color: Theme.of(context).colorScheme.primary,
),
),
);
spanChilds.add(
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
onTap: () {},
child: Text(
'${i.origText} ',
style: authorStyle,
), ),
), );
), }
); // 表情
} if (i.type == 'RICH_TEXT_NODE_TYPE_EMOJI') {
spanChilds.add(
WidgetSpan(
child: NetworkImgLayer(
src: i.emoji.iconUrl,
type: 'emote',
width: i.emoji.size * 20,
height: i.emoji.size * 20,
),
),
);
}
// 抽奖
if (i.type == 'RICH_TEXT_NODE_TYPE_LOTTERY') {
spanChilds.add(
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Icon(
Icons.redeem_rounded,
size: 16,
color: Theme.of(context).colorScheme.primary,
),
),
);
spanChilds.add(
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
onTap: () {},
child: Text(
'${i.origText} ',
style: authorStyle,
),
),
),
);
}
/// TODO 商品 /// TODO 商品
if (i.type == 'RICH_TEXT_NODE_TYPE_GOODS') { if (i.type == 'RICH_TEXT_NODE_TYPE_GOODS') {
spanChilds.add( spanChilds.add(
WidgetSpan( WidgetSpan(
alignment: PlaceholderAlignment.middle, alignment: PlaceholderAlignment.middle,
child: Icon( child: Icon(
Icons.shopping_bag_outlined, Icons.shopping_bag_outlined,
size: 16, size: 16,
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
), ),
),
);
spanChilds.add(
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
onTap: () {},
child: Text(
'${i.text} ',
style: authorStyle,
), ),
), );
), spanChilds.add(
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: GestureDetector(
onTap: () {},
child: Text(
'${i.text} ',
style: authorStyle,
),
),
),
);
}
}
if (contentType == 'major' &&
item.modules.moduleDynamic.major.opus.pics.isNotEmpty) {
// 图片可能跟其他widget重复渲染
print('有图片');
List<OpusPicsModel> pics = item.modules.moduleDynamic.major.opus.pics;
int len = pics.length;
List picList = [];
if (len == 1) {
OpusPicsModel pictureItem = pics.first;
picList.add(pictureItem.url);
spanChilds.add(const TextSpan(text: '\n'));
spanChilds.add(
WidgetSpan(
child: LayoutBuilder(
builder: (context, BoxConstraints box) {
return GestureDetector(
onTap: () {
Get.toNamed('/preview',
arguments: {'initialPage': 0, 'imgList': picList});
},
child: Padding(
padding: const EdgeInsets.only(top: 4),
child: NetworkImgLayer(
src: pictureItem.url,
width: box.maxWidth / 2,
height: box.maxWidth *
0.5 *
pictureItem.height! /
pictureItem.width!,
),
),
);
},
),
),
);
}
if (len > 1) {
List<Widget> list = [];
for (var i = 0; i < len; i++) {
picList.add(pics[i].url);
list.add(
LayoutBuilder(
builder: (context, BoxConstraints box) {
return GestureDetector(
onTap: () {
Get.toNamed('/preview',
arguments: {'initialPage': i, 'imgList': picList});
},
child: NetworkImgLayer(
src: pics[i].url,
width: box.maxWidth,
height: box.maxWidth,
),
);
},
),
);
}
spanChilds.add(
WidgetSpan(
child: LayoutBuilder(
builder: (context, BoxConstraints box) {
double maxWidth = box.maxWidth;
double crossCount = len < 3 ? 2 : 3;
double height = maxWidth /
crossCount *
(len % crossCount == 0
? len ~/ crossCount
: len ~/ crossCount + 1) +
6;
return Container(
padding: const EdgeInsets.only(top: 6),
height: height,
child: GridView.count(
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: crossCount.toInt(),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
childAspectRatio: 1,
children: list,
),
);
},
),
),
);
}
// spanChilds.add(
// WidgetSpan(
// child: NetworkImgLayer(
// src: pics.first.url,
// type: 'emote',
// width: 100,
// height: 200,
// ),
// ),
// );
}
return TextSpan(
children: spanChilds,
); );
} }
} catch (err) {
print('❌rich_node_panel err: $err');
return spacer;
} }
return TextSpan( }
children: spanChilds,
); class _VerticalSpaceSpan extends WidgetSpan {
_VerticalSpaceSpan(double height)
: super(child: SizedBox(height: height, width: double.infinity));
} }

View File

@ -57,20 +57,21 @@ Widget videoSeasonWidget(item, context, type, {floor = 1}) {
const SizedBox(height: 6), const SizedBox(height: 6),
], ],
// const SizedBox(height: 4), // const SizedBox(height: 4),
if (item.modules.moduleDynamic.topic != null) ...[ /// fix #话题跟content重复
Padding( // if (item.modules.moduleDynamic.topic != null) ...[
padding: floor == 2 // Padding(
? EdgeInsets.zero // padding: floor == 2
: const EdgeInsets.only(left: 12, right: 12), // ? EdgeInsets.zero
child: GestureDetector( // : const EdgeInsets.only(left: 12, right: 12),
child: Text( // child: GestureDetector(
'#${item.modules.moduleDynamic.topic.name}', // child: Text(
style: authorStyle, // '#${item.modules.moduleDynamic.topic.name}',
), // style: authorStyle,
), // ),
), // ),
const SizedBox(height: 6), // ),
], // const SizedBox(height: 6),
// ],
if (floor == 2 && item.modules.moduleDynamic.desc != null) ...[ if (floor == 2 && item.modules.moduleDynamic.desc != null) ...[
Text.rich(richNode(item, context)), Text.rich(richNode(item, context)),
const SizedBox(height: 6), const SizedBox(height: 6),