You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flet框架下主页面展示多自定义视图及路由实现问题(解决Unknown control view错误)

Flet框架下主页面展示多自定义视图及路由实现问题(解决Unknown control view错误)

嘿,我来帮你捋捋这个问题哈!你遇到的"Unknown control view"错误,核心原因是自定义View类的写法不对——你继承了ft.View,但又在build方法里返回了一个全新的ft.View实例,相当于把View嵌套起来了,Flet根本没法识别这种嵌套的结构作为页面视图~

问题拆解

你的WelcomeView和LoginView都继承了ft.View,但在build里又重新创建了一个ft.View并返回,这就导致最终添加到page.views里的不是一个合法的View实例,而是一个包裹着View的自定义类对象,Flet自然就报错啦。另外还发现你实例化视图时把window_height和window_width传反了,这个小问题也得改哦!

修复方案

我们需要调整自定义View类的实现:既然已经继承了ft.View,那就直接在类里配置当前实例的属性(比如route、padding、controls等),不需要再额外创建新的View。

下面是修改后的完整代码,我标了关键修改点:

import flet as ft
import time

class WelcomeView(ft.View):
    def __init__(self, window_width, window_height, login_on_click, route):
        # 直接在super().__init__里传入View的核心参数
        super().__init__(
            route=route,
            padding=0,
            horizontal_alignment="center",
            vertical_alignment="top"
        )      
        self.window_width = window_width
        self.window_height = window_height
        self.login_on_click = login_on_click

    def update_layout(self):
        colors = [ft.colors.GREEN_50, ft.colors.GREEN_100, ft.colors.GREEN_200, ft.colors.GREEN_300, ft.colors.GREEN_400, ft.colors.GREEN_500, ft.colors.GREEN_600, ft.colors.GREEN_700, ft.colors.GREEN_800, ft.colors.GREEN_900]

        val=0
        while val < 101:
            self.pb.value = val * 0.01
            time.sleep(0.05)
            mod = val % 10
            if mod == 0 and val != 0:  # 修正val=0时的索引越界问题
                self.topContainer.bgcolor = colors[int(val/10) - 1]
                self.loginButton.style = ft.ButtonStyle(bgcolor=colors[int(val/10) - 1])
            val += 1
            if val == 100:
                val=0
            self.update()

    def did_mount(self):
        self.update_layout()

    def build(self):
        self.topContainer = ft.Container(
            bgcolor=ft.colors.GREEN, 
            width=self.window_width,
            height=self.window_height * 0.25,
        )
        self.pb = ft.ProgressBar()
        self.loginButton=ft.FilledButton(text="LOGIN", on_click = self.login_on_click)
        self.bottomContainer = ft.Container(
            width=self.window_width,
            height=self.window_height * 0.75,
            content=ft.Column(
                [self.loginButton],
                alignment="CENTER",
                horizontal_alignment="CENTER",                                          
            ), 
        ) 
        # 直接把控件添加到当前View的controls列表里,不用再创建新View
        self.controls = [
            ft.Column([self.topContainer, self.pb, self.bottomContainer], spacing=0,)
        ]
        # 继承ft.View的build方法可以不用返回值,或者返回self.controls也可以
        return self.controls

class LoginView(ft.View):
    def __init__(self, window_width, window_height, route, on_click):
        super().__init__(
            route=route,
            padding=0,
            horizontal_alignment="center",
            vertical_alignment="top"
        )      
        self.window_width = window_width
        self.window_height = window_height
        self.back_on_click = on_click
    
    def build(self):
        # 直接配置当前View的controls
        self.controls = [
            ft.Column([ft.FilledButton(text="BACK", on_click=self.back_on_click)], )
        ]
        return self.controls

def main(page: ft.Page):
    def route_change(route):        
        page.views.clear()
        page.views.append(welcome_view)

        if page.route == "/login_view":
            page.views.append(login_view)

        page.update()

    def view_pop(view):     
        if page.route == "/login_view":
            page.go("/")

    page.theme = ft.Theme(color_scheme_seed = ft.colors.GREEN)
    page.theme_mode = "light"
    page.window_height = 700
    page.window_width = 400
    page.window_resizable = False
    page.window_maximizable = False
    page.title = "Mobile App UI Example"

    # 修正window_height和window_width的传参顺序
    welcome_view = WelcomeView(
        window_width=page.window_width, 
        window_height=page.window_height, 
        route="/",
        login_on_click=lambda _: page.go("/login_view"),
    )
    login_view = LoginView(
        window_width=page.window_width, 
        window_height=page.window_height, 
        route="/login_view",
        on_click=lambda _: page.go("/")
    )
    page.on_route_change = route_change
    page.on_view_pop = view_pop
    page.go(page.route)

ft.app(target=main, assets_dir="assets")

关键修改点说明

  1. 自定义View的初始化:在__init__调用super().__init__时,直接传入route、padding等View的核心属性,不用等到build方法再创建新View。
  2. build方法的调整:不再返回新的ft.View实例,而是把需要的控件添加到当前View的self.controls列表中。
  3. 修正参数传反问题:实例化WelcomeView和LoginView时,把window_width和window_height的顺序调整正确,避免布局错乱。
  4. 修复索引越界:在update_layout里加了val != 0的判断,防止val=0时访问colors[-1]导致索引错误。

这样修改后,你的自定义View就是合法的ft.View子类实例了,添加到page.views里就能正常识别,路由跳转也能正常工作啦~

备注:内容来源于stack exchange,提问作者eljamba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 14:08:04