PythonIDE Docs
中文
简体中文

媒体

图片、相册、相机、地图、视频和 WebView 的页面模式。

appui 中与图片、相册、相机、文件导入、视频、网页与地图相关的视图。下列示例均可在应用内 AppUI 预览环境运行。

#预期效果

示例会展示图片、网络图、相册、文件、相机、视频、网页和地图控件如何嵌入 AppUI 页面。

#设计原则

  • 资源图Image(name=...)SF SymbolsImage(system_name=...)
  • 网络图AsyncImage,占位与失败视图通过子视图传入。
  • 相册 / 相机返回的是设备上的文件路径字符串(由系统写入临时目录后回调)。
  • Files App / 文档提供方FileImporter,默认复制到 App 可访问位置后返回路径列表。
  • WebView 只能二选一:urlhtml
  • MapViewmarkers 为字典列表,键包括 latitudelongitudetitle

#Image:本地资源与 SF Symbol

Image 支持链式修饰:resizable()aspect_ratio(ratio, content_mode)symbol_rendering_mode(mode)image_scale(scale)

python
import appui

state = appui.State(kind="SF Symbol")


def body():
    return appui.NavigationStack(
        appui.VStack([
            appui.Text(state.kind).font("headline"),
            appui.Image(system_name="star.fill")
                .resizable()
                .aspect_ratio(content_mode="fit")
                .symbol_rendering_mode("palette")
                .image_scale("large")
                .frame(width=56, height=56)
                .foreground_color("systemYellow"),
            appui.Label("设置", system_image="gear"),
        ], spacing=16).padding()
        .navigation_title("Image")
    )


appui.run(body, state=state, presentation="sheet")

content_mode'fit''fill'symbol_rendering_mode 常用:'hierarchical''palette''multicolor'(未识别时回退为单色)。

image_scale'small''medium'(默认)、'large'


#AsyncImage:网络图片

参数:urlplaceholdererror_viewcontent_modeon_successon_failure。占位与错误视图为子节点(前两个子视图依次为占位、错误)。

python
import appui

state = appui.State(status="等待加载")


def image_loaded():
    state.status = "图片已加载"


def image_failed():
    state.status = "图片加载失败"


def body():
    return appui.NavigationStack(
        appui.VStack([
            appui.AsyncImage(
                url="https://www.apple.com/ac/structured-data/images/knowledge_graph_logo.png",
                placeholder=appui.ProgressView(label="Loading"),
                error_view=appui.Image(system_name="exclamationmark.triangle"),
                content_mode="fit",
                on_success=image_loaded,
                on_failure=image_failed,
            ).frame(height=120),
            appui.LabeledContent("状态", value=state.status),
        ], spacing=16).padding()
        .navigation_title("AsyncImage")
    )


appui.run(body, state=state, presentation="sheet")

#PhotoPicker:相册

selection_limit1 表示单选;0 表示不限制(以系统行为为准)。filter'images''videos''all'on_picked 收到 路径列表

python
import appui

state = appui.State(paths=[])


def on_picked(paths):
    state.paths = paths or []


def body():
    return appui.VStack([
        appui.Text("已选: " + (" | ".join(state.paths) if state.paths else "无")).font("caption"),
        appui.PhotoPicker(
            selection_limit=1,
            filter="images",
            on_picked=on_picked,
            label=appui.Label("选择照片", system_image="photo.on.rectangle"),
        ),
    ], spacing=12).padding()

appui.run(body, state=state, presentation="sheet")

#FileImporter:文件导入

allowed_types 可传类型名、扩展名或 MIME 类型,例如 'text''pdf''csv''image/png'allows_multiple=True 允许多选。copy=True 是默认值,表示先复制进 App 可访问位置,再把路径列表传给 on_picked

python
import appui

state = appui.State(files=[])


def on_files(paths):
    state.files = paths or []


