目录

class 卑微码农:
def __init__(self):
self.技能 = ['能读懂十年前祖传代码', '擅长用Ctrl+C/V搭建世界', '信奉"能跑就别动"的玄学']
self.发量 = 100 # 初始发量
self.咖啡因耐受度 = '极限'
def 修Bug(self, bug):
try:
# 试图用玄学解决问题
if bug.严重程度 == '离谱':
print("这一定是环境问题!")
else:
print("让我看看是谁又没写注释...哦,是我自己。")
except Exception as e:
# 如果try块都救不了,那就...
print("重启一下试试?")
self.发量 -= 1 # 每解决一个bug,头发-1
# 实例化一个我
我 = 卑微码农()
引言:为什么选择 Kivy 做跨平台开发?
在 Python GUI 框架生态中,Tkinter 轻量但功能单一,PyQt 强大却侧重桌面端,而 Kivy 作为一款专为触控设计的跨平台框架,以其一次编写、多端运行的特性脱颖而出。它不仅支持 Windows、macOS、Linux 等桌面系统,还能无缝适配 Android、iOS 移动设备,甚至可部署到树莓派等嵌入式平台。

Kivy 的核心优势在于原生支持多点触控、内置丰富的动画系统和声明式 UI 开发(KV 语言),尤其适合开发交互性强的移动应用和创意项目。无论是开发简单的工具类 App,还是复杂的游戏或多媒体应用,Kivy 都能提供灵活高效的解决方案。
本文将从零基础开始,系统讲解 Kivy 的核心知识点与实战技巧,内容涵盖环境搭建、核心概念、布局管理、控件使用、KV 语言、动画效果、数据绑定,最终通过完整项目实现知识落地。全程搭配可直接运行的代码示例和清晰对比表格,帮助你快速掌握 Kivy 开发能力。
一、环境搭建与基础认知

1.1 多平台安装步骤
Kivy 的安装需依赖部分系统库,不同操作系统的安装流程略有差异,推荐使用 Python 3.7-3.10 版本(兼容性最佳):
Windows 系统
# 升级pip
python -m pip install --upgrade pip setuptools wheel
# 安装依赖(若提示缺失)
pip install docutils pygments pypiwin32 kivy-deps-winker kivy-deps-glew
# 安装Kivy
pip install kivy[base]
macOS 系统
# 安装系统依赖(需先安装Homebrew:https://brew.sh/)
brew install pkg-config sdl2 sdl2_image sdl2_ttf sdl2_mixer gstreamer
# 安装Kivy
pip install kivy[base]
Linux 系统(Ubuntu/Debian)
# 安装系统依赖
sudo apt-get install -y python3-pip build-essential git python3 python3-dev ffmpeg \
libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev libportmidi-dev \
libswscale-dev libavformat-dev libavcodec-dev zlib1g-dev
# 安装Kivy
pip3 install kivy[base]
验证安装
运行以下代码,若弹出 Kivy 示例窗口则说明安装成功:
import kivy
kivy.require('2.1.0') # 替换为你的Kivy版本
from kivy.app import App
from kivy.uix.label import Label
class TestApp(App):
def build(self):
return Label(text='Kivy安装成功!')
if __name__ == '__main__':
TestApp().run()
1.2 Kivy 核心概念速览
在编写第一个完整程序前,需先理解 Kivy 的三个核心概念:
- App:所有 Kivy 应用的入口,每个应用必须继承自
kivy.app.App,并实现build()方法返回根 Widget。 - Widget:所有 UI 组件的基类,如按钮、标签、输入框等,支持事件处理和属性绑定。
- Layout:布局管理器,用于控制 Widget 的排列方式,解决组件位置和大小的自适应问题。
1.3 第一个 Kivy 应用:待办事项清单雏形
以下示例将实现一个简单的待办事项输入界面,涵盖 App、Widget、Layout 的基础使用:
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
class TodoApp(App):
def build(self):
# 创建垂直布局(自上而下排列组件)
root_layout = BoxLayout(orientation='vertical', spacing=10, padding=20)
# 添加标题标签
title = Label(text='我的待办事项', font_size=24)
root_layout.add_widget(title)
# 添加文本输入框(用于输入待办内容)
self.todo_input = TextInput(hint_text='请输入待办事项...', font_size=16)
root_layout.add_widget(self.todo_input)
# 添加添加按钮
add_btn = Button(text='添加事项', font_size=16, background_color=(0.2, 0.7, 0.3, 1))
add_btn.bind(on_press=self.add_todo) # 绑定点击事件
root_layout.add_widget(add_btn)
# 添加待办事项显示标签
self.todo_label = Label(text='已添加的事项:', font_size=16)
root_layout.add_widget(self.todo_label)
return root_layout
def add_todo(self, instance):
# 获取输入框内容
todo_text = self.todo_input.text.strip()
if todo_text:
# 更新显示标签
self.todo_label.text += f'\n• {todo_text}'
# 清空输入框
self.todo_input.text = ''
if __name__ == '__main__':
TodoApp().run()
运行代码后,将看到一个包含输入框、按钮和显示区域的窗口,输入内容并点击按钮即可添加待办事项。
1.4 Kivy 与其他 GUI 框架的核心差异
很多开发者会混淆 Kivy 与传统 GUI 框架,以下表格清晰对比其关键区别:
| 对比维度 | Kivy | PyQt6 | Tkinter |
|---|---|---|---|
| 核心定位 | 跨平台触控应用 | 桌面端专业 GUI | 轻量桌面工具 |
| 移动支持 | 原生支持 Android/iOS | 需借助第三方工具(如 PyInstaller) | 不支持移动平台 |
| UI 开发方式 | Python 代码 + KV 语言(声明式) | Python 代码 + Qt Designer | 纯 Python 代码 |
| 触控支持 | 原生支持多点触控 | 有限支持 | 不支持 |
| 动画系统 | 内置强大动画框架 | 需手动实现复杂动画 | 仅基础动画支持 |
| 学习曲线 | 中等(需掌握 KV 语言) | 较陡(概念较多) | 平缓(入门简单) |
| 适用场景 | 移动应用、创意项目、游戏 | 桌面端专业软件 | 简单工具、小脚本 |
选择建议:开发跨平台移动应用或触控交互项目优先选 Kivy;开发桌面端专业软件可选 PyQt6;快速实现简单工具可用 Tkinter。
二、Kivy 核心组件详解

