Tencent / Tencent/tdesign-flutter

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

Open
#875 1 comment 0 reactions 0 assignees View on GitHub

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.