def body():
    rows = [
        appui.Text(path).font("caption").line_limit(1)
        for path in state.files
    ]
    return appui.NavigationStack(
        appui.Form([
            appui.Section("导入", [
                appui.FileImporter(
                    allowed_types=["text", "pdf", "csv"],
                    allows_multiple=True,
                    on_picked=on_files,
                    label=appui.Label("选择文件", system_image="doc.badge.plus"),
                ),
            ]),
            appui.Section("文件", rows or [
                appui.ContentUnavailableView("暂无文件", system_image="doc", description="从系统文件选择器导入")
            ]),
        ]).navigation_title("文件导入")
    )


appui.run(body, state=state, presentation="sheet")

文件选择由系统界面完成;用户取消时通常不会触发有效路径。需要读取文件内容时,在回调里保存路径,再在按钮动作、刷新函数或后台流程中读取,避免在 body() 里同步读大文件。


#CameraPicker:相机

source'camera''front'media_type'photo''video'on_captured 收到单个路径字符串

python
import appui

state = appui.State(last="")


def on_captured(path):
    state.last = path or ""


def body():
    return appui.VStack([
        appui.Text(state.last or "尚未拍摄").font("caption"),
        appui.CameraPicker(
            source="camera",
            media_type="photo",
            on_captured=on_captured,
            label=appui.Label("拍照", system_image="camera.fill"),
        ),
    ], spacing=12).padding()

appui.run(body, state=state, presentation="sheet")

#VideoPlayer:AVKit

url 可为远程 HTTPS 或应用内可访问的本地文件名。autoplayloopshow_controls 控制播放行为。

只展示视频时直接用 VideoPlayer(url=...)。如果页面需要播放/暂停/seek、保存进度、倍速、PiP 状态或切集,使用 PlayerController 并传给 VideoPlayer(player=player);AppUI 新页面不要再 import avplayer 控制同一块内嵌视频。

python
import appui

state = appui.State(status="可播放")

def body():
    return appui.NavigationStack(
        appui.VStack([
            appui.VideoPlayer(
                url="https://media.w3.org/2010/05/sintel/trailer.mp4",
                autoplay=False,
                loop=False,
                show_controls=True,
            ).frame(height=220),
            appui.LabeledContent("状态", value=state.status),
        ], spacing=16).padding()
        .navigation_title("VideoPlayer")
    )

appui.run(body, state=state, presentation="sheet")

#WebView:URL 或 HTML

python
import appui

state = appui.State()

def body():
    return appui.WebView(
        html="<html><body style='font-family:system-ui'><h1>appui</h1><p>内嵌 HTML</p></body></html>"
    ).frame(height=360).padding()

appui.run(body, state=state, presentation="sheet")

远程页面示例:appui.WebView(url="https://www.apple.com").frame(height=360)


#MapView:地图与标注

默认中心为旧金山坐标。span 为经纬跨度。map_style 可为 'automatic'(默认,不传样式)、'standard''satellite''hybrid'

python
import appui

state = appui.State()

def body():
    return appui.MapView(
        latitude=37.7749,
        longitude=-122.4194,
        span=0.08,
        markers=[
            {"latitude": 37.78, "longitude": -122.40, "title": "标记 A"},
        ],
        map_style="standard",
    ).frame(height=280).padding()

appui.run(body, state=state, presentation="sheet")

#与旧版 ui 模块对照(迁移)

ui 为 Pythonista 风格命令式 API;同一应用内可对照理解差异:

python
import ui

v = ui.View()
b = ui.Button(title="Go")


def on_button(sender):
    pass


b.action = on_button
v.add_subview(b)
# v.present('sheet')  # 需在 AppUI 预览环境中调用

appui 用声明式 body() 返回 View,由 appui.run(body, state=..., presentation="sheet") 呈现。


#小结

视图典型用途
Image资源图、SF Symbol、缩放与宽高比
AsyncImage网络图片与阶段 UI
PhotoPicker / CameraPicker系统相册与相机,路径回调
FileImporter系统文件选择器,路径列表回调
VideoPlayer流媒体或本地视频
WebViewurlhtml 嵌入网页
MapView坐标、跨度、标注与样式

更完整的参数说明见同目录下的 appui-ref-media.md