Kivy 的 UI 构建基于 Widget 体系,常用组件可分为基础控件、布局控件和容器控件三类,掌握这些组件是开发复杂界面的基础。
2.1 基础控件:UI 交互的基石
基础控件是构成界面的最小单元,涵盖文本显示、输入、按钮等核心交互元素:
2.1.1 常用基础控件速览
| 控件类名 | 核心功能 | 常用属性 | 适用场景 |
|---|---|---|---|
| Label | 显示文本 | text(文本内容)、font_size(字体大小)、color(文本颜色) | 标题、提示信息展示 |
| TextInput | 文本输入 | hint_text(提示文本)、text(输入内容)、password(密码模式) | 用户名、内容输入 |
| Button | 点击交互 | text(按钮文本)、background_color(背景色)、on_press(点击事件) | 触发操作(提交、删除等) |
| CheckBox | 多选功能 | active(是否选中)、on_active(状态变化事件) | 多选选项(如设置项) |
| Slider | 数值调节 | value(当前值)、min/max(范围)、on_value(值变化事件) | 音量、亮度调节 |
| Image | 图片显示 | source(图片路径)、size_hint(尺寸比例) | 展示图标、背景图 |
2.1.2 基础控件实战示例
以下示例展示如何组合使用基础控件实现一个简单的用户注册界面:
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.checkbox import CheckBox
from kivy.uix.slider import Slider
class RegisterApp(App):
def build(self):
# 垂直布局,设置间距和内边距
root = BoxLayout(orientation='vertical', spacing=15, padding=30)
# 用户名输入
root.add_widget(Label(text='用户名:', font_size=16))
self.username = TextInput(font_size=16, hint_text='请输入用户名')
root.add_widget(self.username)
# 密码输入
root.add_widget(Label(text='密码:', font_size=16))
self.password = TextInput(font_size=16, hint_text='请输入密码', password=True)
root.add_widget(self.password)
# 年龄调节滑块
age_layout = BoxLayout(orientation='horizontal', spacing=10)
age_layout.add_widget(Label(text='年龄:', font_size=16))
self.age_slider = Slider(min=18, max=60, value=25)
self.age_label = Label(text=f'{int(self.age_slider.value)}', font_size=16)
# 绑定滑块值变化事件
self.age_slider.bind(value=lambda x, y: setattr(self.age_label, 'text', f'{int(y)}'))
age_layout.add_widget(self.age_slider)
age_layout.add_widget(self.age_label)
root.add_widget(age_layout)
# 同意协议复选框
agree_layout = BoxLayout(orientation='horizontal', spacing=10)
self.agree_cb = CheckBox()
agree_layout.add_widget(self.agree_cb)
agree_layout.add_widget(Label(text='同意用户协议和隐私政策', font_size=14))
root.add_widget(agree_layout)
# 注册按钮
register_btn = Button(text='注册', font_size=18, background_color=(0.1, 0.6, 0.9, 1))
register_btn.bind(on_press=self.register)
root.add_widget(register_btn)
return root
def register(self, instance):
# 验证注册信息
if not self.username.text.strip():
print('用户名不能为空!')
return
if len(self.password.text) < 6:
print('密码长度不能小于6位!')
return
if not self.agree_cb.active:
print('请同意用户协议!')
return
# 注册成功
print(f'注册成功!用户名:{self.username.text},年龄:{int(self.age_slider.value)}')
if __name__ == '__main__':
RegisterApp().run()
2.2 布局控件:实现界面自适应
手动设置控件位置无法适应不同屏幕尺寸,Kivy 提供 5 种核心布局管理器,实现组件自动排列和响应式适配:
2.2.1 布局控件对比与适用场景
| 布局类型 | 排列方式 | 核心属性 | 适用场景 |
|---|---|---|---|
| BoxLayout | 垂直 / 水平线性排列 | orientation(方向)、spacing(间距)、padding(内边距) | 表单、按钮组等线性结构 |
| GridLayout | 网格状排列 | cols(列数)、rows(行数)、row_force_default(行高固定) | 登录表单、数据表格等结构化界面 |
| FloatLayout | 自由定位 | 需手动设置 pos(位置)、size(大小) | 自定义复杂布局(如游戏界面) |
| AnchorLayout | 锚点定位 | anchor_x(水平锚点)、anchor_y(垂直锚点) | 单个组件的定位(如底部按钮、顶部标题) |
| StackLayout | 堆叠排列 | orientation(排列方向)、spacing(间距) | 组件重叠或流式布局(如标签云) |
2.2.2 复杂布局嵌套实战
布局支持嵌套组合,可实现灵活的界面结构,以下示例用 GridLayout 和 BoxLayout 嵌套实现一个音乐播放器界面:
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.uix.slider import Slider
class MusicPlayerApp(App):
def build(self):
# 主网格布局(3行1列)
root = GridLayout(cols=1, spacing=20, padding=30)
# 第一行:歌曲信息(图片+文本)
info_layout = BoxLayout(orientation='horizontal', spacing=20)
# 歌曲封面
cover = Image(source='music_cover.png', size_hint=(0.3, 1)) # 需提前准备图片
info_layout.add_widget(cover)
# 歌曲文本信息(垂直排列)
text_layout = BoxLayout(orientation='vertical', spacing=10)
text_layout.add_widget(Label(text='晴天', font_size=24, bold=True))
text_layout.add_widget(Label(text='周杰伦 - 叶惠美', font_size=18))
text_layout.add_widget(Label(text='播放量:1000万+', font_size=14))
info_layout.add_widget(text_layout)
root.add_widget(info_layout)
# 第二行:播放控制按钮(网格布局,4列1行)
btn_layout = GridLayout(cols=4, spacing=15, size_hint=(1, 0.2))
btn_layout.add_widget(Button(text='上一首', font_size=16))
btn_layout.add_widget(Button(text='暂停', font_size=16, background_color=(0.9, 0.3, 0.3, 1)))
btn_layout.add_widget(Button(text='播放', font_size=16, background_color=(0.2, 0.7, 0.2, 1)))
btn_layout.add_widget(Button(text='下一首', font_size=16))
root.add_widget(btn_layout)
# 第三行:进度条和音量控制
control_layout = BoxLayout(orientation='vertical', spacing=10)
# 播放进度
progress_layout = BoxLayout(orientation='horizontal', spacing=10, size_hint=(1, 0.3))
progress_layout.add_widget(Label(text='02:30', font_size=14))
self.progress_slider = Slider(value=30, max=180) # 总时长3分钟(180秒)
progress_layout.add_widget(self.progress_slider)
progress_layout.add_widget(Label(text='03:00', font_size=14))
control_layout.add_widget(progress_layout)
# 音量控制
volume_layout = BoxLayout(orientation='horizontal', spacing=10, size_hint=(1, 0.3))
volume_layout.add_widget(Label(text='音量', font_size=14))
self.volume_slider = Slider(value=70, max=100)
volume_layout.add_widget(self.volume_slider)
control_layout.add_widget(volume_layout)
root.add_widget(control_layout)
return root
if __name__ == '__main__':
MusicPlayerApp().run()
2.3 容器控件:实现复杂界面切换
容器控件用于管理多个界面的切换和组合,是实现多页面应用的核心:
2.3.1 常用容器控件
- ScreenManager:屏幕管理器,用于管理多个 Screen 界面,支持切换动画。
- Screen:单个屏幕界面,作为 ScreenManager 的子组件,每个 Screen 代表一个页面。
- ScrollView:滚动容器,当内容超出显示区域时可滚动查看。
2.3.2 多页面应用实战
以下示例用 ScreenManager 实现登录、注册、首页的页面切换功能:
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
# 登录页面
class LoginScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# 垂直布局
layout = BoxLayout(orientation='vertical', spacing=15, padding=50)
# 标题
layout.add_widget(Label(text='用户登录', font_size=28, bold=True))
# 用户名输入
layout.add_widget(Label(text='用户名:', font_size=16))
self.username = TextInput(font_size=16, hint_text='请输入用户名')
layout.add_widget(self.username)
# 密码输入
layout.add_widget(Label(text='密码:', font_size=16))
self.password = TextInput(font_size=16, hint_text='请输入密码', password=True)
layout.add_widget(self.password)
# 登录按钮
login_btn = Button(text='登录', font_size=18, background_color=(0.1, 0.6, 0.9, 1))
login_btn.bind(on_press=self.login)
layout.add_widget(login_btn)
# 跳转到注册页面
register_btn = Button(text='没有账号?立即注册', font_size=14, background_color=(0.8, 0.8, 0.8, 1))
register_btn.bind(on_press=self.goto_register)
layout.add_widget(register_btn)
self.add_widget(layout)
def login(self, instance):
# 简单验证
if self.username.text == 'admin' and self.password.text == '123456':
# 登录成功,跳转到首页
self.manager.current = 'home'
else:
print('用户名或密码错误!')
def goto_register(self, instance):
# 跳转到注册页面
self.manager.current = 'register'
# 注册页面
class RegisterScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
layout = BoxLayout(orientation='vertical', spacing=15, padding=50)
layout.add_widget(Label(text='用户注册', font_size=28, bold=True))
# 用户名
layout.add_widget(Label(text='用户名:', font_size=16))
self.username = TextInput(font_size=16, hint_text='请输入用户名')
layout.add_widget(self.username)
# 密码
layout.add_widget(Label(text='密码:', font_size=16))
self.password = TextInput(font_size=16, hint_text='请输入密码', password=True)
layout.add_widget(self.password)
# 确认密码
layout.add_widget(Label(text='确认密码:', font_size=16))
self.confirm_pwd = TextInput(font_size=16, hint_text='请再次输入密码', password=True)
layout.add_widget(self.confirm_pwd)
# 注册按钮
register_btn = Button(text='注册', font_size=18, background_color=(0.2, 0.7, 0.2, 1))
register_btn.bind(on_press=self.register)
layout.add_widget(register_btn)
# 跳转到登录页面
login_btn = Button(text='已有账号?立即登录', font_size=14, background_color=(0.8, 0.8, 0.8, 1))
login_btn.bind(on_press=self.goto_login)
layout.add_widget(login_btn)
self.add_widget(layout)
def register(self, instance):
# 验证注册信息
if not self.username.text.strip():
print('用户名不能为空!')
return
if self.password.text != self.confirm_pwd.text:
print('两次输入的密码不一致!')
return
# 注册成功,跳转到登录页面
print('注册成功!请登录')
self.manager.current = 'login'
def goto_login(self, instance):
self.manager.current = 'login'
# 首页
class HomeScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
layout = BoxLayout(orientation='vertical', spacing=20, padding=50)
layout.add_widget(Label(text='欢迎来到首页!', font_size=28, bold=True))
# 功能按钮
layout.add_widget(Button(text='我的资料', font_size=18))
layout.add_widget(Button(text='消息通知', font_size=18))
layout.add_widget(Button(text='设置中心', font_size=18))
# 退出登录
logout_btn = Button(text='退出登录', font_size=18, background_color=(0.9, 0.3, 0.3, 1))
logout_btn.bind(on_press=self.logout)
layout.add_widget(logout_btn)
self.add_widget(layout)
def logout(self, instance):
# 退出登录,跳转到登录页面
self.manager.current = 'login'
# 应用入口
class MultiScreenApp(App):
def build(self):
# 创建屏幕管理器,设置切换动画
sm = ScreenManager(transition=FadeTransition())
# 添加三个页面
sm.add_widget(LoginScreen(name='login'))
sm.add_widget(RegisterScreen(name='register'))
sm.add_widget(HomeScreen(name='home'))
return sm
if __name__ == '__main__':
MultiScreenApp().run()
三、KV 语言:Kivy 的声明式 UI 开发

