news 2026/9/23 12:40:32

PaddleOCR 2.0实战指南:从文本检测到部署避坑全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PaddleOCR 2.0实战指南:从文本检测到部署避坑全解析

简介:PaddleOCR 2.0 是基于飞桨深度学习框架的中英文光学字符识别工具,面向需要把图片、截图或扫描件中的文字批量提取为可编辑文本的办公人员、开发者和内容整理者。它支持本地单机运行,无需联网即可完成延时截图识别、图片旋转与镜像识别、批量图片文件列表识别;识别过程可在 CPU 环境下完成,并提供识别区域坐标查看功能,便于对输出结果做位置核验或二次处理。资源包以 zip 格式发布,整体约 98.84MB,因上传信息未给出文件数量与类型明细,压缩包内具体目录结构和所需依赖需在下载后自行查看。目前已有 202 人学习下载,适合有离线 OCR、批量文档数字化、截图文字采集或轻量级文字识别需求的用户直接使用,也可在其基础上调用飞桨 API 进行定制化扩展。

1. PaddleOCR 2.0:一张报表照片,最快多久变成能用的文本?

接到过不止一次这类需求:财务说每个月要对几百张银行回单做二次核验,实习生一张张手敲;仓库说发货单拍照存档了,但出了问题要翻图,眼睛都要瞎了;还有做档案数字化的,一堆年代久远、带着印章和倾斜角度的扫描件要转成可检索文本。我大部分时候推荐的第一套方案还是 PaddleOCR 2.0。它不是最新版本,但它的稳定性和资料完善程度,让它在这类真实脏数据场景里表现得比很多商业 OCR 服务还靠谱——不花钱、能离线跑、三个模型串起来按需替换,这套设计在 2020 年那会儿就是国内开源 OCR 工具里最完整的,放到现在,作为生产环境基线依然说得过去。这篇文章想讲清楚这套东西怎么用、模型怎么选、参数怎么调,以及那些最容易翻车的地方。

适合谁看:刚接触 OCR 想在一周内跑通识别流程的开发者,已经在用但踩过乱码、打包失败、精度上不去的坑的从业者。适合把 PaddleOCR 2.0 当作离线 OCR 基线的方案选型人。不适合指望一行代码解决全部识别问题的场景,以及完全不做预处理就要识别那种亮度极低、形变极大的拍照件的需求。这套工具救不了那种图,但它会让你清楚问题出在哪。

2. 检测、方向分类、识别三段式:一套 OCR 为什么非要三个模型分开跑

PaddleOCR 2.0 的核心不是单个模型,而是一条流水线:检测模型先从原图里找出所有文字区域并画框,方向分类器判断这些区域是否需要旋转,识别模型把剪裁出来的小图转成文本。三个模型各干各的活,好处是任一段出问题可以单独换模型或调参数,不用整个重训。坏处是每段都有各自的坑,误差会累积。

2.1 DB 文本检测:可微二值化让边界框回归变得可直接训练

检测模型用的是 DB(Differentiable Binarization),和传统分割后做后处理找文本行的方案不同,它把二值化这一步做成了网络的一部分,这样训练的时候梯度可以直接传到分割图上,收敛明显更快。实际效果上,对倾斜文本、弯曲文本的检测能力比前一代 CTPN 那种基于锚点的方案好很多。在 PaddleOCR 2.0 里,默认的检测模型是 ch_ppocr_mobile_v2.0_det,移动端模型体积小,CPU 上速度不错;追求精度就换 server 版本。

跑检测这一步,代码只需要几行:

import paddleocr ocr = paddleocr.PaddleOCR( det_model_dir="inference/ch_ppocr_mobile_v2.0_det", rec_model_dir="inference/ch_ppocr_mobile_v2.0_rec", cls_model_dir="inference/ch_ppocr_mobile_v2.0_cls", use_angle_cls=True, lang="ch", ) result = ocr.ocr("scan.jpg", cls=True)

代码逻辑:构造 PaddleOCR 对象时传入三个模型目录,use_angle_cls决定是否启用方向分类器,调用ocr方法时传入图片路径和cls=True让方向分类参与推理。result是一个两层嵌套列表,外层每个元素对应一个检测到的文本框,内层第一个元素是四个角点坐标,第二个元素是识别文本和置信度。

