微信小程序 TabBar 图标生成

Polar Sponsor
爱发电 赞助
.NET 9.0

微信小程序 TabBar 图标生成技能,使用 Python PIL 绘制简约几何图标(未选中灰、选中绿),自动写入 app.json 配置。适用于“生成 tabBar 图标”、“底部菜单栏图标”、“tab 图标”等指令。

微信小程序 TabBar 图标生成

功能概述

微信小程序 TabBar 图标生成是一项面向实际任务的技能,主要用于为微信小程序项目生成底部 TabBar 图标,包括:;用 Python PIL 绘制每个 tab 的几何图形图标(81×81 px PNG,透明背景);

核心要点

  • 每个 tab 生成 2 张:未选中(灰色)+ 选中(主题色);
  • 输出到小程序项目的 images/ 目录;
  • 自动更新 app.json 的 tabBar 配置,补上 iconPath / selectedI。

使用与执行

它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。

结果检查与注意事项

执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。该技能适合用于一次性任务,也可以接入自动化工作流,与其他技能或上层代理配合完成更完整的业务链路;在组合使用时,应明确每一步的输入输出关系,并避免不同步骤之间出现参数冲突。

微信小程序 TabBar 图标生成

功能

为微信小程序项目生成底部 TabBar 图标,包括:

  1. 用 Python PIL 绘制每个 tab 的几何图形图标(81×81 px PNG,透明背景)
  2. 每个 tab 生成 2 张:未选中(灰色)+ 选中(主题色)
  3. 输出到小程序项目的 images/ 目录
  4. 自动更新 app.json 的 tabBar 配置,补上 iconPath / selectedIconPath

前置条件

  • Python 3 + Pillow (pip install pillow)
  • 已知小程序项目路径和 app.json 中的 tabBar 配置

工作流程

Step 1:读取 app.json

读取小程序项目的 app.json,提取 tabBar.list 中每个 tab 的:

  • pagePath:用于推断 tab 用途
  • text:tab 文字,用于匹配图标类型

Step 2:匹配图标类型

根据 tab 的 text 或 pagePath 自动匹配图标类型。优先按 text 关键词匹配, 无法匹配的 tab 向用户确认。

内置图标库

图标ID 图形描述 匹配关键词
star 五角星 推荐、首页、精选
home 房屋 首页、主页、home
record 记事本+横线 记录、日志、笔记
chat 对话气泡+三点 助手、聊天、问答、AI、客服
history 时钟 历史、记录、时间
profile 人形头像 我的、个人、设置、profile
cart 购物车 购物车、购物、商城
order 文档+勾 订单、工单
search 放大镜 搜索、发现、探索
category 四宫格 分类、目录
heart 爱心 收藏、喜欢、关注
bell 铃铛 消息、通知、提醒
map 定位标记 地图、位置、附近
stats 柱状图 统计、数据、分析、报表
camera 相机 拍照、相册、图片
scan 扫码框 扫码、扫描

Step 3:确认配色

默认配色方案:

  • 未选中:#999999(灰色)
  • 选中:#4CAF50(绿色)

读取 app.json 中 tabBar 的 selectedColor 字段作为选中色,保持与项目一致。 如果 app.json 没有 selectedColor,使用默认绿色,并向用户确认。

Step 4:生成图标

运行 Python 脚本,用 PIL ImageDraw 绘制几何图形:

  • 画布:81×81 px,RGBA 透明背景
  • 线宽:3px
  • 边距:14px
  • 填充模式:实心填充(非描边),保证小尺寸下清晰可辨

每个 tab 输出 2 个文件到 {miniprogram}/images/:

  • tab_{id}.png(未选中)
  • tab_{id}_active.png(选中)

Step 5:更新 app.json

为 tabBar.list 中每一项添加:

{
  "iconPath": "images/tab_{id}.png",
  "selectedIconPath": "images/tab_{id}_active.png"
}

Step 6:自检

  • images/ 目录下生成了 N×2 个 PNG 文件
  • 每个 PNG 尺寸为 81×81
  • app.json 每个 tab 都有 iconPath 和 selectedIconPath
  • 图标配色与 tabBar selectedColor 一致