KV 语言是 Kivy 专属的声明式 UI 描述语言,能够将 UI 布局与 Python 业务逻辑分离,大幅简化界面开发流程,让代码结构更清晰。
3.1 KV 语言基础语法
3.1.1 基本规则
- KV 文件命名:需与 App 类名对应,且首字母小写,后缀为
.kv(如TodoApp对应todo.kv)。 - 组件声明:使用类名或自定义类名作为根节点,子组件缩进显示。
- 属性赋值:使用
:赋值,支持直接设置或绑定表达式。 - 事件绑定:使用
on_属性绑定事件,如on_press绑定按钮点击。
3.1.2 语法示例:KV 语言实现登录界面
首先创建loginapp.kv文件(对应 App 类LoginApp):
#:kivy 2.1.0 # 指定Kivy版本
# 登录页面布局
BoxLayout:
orientation: 'vertical'
spacing: 15
padding: 50
# 标题
Label:
text: 'KV语言登录界面'
font_size: 28
bold: True
# 用户名输入
Label:
text: '用户名:'
font_size: 16
TextInput:
id: username # 组件ID,用于Python代码中引用
font_size: 16
hint_text: '请输入用户名'
# 密码输入
Label:
text: '密码:'
font_size: 16
TextInput:
id: password
font_size: 16
hint_text: '请输入密码'
password: True
# 登录按钮
Button:
text: '登录'
font_size: 18
background_color: 0.1, 0.6, 0.9, 1
on_press: app.login() # 绑定App的login方法
# 注册按钮
Button:
text: '注册'
font_size: 18
background_color: 0.2, 0.7, 0.2, 1
on_press: app.goto_register()
然后创建 Python 代码文件login_app.py:
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
# 登录页面
class LoginScreen(Screen):
pass # UI由KV文件定义
# 注册页面
class RegisterScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# 注册页面UI可继续用KV文件实现,此处简化
from kivy.uix.label import Label
self.add_widget(Label(text='注册页面', font_size=28))
# 应用入口
class LoginApp(App):
def build(self):
sm = ScreenManager(transition=FadeTransition())
sm.add_widget(LoginScreen(name='login'))
sm.add_widget(RegisterScreen(name='register'))
return sm
def login(self):
# 通过ID获取组件内容
username = self.root.get_screen('login').ids.username.text
password = self.root.get_screen('login').ids.password.text
if username == 'admin' and password == '123456':
print('登录成功!')
else:
print('用户名或密码错误!')
def goto_register(self):
self.root.current = 'register'
if __name__ == '__main__':
LoginApp().run()
3.2 KV 语言高级特性
3.2.1 动态属性绑定
KV 语言支持属性之间的动态绑定,当一个属性变化时,关联属性自动更新:
BoxLayout:
orientation: 'vertical'
spacing: 10
Slider:
id: slider
min: 0
max: 100
value: 50
Label:
# 绑定滑块值,实时更新显示
text: f'当前值:{int(slider.value)}'
font_size: 16
3.2.2 自定义组件
在 KV 语言中可自定义组件,实现 UI 复用:
# 自定义按钮组件
<CustomButton@Button>:
font_size: 16
background_color: 0.1, 0.5, 0.9, 1
size_hint: 1, 0.1
# 使用自定义组件
BoxLayout:
orientation: 'vertical'
spacing: 10
CustomButton:
text: '自定义按钮1'
CustomButton:
text: '自定义按钮2'
background_color: 0.2, 0.7, 0.2, 1 # 覆盖默认属性
3.2.3 样式与主题
KV 语言支持通过Canvas自定义组件样式,实现圆角、阴影等效果:
Button:
text: '圆角按钮'
font_size: 18
background_color: 0, 0, 0, 0 # 透明背景
# 自定义画布样式
Canvas.before:
Color:
rgba: 0.1, 0.6, 0.9, 1 # 按钮背景色
RoundedRectangle:
pos: self.pos
size: self.size
radius: [10, 10, 10, 10] # 圆角半径
四、Kivy 特色功能:动画、数据绑定与触控