参数说明:det_model_dir不填会自动下载默认模型,但生产环境建议手动下载后指定本地路径,避免每次运行都做网络检查;use_angle_cls在 2.0 中默认是 False,但中文场景里 90 度和 180 度的扫描件很常见,建议显式打开。

2.2 方向分类器:四分类解决被转着拍照的文本,不是可选项

好多第一次用 PaddleOCR 的人会问:都做检测了,旋转文本检测框不也跟着转吗,为什么还要单独转图片?因为识别模型训练时见的文本大多是水平方向,检测框虽然框住了,但里面的文字若旋转了 90 度或 180 度,识别模型输出基本是乱码。方向分类器做的事是判断裁剪出来的这块区域属于 0°/90°/180°/270° 中的哪一类,然后自动转正。

这个模型很小,ch_ppocr_mobile_v2.0_cls 在 CPU 上单张图耗时约几毫秒,性价比极高。强烈建议日常使用都开着:拍照件里面手机拿歪的情况太常见了,有它兜底,识别准确率能提升不少。

2.3 CRNN 识别网络:卷积提特征,循环网络串序列,CTC 对齐文本

识别模型是典型的 CRNN 结构:卷积层提取空间特征,输出一组特征序列;双向 LSTM 建模序列上下文;最后由 CTC(Connectionist Temporal Classification)解码出文本序列。CTC 的好处是不需要逐字符标注,只要知道整行文本的内容即可训练。

PaddleOCR 2.0 里识别模型有两个字典路径在配置里非常重要:rec_char_dict_path默认指向 ppocr/utils/ppocr_keys_v1.txt,这个文件包含了中文字符全集。如果你自己训练数据里只有几百个字,建议自定义一个精简字典,否则模型预测时永远从全量字符里挑,误判率会高。

2.4 最小跑通命令:一行代码验证环境,避免一上来就被依赖卡死

很多教程会让你先下载模型再写 Python 脚本,但最容易排查环境问题的方式是用命令行直接验证:

paddleocr --image_dir demo.jpg --use_angle_cls true --lang ch

代码逻辑:这里--image_dir指定待识别图片,--use_angle_cls true开启方向分类,--lang ch选择中文模型。第一次运行会自动下载模型,网络状态正常的情况下几分钟搞定。如果这条命令刷出识别结果,说明 PaddleOCR 2.0 的环境是通的;如果报错,大概率是依赖问题,而不是模型下载问题。

参数说明:--lang可选 ch、en、japan、korean 等,选择对应语种的默认模型;--use_angle_cls是布尔开关,命令行传字符串 true/false。跑通后,再用 Python API 做后续定制。

3. 模型选型与数据集准备:预训练模型怎么挑,训练自己的子弹库

PaddleOCR 2.0 的一大价值在于开箱即用的预训练模型丰富。但真实业务情况是:通用模型在自己领域的印刷体上可能到 95% 以上,一碰到票据的异形字体、手写体、印章叠字,立刻掉到 80% 以下。这时候就得考虑在预设模型基础上微调,而不是从零训练。从零训练一张 GPU 要几天,微调只需要几小时,性价比天差地别。

3.1 预训练模型怎么选:中文移动版、服务器版,还是多语言

需要做这个选择的场景一般是确定了要用 PaddleOCR 但版本里模型太多,不知道怎么选。我一般给出的参考维度是部署资源、精度需求和语言覆盖:

模型集合体积CPU 推理耗时适用场景
mobile 系列约 3-5 MB约 50-100 ms/张端侧、CPU 服务、高并发
server 系列约 80-110 MB约 200-400 ms/张GPU 服务、精度优先
multilingual约 80 MB约 300 ms/张多语言混合、跨国业务

服务部署在 GPU 上,可以无脑用 server 系列;CPU 上追求响应时间优先 mobile。混合语言场景比如中英文发票混排,用lang="ch"即可,中文模型本身包含英文字符,不需要切到 en。

3.2 用 PPOCRLabel 标注:这步决定了你能训练出什么水平的模型

标注工具是 PaddleOCR 系列里很关键的配套:PPOCRLabel。它是一个半自动标注工具,先用预训练模型对图片做预标注,人工复核修正后导出训练数据。省去了自己写标注界面的时间。

