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")
关键修改点说明
- 自定义View的初始化:在
__init__调用super().__init__时,直接传入route、padding等View的核心属性,不用等到build方法再创建新View。 - build方法的调整:不再返回新的
ft.View实例,而是把需要的控件添加到当前View的self.controls列表中。 - 修正参数传反问题:实例化
WelcomeView和LoginView时,把window_width和window_height的顺序调整正确,避免布局错乱。 - 修复索引越界:在
update_layout里加了val != 0的判断,防止val=0时访问colors[-1]导致索引错误。
这样修改后,你的自定义View就是合法的ft.View子类实例了,添加到page.views里就能正常识别,路由跳转也能正常工作啦~
备注:内容来源于stack exchange,提问作者eljamba
相关产品推荐
相关产品推荐