图标绘制参考代码

以下是各图标的 PIL 绘制逻辑参考,实际使用时封装为函数统一调用。

import math
from PIL import Image, ImageDraw

SIZE = 81
PAD = 14

def new_canvas():
    img = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0))
    return img, ImageDraw.Draw(img)

# ===== star(五角星)=====
def draw_star(color):
    img, d = new_canvas()
    cx, cy = SIZE // 2, SIZE // 2
    r_out = SIZE // 2 - PAD + 4
    r_in = r_out * 0.38
    pts = []
    for i in range(10):
        a = math.pi / 2 + i * math.pi / 5
        r = r_out if i % 2 == 0 else r_in
        pts.append((cx + r * math.cos(a), cy - r * math.sin(a)))
    d.polygon(pts, fill=color)
    return img

# ===== home(房屋)=====
def draw_home(color):
    img, d = new_canvas()
    m = PAD
    # 屋顶三角
    d.polygon([(SIZE//2, m), (m, SIZE//2), (SIZE-m, SIZE//2)], fill=color)
    # 屋体矩形
    d.rectangle([m+8, SIZE//2, SIZE-m-8, SIZE-m], fill=color)
    # 门(透明挖洞效果用背景色)
    d.rectangle([SIZE//2-8, SIZE//2+10, SIZE//2+8, SIZE-m], fill=(0,0,0,0))
    return img

# ===== record(记事本)=====
def draw_record(color):
    img, d = new_canvas()
    m = PAD
    d.rounded_rectangle([m, m, SIZE-m, SIZE-m], radius=6, outline=color, width=3)
    lm, rm = m+10, SIZE-m-10
    for pct in [0.30, 0.48, 0.66]:
        y = int(SIZE * pct)
        d.line([(lm, y), (rm, y)], fill=color, width=2)
    return img

# ===== chat(对话气泡)=====
def draw_chat(color):
    img, d = new_canvas()
    m = PAD - 2
    d.rounded_rectangle([m, m, SIZE-m, SIZE-m-10], radius=14, fill=color)
    cx, by = SIZE//2, SIZE-m-10
    d.polygon([(cx-8, by), (cx+8, by), (cx, by+12)], fill=color)
    dot_y = (m + SIZE-m-10) // 2
    for dx in [-12, 0, 12]:
        d.ellipse([cx+dx-3, dot_y-3, cx+dx+3, dot_y+3], fill=(255,255,255,255))
    return img

# ===== history(时钟)=====
def draw_history(color):
    img, d = new_canvas()
    cx, cy = SIZE//2, SIZE//2
    r = SIZE//2 - PAD
    d.ellipse([cx-r, cy-r, cx+r, cy+r], outline=color, width=3)
    d.line([(cx, cy), (cx, cy-r+8)], fill=color, width=3)
    d.line([(cx, cy), (cx+r-12, cy)], fill=color, width=3)
    d.ellipse([cx-3, cy-3, cx+3, cy+3], fill=color)
    return img

# ===== profile(人形)=====
def draw_profile(color):
    img, d = new_canvas()
    cx = SIZE//2
    hr = 12
    hy = PAD + hr
    d.ellipse([cx-hr, hy-hr, cx+hr, hy+hr], fill=color)
    br, body_top = 24, hy+hr+4
    d.ellipse([cx-br, body_top, cx+br, SIZE-PAD+br], fill=color)
    return img

# ===== cart(购物车)=====
def draw_cart(color):
    img, d = new_canvas()
    m = PAD
    # 车身
    d.line([(m, m+5), (m+10, m+5), (SIZE-m-5, SIZE-m-18)], fill=color, width=3)
    d.line([(m+10, m+5), (SIZE-m, m+5)], fill=color, width=3)
    d.line([(SIZE-m, m+5), (SIZE-m-5, SIZE-m-18)], fill=color, width=3)
    d.line([(m+10, SIZE-m-18), (SIZE-m-5, SIZE-m-18)], fill=color, width=3)
    # 轮子
    d.ellipse([m+12, SIZE-m-12, m+22, SIZE-m-2], fill=color)
    d.ellipse([SIZE-m-22, SIZE-m-12, SIZE-m-12, SIZE-m-2], fill=color)
    return img

# ===== order(文档+勾)=====
def draw_order(color):
    img, d = new_canvas()
    m = PAD
    d.rounded_rectangle([m, m, SIZE-m, SIZE-m], radius=6, outline=color, width=3)
    # 勾
    cx, cy = SIZE//2, SIZE//2
    d.line([(cx-12, cy), (cx-2, cy+10), (cx+14, cy-10)], fill=color, width=3)
    return img

# ===== search(放大镜)=====
def draw_search(color):
    img, d = new_canvas()
    cx, cy = SIZE//2 - 4, SIZE//2 - 4
    r = 16
    d.ellipse([cx-r, cy-r, cx+r, cy+r], outline=color, width=3)
    d.line([(cx+r-4, cy+r-4), (SIZE-PAD, SIZE-PAD)], fill=color, width=4)
    return img

# ===== category(四宫格)=====
def draw_category(color):
    img, d = new_canvas()
    m = PAD
    gap = 6
    bw = (SIZE - 2*m - gap) // 2
    for r in range(2):
        for c in range(2):
            x0, y0 = m + c*(bw+gap), m + r*(bw+gap)
            d.rounded_rectangle([x0, y0, x0+bw, y0+bw], radius=6, fill=color)
    return img

# ===== heart(爱心)=====
def draw_heart(color):
    img, d = new_canvas()
    cx, cy = SIZE//2, SIZE//2 + 2
    r = 13
    d.ellipse([cx-r*2, cy-r-4, cx, cy+2], fill=color)
    d.ellipse([cx, cy-r-4, cx+r*2, cy+2], fill=color)
    d.polygon([(cx-r*2+1, cy), (cx, cy+r+8), (cx+r*2-1, cy)], fill=color)
    return img

# ===== bell(铃铛)=====
def draw_bell(color):
    img, d = new_canvas()
    cx = SIZE//2
    m = PAD
    # 铃身
    d.arc([m+6, m, SIZE-m-6, SIZE-m-10], 180, 0, fill=color, width=3)
    d.line([(m+6, SIZE//2), (m+6, SIZE-m-10)], fill=color, width=3)
    d.line([(SIZE-m-6, SIZE//2), (SIZE-m-6, SIZE-m-10)], fill=color, width=3)
    d.line([(m, SIZE-m-10), (SIZE-m, SIZE-m-10)], fill=color, width=3)
    # 铃舌
    d.ellipse([cx-5, SIZE-m-8, cx+5, SIZE-m+2], fill=color)
    return img

# ===== map(定位标记)=====
def draw_map(color):
    img, d = new_canvas()
    cx = SIZE//2
    r = 18
    d.ellipse([cx-r, PAD, cx+r, PAD+r*2], fill=color)
    d.polygon([(cx-r+4, PAD+r+4), (cx, SIZE-PAD), (cx+r-4, PAD+r+4)], fill=color)
    d.ellipse([cx-6, PAD+r-6, cx+6, PAD+r+6], fill=(0,0,0,0))
    return img

# ===== stats(柱状图)=====
def draw_stats(color):
    img, d = new_canvas()
    m = PAD
    bw = 10
    heights = [0.4, 0.7, 0.55, 0.85]
    total_w = len(heights) * bw + (len(heights)-1) * 5
    sx = (SIZE - total_w) // 2
    for i, h in enumerate(heights):
        x = sx + i * (bw + 5)
        bh = int((SIZE - 2*m) * h)
        d.rectangle([x, SIZE-m-bh, x+bw, SIZE-m], fill=color)
    return img

# ===== camera(相机)=====
def draw_camera(color):
    img, d = new_canvas()
    m = PAD
    d.rounded_rectangle([m, m+10, SIZE-m, SIZE-m], radius=8, outline=color, width=3)
    # 镜头
    cx, cy = SIZE//2, SIZE//2 + 5
    d.ellipse([cx-12, cy-12, cx+12, cy+12], outline=color, width=3)
    # 闪光灯
    d.rectangle([SIZE//2-6, m+4, SIZE//2+6, m+12], fill=color)
    return img

# ===== scan(扫码框)=====
def draw_scan(color):
    img, d = new_canvas()
    m = PAD
    l = 14  # 角标线长
    # 四个角标
    for x0, y0, dx, dy in [(m,m,1,1), (SIZE-m,m,-1,1), (m,SIZE-m,1,-1), (SIZE-m,SIZE-m,-1,-1)]:
        d.line([(x0, y0), (x0+l*dx, y0)], fill=color, width=3)
        d.line([(x0, y0), (x0, y0+l*dy)], fill=color, width=3)
    # 中间扫描线
    d.line([(m+4, SIZE//2), (SIZE-m-4, SIZE//2)], fill=color, width=2)
    return img

绝对不能做的事

  1. 不能生成超过 81×81 px 的图标 — 微信 tabBar 要求 81×81
  2. 不能使用外部图标字体或 iconfont — 用纯几何绘制,零依赖
  3. 不能忘记更新 app.json — 生成图标后必须写入 iconPath/selectedIconPath
  4. 不能让选中色与 app.json 的 selectedColor 不一致

相关专题

更多
微信调黑色模式教程
微信调黑色模式教程

本专题整合了微信调黑色模式教程,阅读下面的文章了解更多详细内容。

2025.12.25

776

25

微信访客记录查看教程
微信访客记录查看教程

微信虽功能丰富,却未直接设置查看访客记录的功能,不过,仍能借助一些间接方法,来了解访客的相关情况。比如,通过朋友圈互动,查看点赞、评论者,推断访客踪迹;运营公众号的用户,可在后台统计数据中,分析访客行为。

2025.05.28

4916

10

微信怎么解除未成年认证
微信怎么解除未成年认证

若要解除微信未成年认证,您必须已满 18 周岁且认证时间已超过 30 天。具体解除步骤如下:登录微信,前往“我”页面。点击“设置”>“未成年保护”。填写真实姓名、身份证号和身份证照片。进行人脸识别。点击“解除未成年认证”,提交审核。审核通过后,解除成功,即可恢复所有微信功能。

2025.04.22

8073

12

微信对方没打电话显示忙线咋回事儿
微信对方没打电话显示忙线咋回事儿

微信显示“忙线”原因:对方正在通话;对方开启了“免打扰”模式;信号不佳;操作延迟;系统故障。

2025.03.28

3440

4

微信是谁开发的
微信是谁开发的

微信是由张小龙所带领的腾讯广州研发中心产品团队打造开发的,并不是马化腾开发的,而腾讯公司总裁马化腾是在产品策划的邮件中确定这款产品的名称叫做“微信”的。想了解更多微信相关的内容,可阅读本专题下面的相关文章。

2024.11.05

5155

8

微信角标数字怎么恢复
微信角标数字怎么恢复

恢复微信角标数字的方法:1、强制退出微信,重新启动;2、清除微信缓存;3、检查微信版本更新;4、卸载并重新安装微信。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2025.01.16

3022

7

怎么查看微信注册时间
怎么查看微信注册时间

通过以下步骤查看微信注册时间:1. 打开微信;2. 点击“我”;3. 点击“设置”;4. 进入“账号与安全”;5. 查看“微信号”;6. 查看注册时间。想了解更多相关的内容,请阅读专题下面的文章。

2024.12.23

6200

8

微信打电话怎么不显示
微信打电话怎么不显示

微信电话不显示的原因可能是:未打开通话显示设定。运营商限制。对方设定了拒接陌生来电。技术问题。隐私保护导致来电号码隐藏,需对方主动选择显示。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.12.10

3575

6

手动删除的微信聊天记录怎么找回
手动删除的微信聊天记录怎么找回

手动删除的微信聊天记录可以通过以下方法找回:如已开启微信聊天记录备份,可通过「设置」>「聊天」>「聊天记录备份与迁移」恢复。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.12.02

1474

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
秒哒微信小程序发布
秒哒微信小程序发布

共0课时 | 0人学习

微信小程序开发之API篇
微信小程序开发之API篇

共15课时 | 1.8万人学习