pip install PPOCRLabel PPOCRLabel --lang ch

代码逻辑:--lang ch让界面显示中文。标注界面里按快捷键框选文本区域、输入对应文字,保存后每个图片同一目录下会生成同名的 json 文件。标注完成后点“导出标记结果”,会生成一个train.txt——这是训练要用的核心索引文件,每行格式是“图片路径 标注框坐标和文本”,坐标格式是[[x1,y1],[x2,y2],[x3,y3],[x4,y4]], "文本内容"

参数说明:如果图片很大且文字密集,标注时会累且容易错。建议先把图片做切分或压缩到最长边 2000 像素以内,保留清晰度同时降低标注负担。标注的框要贴合文本行,不要框住两行文字,训练效果会差很多。

3.3 检测模型微调:五到十张图也能逼近极佳效果

很多人以为微调要准备几千张图,实际 PaddleOCR 2.0 的检测模型微调从几张图开始就能有明显提升,前提是这几张图覆盖了目标场景的版式变化。比如只识别回单类图片,收集大约 50 张不同银行、不同亮度的回单即可起步。

# 训练检测模型(基于 mobile det 预训练权重) python tools/train.py -c configs/det/ch_ppocr_v2.0/ch_det_mv3_db_v2.0.yml \ -o Global.pretrain_weights=./pretrain_models/ch_ppocr_mobile_v2.0_det_train/best_accuracy \ Global.save_model_dir=./output/det_ft

代码逻辑:命令加载检测模型配置文件,用-o参数覆盖配置里的预训练权重路径和保存路径。训练时会读取上一步标注生成的train.txteval.txt,配置里通过Train.dataset.data_dirlabel_file_list指定,需要自行编辑配置文件。

参数说明:检测模型训练的关键参数是Train.loader.batch_size_per_card,内存不够时从默认值往下降,直到不 OOM;Global.epoch_num微调场景设 100 差不多,多了容易过拟合标注误差。学习率optimizer.lr微调时用默认值,不要自己调大。

3.4 识别模型微调:几个常见参数与字典路径的对应关系

识别模型微调的命令结构类似,但配置和参数不同:

# 训练识别模型 python tools/train.py -c configs/rec/ch_ppocr_v2.0/ch_PP-OCRv2_rec.yml \ -o Global.pretrain_weights=./pretrain_models/ch_ppocr_mobile_v2.0_rec_train/best_accuracy \ Global.save_model_dir=./output/rec_ft \ Character.dict_path=./ppocr/utils/dict/ppocr_keys_v1.txt \ Train.dataset.label_file_list=["./train_data/rec_train.txt"]

代码逻辑:识别模型训练用类似结构,但注意多了Character.dict_path参数。对应识别标注文件每行格式为“图片路径\t文本内容”,注意是制表符分隔,且文本内容用双引号包裹,实际文本里含逗号也不影响。

参数说明:rec_batch_num在推理时是很关键的性能参数,训练时batch_size则决定 GPU 利用率。如果训练数据只有千级规模,epoch_num调到 50 就好,识别模型收敛快,训练太久会记住标注噪声。

提示:训练识别模型前,检查标注文本里最容易出现的符号,比如“()”和“()”是否混用。PaddleOCR 的 dict 里两者是不同字符,会直接影响训练时标签匹配,识别结果会不稳定。

4. 实战避坑:乱码、打包、版本混用、CPU 慢的踩坑记录

这一章全是实操里最容易卡住人的地方。每个问题都按“现象→原因→解决”的路径拆解。这些坑是我在多个项目里真实处理过的,不绕弯子直接说结论。

4.1 识别乱码:中文输出一堆“锟斤拷”或问号,先查解码再查字体

现象:PaddleOCR 2.0 识别中文图,返回的文本在终端里显示为“锟斤拷”或“口口口”。模型本身识别是对的,问题出在显示或存储环节。

原因:Windows 终端默认编码是 GBK,Python 输出 UTF-8 字符串时没有被正确转码;另一种情况是存储到 CSV 文件时没有指定 UTF-8 with BOM,Excel 打开乱码。跟 OCR 模型本身没关系,但很多人误以为识别精度不行。

解决:终端里先执行chcp 65001切到 UTF-8;输出到文件时指定编码:

import csv with open("result.csv", "w", newline="", encoding="utf-8-sig") as f: writer = csv.writer(f) for line in result: writer.writerow(line)

代码逻辑:utf-8-sig编码会在文件开头写入 BOM,Excel 识别这个标记后按 UTF-8 解析,不会乱码。这是处理 OCR 结果落地最省心的方式。

4.2 pyinstaller 打包 PaddleOCR:环境跑得通,打包后双击就闪退

现象:本地 Python 脚本跑得好好的,用 pyinstaller 打成 exe 复制到别的机器上,双击后窗口一闪而过,或者报ModuleNotFoundError: No module named 'paddleocr'

原因:pyinstaller 打包时没能收集全 PaddleOCR 的动态依赖和子模块。PaddleOCR 内部按需 import 的模块很多,静态分析抓不全。

解决:打包时指定--hidden-import,把关键子模块手动加入:

pyinstaller -F ocr_app.py \ --hidden-import=paddleocr \ --hidden-import=paddle \ --hidden-import=shapely \ --hidden-import=skimage \ --hidden-import=imghdr \ --collect-all paddleocr

代码逻辑:-F打包成单文件,--collect-all paddleocr把 paddleocr 包里的所有子模块和数据文件都收进来;--hidden-import逐个补上运行时才导入的依赖。打包后体积会到 200 MB 以上,这是正常现象。

参数说明:拍脑袋加依赖项是不可靠的,稳妥做法是先在打包机上跑一次被打包脚本,把报错里缺哪个模块名就加哪个,迭代个两三轮基本能稳定。注意 pyinstaller 的版本和 Python 版本要对应,Windows 上 Python 3.8/3.9 和 pyinstaller 5.x 组合比较稳。

4.3 PaddleOCR 2.0 和 3.x 混用:接口不兼容不是玄学是必然

现象:有人项目里既有旧脚本用的 PaddleOCR 2.x,又 pip 安装了新版今天发布的 PaddleOCR 3.x(类似paddleocr 3.x这种大版本号),运行时直接报TypeErrorAttributeError,因为接口变了。

原因:PaddleOCR 从 2.x 到 3.x 改了 API,比如ocr()方法返回格式变了,--use_angle_cls参数名变了,模型目录结构变了。新旧版本装在同一环境里,import paddleocr实际导入的是先装的那个,脚本还不知道。

解决:生产环境建议用虚拟环境锁版本,这是最稳的做法:

python -m venv ocr_env source ocr_env/bin/activate # Windows 下是 ocr_env\Scripts\activate pip install paddlepaddle==2.3.2 paddleocr==2.7.0

代码逻辑:虚拟环境隔离了包依赖,pip install paddleocr==2.7.0明确指定版本。2.0 系列推荐 2.7.0,这个版本是 2.x 里最成熟的一版。注意paddlepaddlepaddleocr要配套,paddleocr 2.7.0 配 paddlepaddle 2.3.x 是经过大量验证的组合。

4.4 CPU 推理慢到无法接受:先看这几个参数,别急着上 GPU

现象:CPU 上跑一张高清图,检测加识别花了两三秒,业务要求 200 毫秒内返回,直接换 GPU 预算下不来。

原因与解决:

  • 原因一:检测模型处理全尺寸图,高清图边长 4000 像素,检测阶段就耗时巨大。解决:设det_limit_side_len,让检测的输入最长边被限制:
ocr = paddleocr.PaddleOCR( det_limit_side_len=960, det_db_thresh=0.3, det_db_box_thresh=0.5, use_angle_cls=True, )

代码逻辑:det_limit_side_len=960把检测输入最长边限制到 960 像素,等比例缩放。短边不会被拉伸,识别精度基本不损失,因为文字区域被放大后检测模型反而更稳。

  • 原因二:识别阶段默认rec_batch_num=6,但实际图片里文本行只有一两行,等于白白把 batch 开大,每个 batch 都等最慢的那张。解决:文本行少的场景降低 batch:
python tools/infer/predict_system.py \ --image_dir=test.jpg \ --det_limit_side_len=960 \ --rec_batch_num=2

参数说明:rec_batch_num直接影响识别速度,CPU 上从 6 降到 2,单图识别耗时可减少 30% 以上。文本行多的场景不要降太多,否则 batch 太小,识别阶段无法并行反而更慢。

5. 部署到真实业务:从单张图识别到结构化返回的完整链路

跑通 demo 之后,绕不开的问题就是怎么把它接到自己的业务流程里:输入不定是单张图,可能是图片流;输出不定要文本,可能要结构化字段;调用者可能是别的服务,要过 HTTP 接口;偶尔还会遇到几个模型都救不了的脏图,要有降级方案。这一章照着顺序搭,基本可以覆盖日常业务的需求。

5.1 从单张图片到批量文件:批处理的数据读法与结果合并

先用最直接的方式——读取文件夹里所有待识别图片,逐张处理,结果汇总到一个结构里:

from pathlib import Path import json img_dir = Path("./receipts") ocr_engine = paddleocr.PaddleOCR(use_angle_cls=True, lang="ch") all_results = {} for img_path in sorted(img_dir.glob("*.jpg")): result = ocr_engine.ocr(str(img_path), cls=True) all_results[img_path.stem] = result with open("ocr_batch_result.json", "w", encoding="utf-8") as f: json.dump(all_results, f, ensure_ascii=False, indent=2)

代码逻辑:用Path.glob遍历目录下所有 jpg 文件,逐张识别后以文件名做 key 存进字典,最后用json.dump输出。ensure_ascii=False确保中文字符直接显示而不是转成 unicode 转义。

参数说明:批量场景里 PaddleOCR 对象只初始化一次,不要在循环里重复创建。每张图片的推理是独立的,多进程并行处理时注意同一进程内创建独立 PaddleOCR 实例,进程间共享内存中的模型参数会有线程安全问题。

5.2 精度评估方法:B 站网友喊“好用”不顶用,要自己算指标

OCR 项目的验收不能只靠肉眼和感觉,要有量化指标。否则模型改一版,你说更好了,对方说没感觉,互相扯皮。业界通用的是精确率(Precision)、召回率(Recall)和 F1 分数,在检测任务里对应文本框是否框对,识别任务里对应文本内容是否一致。

def eval_recognition(gt_texts, pred_texts): correct = 0 for gt, pred in zip(gt_texts, pred_texts): if gt.strip() == pred.strip(): correct += 1 precision = correct / len(pred_texts) recall = correct / len(gt_texts) f1 = 2 * precision * recall / (precision + recall) return precision, recall, f1

代码逻辑:精确率是识别对的除以识别出来的总数,召回率是识别对的除以应该识别的总数。这里假设 gt 和 pred 按顺序一一对应,真实场景里检测框数量和顺序不一定对得上,需要做框的匹配,比对交并比大于阈值就认为匹配上,再做文本比对。

5.3 用 FastAPI 给识别模型包一层 HTTP 服务

生产服务大概率需要对外提供 HTTP 接口,而不是把模型直接暴露给调用方。FastAPI 写起来轻量,配合 PaddleOCR 的同步推理逻辑,足够支撑中小流量场景。

from fastapi import FastAPI, UploadFile app = FastAPI() ocr_engine = paddleocr.PaddleOCR(use_angle_cls=True, lang="ch") @app.post("/ocr") async def ocr_image(file: UploadFile): img_bytes = await file.read() with open("temp.jpg", "wb") as f: f.write(img_bytes) result = ocr_engine.ocr("temp.jpg", cls=True) return {"result": result}

代码逻辑:接口接收上传的图片文件,保存到临时文件后调用 PaddleOCR 推理,结果以 JSON 返回。PaddleOCR 引擎在模块导入时初始化一次,所有请求共享这个实例,避免每次请求都加载模型。

参数说明:await file.read()在内存充足时没问题,但如果图片很大且并发高,建议配限制上传大小。临时文件命名用 uuid 替代固定名,防止并发时多个请求写同一个文件互相覆盖。

6. 进阶习惯:二次识别的效率提升比参数调优更值钱

PaddleOCR 2.0 在单据类识别场景里,很多看起来是精度问题,实际上是流程设计问题。我在几个项目里验证过,一个预处理习惯有时候比换 server 模型提升还大:识别前先手动放大文字区域。拍照件里的文字普遍在 20-30 像素高,而识别模型训练时见到的是 32 像素以上的文字。用小图识别,特征模糊,模型只能靠上下文猜,自然容易错。所以我在批量识别前会用 OpenCV 的关系做一次插值放大:

import cv2 img = cv2.imread("scan.jpg") scale = max(1.0, 32 / min(img.shape[:2])) img_resized = cv2.resize(img, None, fx=scale, fy=scale, interpolation=cv2.INTER_CUBIC) cv2.imwrite("scan_upscaled.jpg", img_resized)

代码逻辑:计算图片短边和 32 的比例,如果短边不足 32 就放大到至少 32,再用三次插值做缩放。这个处理对提升低分辨率拍照件的识别成功率非常明显。

还有一个被忽略的做法是降低识别字典里的候选字符。默认字典是常用中文字符,如果你的业务只需要数字和少量字母,把rec_char_dict_path指向一个只包含数字和字母的字典文件,模型预测时输出空间大幅缩小,识别准确率能直接提升 2-3 个点,误识别的概率也明显降低。这两个手段的效果,在发票、快递单、车牌这种结构化数据上,比调 detection 的阈值还要明显。

另一个我习惯保留的验证动作是:拿一批新图跑完识别后,把置信度低于 0.8 的结果单独拉出来看,分析原因再决定要不要补充训练数据。PaddleOCR 2.0 返回的置信度分布是判断模型有没有过拟合或者数据分布漂移的好抓手。我见过很多团队花了几天时间调模型,最后发现置信度低的样本集中在某种背景色上,用颜色过滤就解决了,压根不需要训练。不要上来就训,先分析输出里的低分样本,往往能省下好几天的功夫。这套工具的工程属性很强,跑通了框架之后,能不能发挥价值,就看这些细节。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 12:39:52

Windows下cuDNN 8.8.0与CUDA 11.x精准安装指南

简介:本资源为 NVIDIA cuDNN 8.8.0 for Windows x64 官方预编译库包,专为使用 CUDA 11.x 版本进行深度学习开发的 Windows 开发者设计,适用于 PyTorch、TensorFlow 等框架的 GPU 加速环境部署与本地调试。压缩包共含 31 个文件,涵…

作者头像 李华
网站建设 2026/9/23 12:39:00

Copula与变分贝叶斯在几何误差建模中的MATLAB实践

简介:这份Matlab代码包面向机器学习、统计推断方向的研究者与进阶学习者,核心复现论文“Copula Variational Bayes inference via information geometry”中的算法,目标是在数据存在非线性、非对称依赖关系时,用Copula构造灵活的变…

作者头像 李华
网站建设 2026/9/23 12:38:15

SWAT+模型全套教程|原理、数据制备、建模操作、结果分析及案例实战

当前,水资源短缺、洪旱灾害频发、水文情势变化复杂等问题,已成为制约社会经济与生态可持续发展的重要因素。国内外研究表明,受全球气候变化与人类活动加剧的双重影响,流域水文过程发生了显著变化,水资源时空分布不均、…

作者头像 李华
网站建设 2026/9/23 12:37:06

攻防实战 | 没一句废话的攻防实战

攻防实战 | 没一句废话的攻防实战演练 信息收集部分为,针对给定的单位进行二级三级单位,全资控股存续在业公司的子主域名进行收集,筛选过后找到一处子公司的子域名下存在某软系统,为了规避该单位信息泄漏,信息收集部分…

作者头像 李华
网站建设 2026/9/23 12:36:17

Unix、Linux、iOS、Android、鸿蒙:系统血缘关系全解析

1. 从一次内核版本排查说起:为什么搞清这些系统的血缘关系这么重要前阵子帮一个朋友排查他服务器上的问题,mysqld_safe报了个错,提示/var/run/mysqld这个目录不存在,导致 unix socket 文件创建失败。这本来是个很常见的权限和目录…

作者头像 李华
网站建设 2026/9/23 12:35:47

Android协程实现精确倒计时器开发指南

1. 功能需求解析在Android应用开发中,定时器功能是常见的基础需求。这个项目要实现的是一个具备暂停和继续功能的倒计时器,并在计时结束时触发回调。这种功能在健身应用(组间休息计时)、学习应用(番茄钟)、…

作者头像 李华