Kivy 的核心优势在于对动画、数据绑定和触控的原生支持,这些功能让应用交互更流畅、开发效率更高。
4.1 动画系统:打造流畅交互效果
Kivy 的Animation类支持对组件的任意属性设置动画,如位置、大小、颜色、透明度等。
4.1.1 基础动画示例
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.animation import Animation
class AnimationApp(App):
def build(self):
layout = BoxLayout(orientation='vertical', spacing=20, padding=50)
# 动画按钮
self.anim_btn = Button(text='点击触发动画', font_size=18, size_hint=(0.5, 0.2), pos_hint={'x': 0.25})
self.anim_btn.bind(on_press=self.start_animation)
layout.add_widget(self.anim_btn)
return layout
def start_animation(self, instance):
# 创建动画:移动+缩放+颜色变化,时长2秒
anim = Animation(
pos_hint={'x': 0.1}, # 水平位置变化
size_hint=(0.8, 0.3), # 尺寸变化
background_color=(0.9, 0.3, 0.3, 1), # 颜色变化
duration=2
)
# 动画完成后反向执行
anim.repeat = False
anim.reverse = True
# 启动动画
anim.start(self.anim_btn)
if __name__ == '__main__':
AnimationApp().run()
4.1.2 组合动画与序列动画
from kivy.animation import Animation
# 序列动画:按顺序执行多个动画
anim1 = Animation(pos_hint={'x': 0.5}, duration=1)
anim2 = Animation(size_hint=(0.6, 0.2), duration=1)
anim3 = Animation(background_color=(0.2, 0.7, 0.2, 1), duration=1)
sequence_anim = anim1 + anim2 + anim3 # 序列执行
sequence_anim.start(self.anim_btn)
# 并行动画:同时执行多个动画
parallel_anim = anim1 & anim2 & anim3 # 并行执行
parallel_anim.start(self.anim_btn)
4.2 数据绑定:实现 UI 与数据同步
Kivy 的Property类支持数据绑定,当数据变化时,关联的 UI 组件自动更新,无需手动操作。
4.2.1 常用 Property 类型
| Property 类型 | 作用 | 示例 |
|---|---|---|
| StringProperty | 字符串类型属性 | name = StringProperty('默认值') |
| NumericProperty | 数值类型属性 | count = NumericProperty(0) |
| BooleanProperty | 布尔类型属性 | is_active = BooleanProperty(False) |
| ListProperty | 列表类型属性 | colors = ListProperty([1, 1, 1, 1]) |
4.2.2 数据绑定实战示例
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import NumericProperty
from kivy.lang import Builder
# 使用KV语言绑定属性
Builder.load_string('''
<CounterLayout>:
orientation: 'vertical'
spacing: 20
padding: 50
Label:
text: f'当前计数:{root.count}' # 绑定CounterLayout的count属性
font_size: 24
Button:
text: '增加'
font_size: 18
on_press: root.increment()
Button:
text: '减少'
font_size: 18
on_press: root.decrement()
''')
class CounterLayout(BoxLayout):
# 定义数值属性,支持数据绑定
count = NumericProperty(0)
def increment(self):
self.count += 1
def decrement(self):
if self.count > 0:
self.count -= 1
class DataBindApp(App):
def build(self):
return CounterLayout()
if __name__ == '__main__':
DataBindApp().run()
4.3 触控支持:开发移动触控应用
Kivy 原生支持多点触控,可通过重写 Widget 的触控方法实现自定义触控逻辑。
4.3.1 基础触控事件
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse
class TouchWidget(Widget):
def on_touch_down(self, touch):
# 触摸按下时触发
with self.canvas:
Color(1, 0, 0, 1) # 红色
Ellipse(pos=(touch.x-20, touch.y-20), size=(40, 40)) # 绘制圆点
return True
def on_touch_move(self, touch):
# 触摸移动时触发
with self.canvas:
Color(0, 1, 0, 1) # 绿色
Ellipse(pos=(touch.x-20, touch.y-20), size=(40, 40))
def on_touch_up(self, touch):
# 触摸抬起时触发
with self.canvas:
Color(0, 0, 1, 1) # 蓝色
Ellipse(pos=(touch.x-20, touch.y-20), size=(40, 40))
class TouchApp(App):
def build(self):
return TouchWidget()
if __name__ == '__main__':
TouchApp().run()
4.3.2 多点触控示例
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse
from kivy.uix.label import Label
class MultiTouchWidget(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.touch_points = {} # 存储多个触控点
def on_touch_down(self, touch):
# 记录触控点ID和位置
self.touch_points[touch.id] = (touch.x, touch.y)
self.update_canvas()
return True
def on_touch_move(self, touch):
# 更新触控点位置
self.touch_points[touch.id] = (touch.x, touch.y)
self.update_canvas()
def on_touch_up(self, touch):
# 移除触控点
del self.touch_points[touch.id]
self.update_canvas()
def update_canvas(self):
# 清空画布
self.canvas.clear()
# 绘制所有触控点
colors = [(1,0,0,1), (0,1,0,1), (0,0,1,1), (1,1,0,1)] # 不同触控点不同颜色
for i, (touch_id, pos) in enumerate(self.touch_points.items()):
color = colors[i % len(colors)]
with self.canvas:
Color(*color)
Ellipse(pos=(pos[0]-20, pos[1]-20), size=(40, 40))
class MultiTouchApp(App):
def build(self):
widget = MultiTouchWidget()
# 添加提示标签
label = Label(text='支持多点触控,点击并拖动', font_size=16, pos_hint={'y': 0.9})
widget.add_widget(label)
return widget
if __name__ == '__main__':
MultiTouchApp().run()
五、实战项目:跨平台待办事项 App

结合前面的知识点,开发一个功能完整的跨平台待办事项 App,支持添加、删除、标记完成、数据持久化等功能,涵盖 KV 语言、数据绑定、布局管理、动画效果等核心技术。
5.1 项目需求分析
- 支持添加待办事项,包含标题和内容;
- 支持标记待办事项为已完成 / 未完成;
- 支持删除待办事项;
- 支持待办事项数据本地持久化(使用 JSON 文件);
- 界面响应式设计,适配桌面和移动设备;
- 添加动画效果,提升交互体验。
5.2 项目结构设计
todo_app/
├── main.py # 应用入口
├── todo.kv # UI布局(KV语言)
└── todo_data.json # 数据持久化文件
5.3 完整代码实现
5.3.1 主程序文件main.py
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ListProperty, StringProperty, BooleanProperty
from kivy.animation import Animation
import json
import os
# 待办事项数据模型
class TodoItem:
def __init__(self, title, content, completed=False):
self.title = title
self.content = content
self.completed = completed
# 转换为字典,用于JSON序列化
def to_dict(self):
return {
'title': self.title,
'content': self.content,
'completed': self.completed
}
# 从字典创建对象
@staticmethod
def from_dict(data):
return TodoItem(
title=data['title'],
content=data['content'],
completed=data.get('completed', False)
)
# 待办事项列表项组件
class TodoListItem(BoxLayout):
title = StringProperty('')
content = StringProperty('')
completed = BooleanProperty(False)
index = NumericProperty(0) # 列表项索引
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.orientation = 'horizontal'
self.spacing = 10
self.size_hint = (1, None)
self.height = 80
def on_completed(self, instance, value):
# 标记完成时添加动画效果
if value:
anim = Animation(color=(0.5, 0.5, 0.5, 1), duration=0.3)
anim.start(self.ids.title_label)
anim.start(self.ids.content_label)
else:
anim = Animation(color=(1, 1, 1, 1), duration=0.3)
anim.start(self.ids.title_label)
anim.start(self.ids.content_label)
def delete(self):
# 删除动画
anim = Animation(opacity=0, height=0, duration=0.3)
anim.bind(on_complete=self.on_delete_complete)
anim.start(self)
def on_delete_complete(self, anim, widget):
# 动画完成后通知主界面删除该项目
self.parent.parent.parent.remove_todo(self.index)
# 主界面
class TodoScreen(Screen):
todos = ListProperty([]) # 待办事项列表,支持数据绑定
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.load_todos() # 加载本地数据
def add_todo(self):
# 获取输入内容
title = self.ids.title_input.text.strip()
content = self.ids.content_input.text.strip()
if not title:
print('标题不能为空!')
return
# 添加新待办事项
new_todo = TodoItem(title=title, content=content)
self.todos.append(new_todo)
# 清空输入框
self.ids.title_input.text = ''
self.ids.content_input.text = ''
# 保存数据
self.save_todos()
# 添加动画效果
self.animate_new_item()
def animate_new_item(self):
# 为最后一个列表项添加入场动画
if self.todos:
items = self.ids.todo_list.children
if items:
item = items[0]
item.opacity = 0
item.y -= 50
anim = Animation(opacity=1, y=item.y+50, duration=0.5)
anim.start(item)
def toggle_completed(self, index):
# 切换待办事项完成状态
self.todos[index].completed = not self.todos[index].completed
self.save_todos()
def remove_todo(self, index):
# 删除待办事项
del self.todos[index]
self.save_todos()
def save_todos(self):
# 保存待办事项到JSON文件
data = [todo.to_dict() for todo in self.todos]
with open('todo_data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def load_todos(self):
# 从JSON文件加载待办事项
if os.path.exists('todo_data.json'):
with open('todo_data.json', 'r', encoding='utf-8') as f:
data = json.load(f)
self.todos = [TodoItem.from_dict(item) for item in data]
# 应用入口
class TodoApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(TodoScreen(name='todo'))
return sm
if __name__ == '__main__':
TodoApp().run()
5.3.2 KV 布局文件todo.kv
#:kivy 2.1.0
< TodoListItem >:
# 复选框
CheckBox:
active: root.completed
on_active: root.parent.parent.parent.toggle_completed(root.index)
size_hint: (0.1, 1)
# 文本内容
BoxLayout:
orientation: 'vertical'
spacing: 5
size_hint: (0.7, 1)
padding: 5
Label:
id: title_label
text: root.title
font_size: 18
bold: True
size_hint: (1, 0.5)
Label:
id: content_label
text: root.content
font_size: 14
size_hint: (1, 0.5)
# 删除按钮
Button:
text: '删除'
font_size: 14
background_color: 0.9, 0.3, 0.3, 1
size_hint: (0.2, 1)
on_press: root.delete()
<TodoScreen>:
BoxLayout:
orientation: 'vertical'
spacing: 15
padding: 20
# 标题
Label:
text: '跨平台待办事项App'
font_size: 28
bold: True
size_hint: (1, 0.1)
# 输入区域
BoxLayout:
orientation: 'vertical'
spacing: 10
size_hint: (1, 0.2)
TextInput:
id: title_input
hint_text: '请输入待办标题'
font_size: 16
size_hint: (1, 0.5)
TextInput:
id: content_input
hint_text: '请输入待办内容'
font_size: 16
size_hint: (1, 0.5)
# 添加按钮
Button:
text: '添加待办事项'
font_size: 18
background_color: 0.2, 0.7, 0.2, 1
size_hint: (1, 0.1)
on_press: root.add_todo()
# 待办事项列表
ScrollView:
size_hint: (1, 0.5)
BoxLayout:
id: todo_list
orientation: 'vertical'
spacing: 10
size_hint: (1, None)
height: self.minimum_height # 自适应高度
# 动态生成待办事项列表项
BoxLayout:
id: todo_items
orientation: 'vertical'
spacing: 10
size_hint: (1, None)
height: self.minimum_height
# 绑定待办事项列表,动态更新UI
on_parent:
for i, todo in enumerate(root.todos):
item = TodoListItem()
item.title = todo.title
item.content = todo.content
item.completed = todo.completed
item.index = i
self.add_widget(item)
# 监听todos变化,更新UI
root.bind(todos=lambda x, y: self.update_items(y))
# 更新列表项的方法
def update_items(self, todos):
self.clear_widgets()
for i, todo in enumerate(todos):
item = TodoListItem()
item.title = todo.title
item.content = todo.content
item.completed = todo.completed
item.index = i
self.add_widget(item)
5.4 项目运行与打包
5.4.1 运行项目
- 创建
todo_app文件夹,将main.py和todo.kv放入其中; - 运行
python main.py,即可启动待办事项 App; - 添加的待办事项会自动保存到
todo_data.json文件中,下次启动时自动加载。
5.4.2 打包为移动应用(Android)
使用 Buildozer 工具将项目打包为 APK 文件:
- 安装 Buildozer:
pip install buildozer; - 在项目目录执行:
buildozer init,生成buildozer.spec配置文件; - 修改配置文件:设置
package.name、package.domain、source.dir等参数; - 执行打包命令:
buildozer android debug deploy run,生成 APK 文件。
六、避坑指南与最佳实践
6.1 常见错误与解决方案
| 错误类型 | 常见原因 | 解决方案 |
|---|---|---|
| KV 文件不生效 | 文件名与 App 类名不匹配 | 确保 KV 文件名为首字母小写的 App 类名(如TodoApp对应todo.kv) |
| 组件 ID 无法引用 | ID 引用路径错误 | 通过root.ids.id_name或self.manager.get_screen('screen_name').ids.id_name引用 |
| 界面布局错乱 | 未设置 size_hint 或 height 属性 | 对垂直排列的 BoxLayout 设置height: self.minimum_height,确保自适应高度 |
| 数据绑定失效 | 未使用 Kivy 的 Property 类型 | 自定义属性需继承NumericProperty、StringProperty等,而非普通 Python 属性 |
| 移动打包失败 | 依赖库缺失或配置错误 | 确保 Buildozer 配置文件正确,依赖库版本兼容,可通过buildozer android logcat查看错误日志 |
6.2 开发最佳实践
- UI 与逻辑分离:使用 KV 语言编写 UI 布局,Python 代码处理业务逻辑,提升代码可读性和维护性;
- 数据持久化:简单数据使用 JSON 文件,复杂数据可使用 SQLite 或 ORM 框架(如 Peewee);
- 性能优化:避免在主线程执行耗时操作,使用
Clock.schedule_once或线程处理;大量数据展示时使用RecycleView替代 BoxLayout; - 跨平台适配:使用
size_hint和pos_hint设置组件尺寸和位置,避免固定像素值;测试时兼顾桌面和移动设备; - 代码复用:自定义 Widget 组件,提取通用功能为工具类,减少重复代码;
- 交互体验:为关键操作添加动画效果,提供明确的反馈(如按钮点击、数据加载)。
总结与展望

Kivy 作为一款专注于跨平台触控应用的 Python GUI 框架,以其独特的 KV 语言、强大的动画系统和原生移动支持,为开发者提供了灵活高效的开发方案。本文从环境搭建、核心组件、布局管理,到 KV 语言、动画效果、数据绑定,再到完整实战项目,系统覆盖了 Kivy 开发的关键知识点,帮助你从入门到精通。
Kivy 的应用场景广泛,除了常规的移动应用和桌面工具,还可用于开发游戏、多媒体应用、嵌入式设备界面等。随着移动开发需求的增长,Kivy 凭借其 “一次编写、多端运行” 的优势,将在 Python 跨平台开发领域占据重要地位。
未来学习中,可进一步探索 Kivy 的高级功能,如 Kivy Garden(第三方组件库)、3D 图形渲染、网络通信集成等,打造更复杂、更专业的跨平台应用。
7494

被折叠的 条评论
为什么被折叠?



