视频播放器 MiniApp
VideoPlayer、片源搜索、播放状态和播放设置。
演示 appui.VideoPlayer 与 TabView:播放页、可搜索片源列表与播放设置表单。
#预期效果
运行后会出现视频播放器页面,片源搜索、播放区域和播放设置保持分区清晰。
#完整示例
已复制
import appui
DEFAULT_SOURCES = [
{
"id": "sintel",
"title": "Sintel Trailer",
"url": "https://media.w3.org/2010/05/sintel/trailer.mp4",
"tag": "默认",
},
{
"id": "bbb",
"title": "Big Buck Bunny",
"url": (
"https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/720/"
"Big_Buck_Bunny_720_10s_1MB.mp4"
),
"tag": "测试",
},
]
state = appui.State(
selected_id="sintel",
query="",
autoplay=False,
loop=False,
show_controls=True,
status="正在播放 Sintel Trailer",
)
def selected_source():
for item in DEFAULT_SOURCES:
if item["id"] == state.selected_id:
return item
return DEFAULT_SOURCES[0]
def set_query(value):
state.query = str(value)
def select_source(source_id):
item = next((row for row in DEFAULT_SOURCES if row["id"] == source_id), DEFAULT_SOURCES[0])
state.batch_update(selected_id=source_id, status=f"已切换到 {item['title']}")
def toggle_autoplay(value):
state.batch_update(autoplay=bool(value), status="已更新自动播放设置")
def toggle_loop(value):
state.batch_update(loop=bool(value), status="已更新循环播放设置")
def toggle_controls(value):
state.batch_update(show_controls=bool(value), status="已更新控制条设置")
def source_row(item):
def choose():
select_source(item["id"])
active = item["id"] == state.selected_id
icon = "play.circle.fill" if active else "play.circle"
return appui.Button(
action=choose,
content=appui.HStack(
[
appui.Image(system_name=icon).foreground_color("systemBlue"),
appui.VStack(
[
appui.Text(item["title"]).font("headline"),
(
appui.Text(item["url"])
.font("caption")
.foreground_color("secondaryLabel")
.line_limit(1)
),
],
alignment="leading",
spacing=3,
),
appui.Spacer(),
appui.Text(item["tag"]).font("caption").foreground_color("secondaryLabel"),
],
spacing=10,
),
)
def filtered_sources():
q = state.query.strip().lower()
if not q:
return DEFAULT_SOURCES
return [
item for item in DEFAULT_SOURCES
if q in item["title"].lower() or q in item["url"].lower() or q in item["tag"].lower()
]
def source_key(item):
return item["id"]
def source_list_rows():
sources = filtered_sources()
if not sources:
return [
appui.ContentUnavailableView(
"没有匹配片源",
system_image="magnifyingglass",
description="换个关键词,或清空搜索条件。",
)
]
return [appui.ForEach(sources, row_builder=source_row, key=source_key)]
def player_page():
item = selected_source()
player = appui.VideoPlayer(
url=item["url"],
autoplay=state.autoplay,
loop=state.loop,
show_controls=state.show_controls,
presentation="inline",
allows_fullscreen=True,
allows_pip=True,
allows_airplay=True,
).frame(height=240)
details = appui.Form(
[
appui.Section(
[
appui.LabeledContent("标题", value=item["title"]),
appui.LabeledContent("标签", value=item["tag"]),
appui.LabeledContent("状态", value=state.status),
appui.Text(item["url"]).font("caption").foreground_color("secondaryLabel"),
],
header="当前片源",
),
]
)
return appui.NavigationStack(
appui.VStack([player, details], spacing=0)
.navigation_title("播放器")
)
def sources_page():
rows = source_list_rows()
return appui.NavigationStack(
appui.List([
appui.Section(
rows,
header="片源",
footer="点击片源会立即更新播放页。",
)
])
.searchable(text=state.query, on_change=set_query)
.navigation_title("片源")
)
def settings_page():
return appui.NavigationStack(
appui.Form(
[
appui.Section(
[
appui.Toggle("自动播放", is_on=state.autoplay, on_change=toggle_autoplay),
appui.Toggle("循环播放", is_on=state.loop, on_change=toggle_loop),
appui.Toggle("显示控制条", is_on=state.show_controls, on_change=toggle_controls),
],
header="播放设置",
),
]
).navigation_title("设置")
)
def body():
return appui.TabView(
[
appui.Tab("播放", system_image="play.rectangle", tag=0, content=player_page()),
appui.Tab("片源", system_image="list.bullet", tag=1, content=sources_page()),
appui.Tab("设置", system_image="gearshape", tag=2, content=settings_page()),
],
selection=0,
)
appui.run(body, state=state, presentation="fullscreen_with_close")
#关键技巧
- 用
VStack把VideoPlayer固定在页面上方,下方再用Form/List,避免把播放器塞进普通列表段落。 - 片源列表用
List(...).searchable(...),动态行通过ForEach(..., key=...)保持稳定身份;无匹配时展示空状态。 - 播放器、地图、WebView 这类大媒体视图固定在页面主区域,下方再放
Form/List控件。 VideoPlayer可配presentation、allows_fullscreen、allows_pip、allows_airplay等。