Skip to content

[TDInput] 页面重组时会导致rightbutton选项里面的组件消失 #875

@dorkytiger

Description

@dorkytiger

tdesign-flutter 版本

0.2.7

重现链接

SVID_20260203_093548_1.mp4

重现步骤/代码

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions