Tencent / Tencent/tdesign-flutter
[TDInput] 页面重组时会导致rightbutton选项里面的组件消失
Nobody has claimed this yet.
- Dominant language
- Dart
- Stars
- 1.2k
- Forks
- 182
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 88
Description
tdesign-flutter 版本
0.2.7
重现链接
https://github.com/user-attachments/assets/9b5ed904-ee41-4792-99b6-e14ce7b8ab55
重现步骤/代码
screen页面
class BookFormScreen extends GetView<BookFormController> {
const BookFormScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: TDNavBar(
title: "添加数据",
onBack: () {
Get.back();
},
),
body: Obx(
() => Container(
padding: EdgeInsets.all(16),
child: Column(
spacing: 16,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTitle(context),
_buildSourceSelection(context),
_buildForm(context),
_buildActionButton(context),
],
),
),
),
);
}
Widget _buildTitle(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TDText("选择导入源"),
TDText(
"请选择您想要导入书籍的来源方式",
textColor: TDTheme.of(context).fontGyColor3,
font: TDTheme.of(context).fontBodySmall,
),
],
);
}
Widget _buildSourceSelection(BuildContext context) {
return Expanded(
child: SingleChildScrollView(
child: Column(
children: [
_addDialogItem(
context: context,
icon: Icons.web,
title: "来自网页",
isSelected: controller.source.value == BookFormSources.web,
description: "从网页解析后,下载书籍到本地",
onTap: () {
controller.source.value = BookFormSources.web;
},
),
_addDialogItem(
context: context,
icon: Icons.archive,
title: "来自压缩包",
isSelected: controller.source.value == BookFormSources.archive,
description: "从压缩包中提取书籍到本地",
onTap: () {
controller.source.value = BookFormSources.archive;
},
),
_addDialogItem(
context: context,
icon: Icons.archive_sharp,
title: "来自批量压缩包",
isSelected:
controller.source.value == BookFormSources.batchArchive,
description: "选择文件夹,从文件夹里面多个压缩包中提取书籍到本地",
onTap: () {
controller.source.value = BookFormSources.batchArchive;
},
),
_addDialogItem(
context: context,
icon: Icons.picture_as_pdf,
title: "来自PDF文件",
isSelected: controller.source.value == BookFormSources.pdf,
description: "从PDF文件中提取书籍到本地",
onTap: () {
controller.source.value = BookFormSources.pdf;
},
),
],
),
),
);
}
Widget _buildForm(BuildContext context) {
switch (controller.source.value) {
case BookFormSources.web:
return TDInput(
controller: controller.webUrlController,
hintText: "请输入书籍网址",
);
case BookFormSources.archive:
return TDInput(
controller: controller.filePathController,
hintText: "请选择压缩包文件",
readOnly: true,
rightBtn: TDButton(
text: "选择文件",
theme: TDButtonTheme.primary,
onTap: () {
controller.pickArchiveFile();
},
),
);
case BookFormSources.batchArchive:
return TDInput(
controller: controller.folderPathController,
hintText: "请选择包含压缩包的文件夹",
readOnly: true,
rightBtn: TDButton(
text: "选择文件夹",
theme: TDButtonTheme.primary,
onTap: () {
controller.pickFolder();
},
),
);
case BookFormSources.pdf:
return TDInput(
controller: controller.pdfPathController,
hintText: "请选择PDF文件",
readOnly: true,
rightBtn: TDButton(
text: "选择文件",
theme: TDButtonTheme.primary,
onTap: () {
controller.pickPdf();
},
),
);
default:
return SizedBox.shrink();
}
}
Widget _buildActionButton(BuildContext context) {
return TDButton(
text: "添加书籍",
width: double.infinity,
theme: TDButtonTheme.primary,
onTap: () {
controller.submitForm();
},
);
}
Widget _addDialogItem({
required BuildContext context,
required IconData icon,
required String title,
required String description,
required bool isSelected,
required VoidCallback onTap,
}) {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(8),
hoverColor: TDTheme.of(context).fontGyColor4.withValues(alpha: 0.05),
splashColor: TDTheme.of(
context,
).brandNormalColor.withValues(alpha: 0.1),
highlightColor: TDTheme.of(
context,
).brandNormalColor.withValues(alpha: 0.05),
child: Container(
decoration: BoxDecoration(
color: isSelected
? TDTheme.of(context).fontGyColor4.withValues(alpha: 0.1)
: Colors.transparent,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isSelected
? TDTheme.of(context).fontGyColor4
: Colors.transparent,
),
),
padding: EdgeInsets.all(16),
child: Row(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: TDTheme.of(
context,
).fontGyColor4.withValues(alpha: 0.1),
),
padding: EdgeInsets.all(16),
child: Icon(icon),
),
SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TDText(title),
TDText(
description,
overflow: TextOverflow.clip,
textColor: TDTheme.of(context).fontGyColor3,
font: TDTheme.of(context).fontBodySmall,
),
],
),
),
],
),
),
),
);
}
}
controller控制器
class BookFormController extends GetxController {
final source = Rxn<BookFormSources>(null);
final submitFormState = Rx<RequestState<void>>(Idle());
final webUrlController = TextEditingController();
final filePathController = TextEditingController();
final folderPathController = TextEditingController();
final pdfPathController = TextEditingController();
Future<void> submitForm() async {
final sourceValue = source.value;
if (sourceValue?.value == null) {
ToastService.showError("请选择书籍来源");
return;
}
if (sourceValue == BookFormSources.web) {
final url = webUrlController.text;
if (url.toString().trim().isEmpty) {
ToastService.showError("请输入网页地址");
return;
}
// 然后打开解析页面
Get.offAndToNamed(AppRoute.parseWeb, arguments: url.toString());
}
if (sourceValue == BookFormSources.archive) {
final file = filePathController.text;
if (file.toString().trim().isEmpty) {
ToastService.showError("请选择压缩包文件");
return;
}
Get.offAndToNamed(
AppRoute.parseArchiveSingle,
arguments: file.toString(),
);
}
if (sourceValue == BookFormSources.batchArchive) {
final folder = folderPathController.text;
if (folder.toString().trim().isEmpty) {
ToastService.showError("请选择压缩包文件夹");
return;
}
Get.offAndToNamed(
AppRoute.parseArchiveBatch,
arguments: folder.toString(),
);
}
if (sourceValue == BookFormSources.pdf) {
final pdf = pdfPathController.text;
if (pdf.toString().trim().isEmpty) {
ToastService.showError("请选择PDF文件");
return;
}
Get.offAndToNamed(AppRoute.parsePdf, arguments: {'path': pdf.toString()});
}
}
Future<void> pickArchiveFile() async {
final result = await PickFileUtil.pickerFile(
type: FileType.custom,
allowedExtensions: ['zip', 'rar', '7z', 'cbz', 'cbr'],
);
if (result != null && result.files.isNotEmpty) {
final filePath = result.files.first.path;
if (filePath != null) {
filePathController.text = filePath;
}
}
}
Future<void> pickFolder() async {
final folderPath = await PickFileUtil.pickDirectory();
if (folderPath != null) {
folderPathController.text = folderPath;
}
}
Future<void> pickPdf() async {
final path = await PdfPicker.pickPdf();
if (path != null) {
pdfPathController.text = path;
}
}
}
enum BookFormSources {
web("web", "网页"),
archive("archive", "压缩包"),
batchArchive("batch_archive", "批量压缩包"),
pdf("pdf", "PDF");
final String value;
final String desc;
const BookFormSources(this.value, this.desc);
}
具体重现方法查看视频和代码,当我页面组件在消失并重现后,rightbuttom会消失,重复操作后又会出现,但设置了clearable为false时候不会出现
期望结果
页面重组后rightbutton属性里面的组件不会消失
实际结果
页面重组后rightbutton属性里面的组件会消失
Flutter版本
3.38.7
设备与机型信息
pixel6
系统版本
android 15
补充说明
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the TDInput implementation and its rightBtn and clearable handling, then reproduce the issue with the provided BookFormScreen and controller. Compare rebuilds with clearable enabled and disabled. Done means the right button remains visible after the page components are removed and rebuilt.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart, flutter
- Domain
- frontend, mobile
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100