我可以在不使用KV语言的情况下实现这个KivyMD示例吗?

问题描述 投票:0回答:1

我正在尝试实现 kivy Hero 组件的这个 example,但不使用 KV language

from kivy.animation import Animation
from kivy.clock import Clock
from kivy.properties import StringProperty, ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.scrollview import ScrollView
from kivymd.app import MDApp
from kivymd.uix.hero import MDHeroFrom, MDHeroTo
from kivymd.uix.imagelist.imagelist import MDSmartTile, MDSmartTileImage, MDSmartTileOverlayContainer
from kivy.metrics import dp
from kivymd.uix.button import MDButton, MDButtonIcon, MDButtonText
from kivymd.uix.screen import MDScreen
from kivymd.uix.screenmanager import MDScreenManager
from kivymd.uix.label.label import MDLabel
from kivymd.uix.scrollview import StretchOverScrollStencil, MDScrollView
from kivymd.uix.gridlayout import MDGridLayout
from kivy.core.window import Window

class HeroItem(MDHeroFrom):
    text = StringProperty()
    tag = StringProperty()
    manager = ObjectProperty()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.size_hint_y = None
        self.height = "200dp"
        self.radius = "24dp"
        window_width, window_height = Window.size

    def create_tile(self, img_path):
        # Create SmartTile
        print('type', type(Window.size), type(self.manager), self.manager)
        print('parent_size', (self.width, self.height), Window.size, self.manager.size)
        print('self.manager', self.manager, self.size_hint)
        self.tile = MDSmartTile(id='tile', size_hint=(None, None))#pos_hint={"x": 0, "y": 0.1}, - not worked
        self.tile.size = self.manager.size
        #size_hint=(None, None) should be None, then only the smooth opening and closing is happening on each tile
        #size=(380, 200) is fine but rearrening the window size it is not dynamic
        self.tile.bind(on_release=self.on_release)

        # Create SmartTileImage
        self.image = MDSmartTileImage(id='image', source=img_path, radius="24dp",)
        #self.image.size = self.tile.size
        self.image.ripple_duration_in_fast = 0.05
        self.tile.add_widget(self.image)

        # Create Overlay Container
        self.overlay = MDSmartTileOverlayContainer(id='overlay',
                                                md_bg_color=(0, 0, 0, .5),
                                                adaptive_height=True,
                                                radius=[0, 0, dp(24), dp(24)],
                                                    padding="8dp",
                                                    spacing="8dp",
                                                )

        #self.overlay.size = self.tile.size

        # Create Label
        #self.label = Label(text=self.tag, color=(1, 1, 1, 1), size_hint_y=None, height=dp(40))
        self.label = MDLabel(text=self.tag+str(Window.size[0]), theme_text_color='Custom', text_color="white", adaptive_height=True)
        self.overlay.add_widget(self.label)
        self.tile.add_widget(self.overlay)

        self.add_widget(self.tile)

    def on_transform_in(self, instance_hero_widget, duration):
        print('in', duration)
        for instance in [
            instance_hero_widget,
            instance_hero_widget._overlay_container,
            instance_hero_widget._image,
        ]:
            Animation(radius=[0, 0, 0, 0], duration=duration).start(instance)

    def on_transform_out(self, instance_hero_widget, duration):
        print('on', duration)
        for instance, radius in {
            instance_hero_widget: [dp(24), dp(24), dp(24), dp(24)],
            instance_hero_widget._overlay_container: [0, 0, dp(24), dp(24)],
            instance_hero_widget._image: [dp(24), dp(24), dp(24), dp(24)],
        }.items():
            print('radius', radius)
            Animation(
                radius=radius,
                duration=duration,
            ).start(instance)

    def on_release(self, *args):
        print('a')
        def switch_screen(*args):
            #print('self.manager.current_heroes', self.manager.current_heroes)
            self.manager.current_heroes = [self.tag]
            #print('self.manager.current_heroes', self.manager.current_heroes)

            print('?', dir(self.manager.ids))
            print('tag', self.tag)
            screen_b = self.manager.get_screen("screen B")
            screen_b.hero_to.tag = self.tag
            self.manager.current = "screen B"

        Clock.schedule_once(switch_screen, 0.2)


#class ScreenA(MDScreen):
#    pass


class ScreenB(MDScreen):
    hero_to = ObjectProperty()  # Use ObjectProperty

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.hero_to = MDHeroTo(size_hint=(1, None), height="220dp", pos_hint={"top": 1})
        self.add_widget(self.hero_to)

        self.button = MDButton(MDButtonText(text="Move Hero To Screen A"), 
                            pos_hint={"center_x": .5}, y = "36dp")#size_hint_y=None, height=dp(50)
        self.button.bind(on_release=self.switch_to_screen_a)
        self.add_widget(self.button)

    def switch_to_screen_a(self, *args):
        print('b', self.hero_to.tag)
        self.manager.current = "screen A"
        self.manager.current_heroes = [self.hero_to.tag]

class Example(MDApp):
    def build(self):
        self.theme_cls.theme_style_switch_animation = True
        self.theme_cls.primary_palette = "Orange"
        self.theme_cls.theme_style = "Dark"  # "Light"
        print('self.theme_cls.backgroundColor', self.theme_cls.backgroundColor)
        
        self.manager = MDScreenManager()
        self.manager.primary_palette = "Orange"
        self.manager.theme_style = "Dark"  # "Light"
        self.manager.md_bg_color = (1, 1, 1, 1) #self.theme_cls.backgroundColor
        
        screen_a = MDScreen(name="screen A")
        screen_b = ScreenB(name="screen B")

        # ScrollView
        scroll_view = MDScrollView()
        grid = MDGridLayout(cols=2, spacing="12dp", padding="12dp", adaptive_height = True,)
        #print('grid', dir(grid))
        #print('??', grid.width, grid.height, grid.x, grid.y, grid.adaptive_height, grid.adaptive_width, grid.adaptive_size,
        #      grid.line_width, grid.minimum_height, grid.minimum_width, grid.minimum_size,
        #      grid.size_hint)
        #grid.width - 100 
        #0 0 0 True False False 1 0 0 [0, 0] 
        #[1, None]
        #grid.bind(minimum_height=grid.setter('height'))
        scroll_view.add_widget(grid)

        screen_a.add_widget(scroll_view)
        self.manager.add_widget(screen_a)
        self.manager.add_widget(screen_b)

        # Add HeroItems to Grid
        for i in range(12):
            hero_item = HeroItem(text=f"Item {i + 1}", tag=f"Tag {i}", manager=self.manager)
            hero_item.create_tile('3.png')
            if not i % 2:
                hero_item.md_bg_color = "lightgrey"
            grid.add_widget(hero_item)

        return self.manager


Example().run()

但是,图像未按正确顺序显示。另外,当我调整窗口大小时,图像不会根据窗口大小自动调整大小:请参阅输出视频 1

我将

size_hint
MDSmartTile
参数从
(None, None)
修改为
(0.5, 1)
,然后图像可以正确显示,并且在调整窗口大小时,图像也会根据窗口大小自动调整大小,但是修改此 size_hint 时出现问题 - 打开图像时动画出现失真:请参阅输出视频 2

这可能是参数问题吗?

python-3.x kivy kivy-language kivymd
1个回答
0
投票

我找到了部分解决方案。在此之前,一些观察。

当您调整窗口大小时,布局也会调整大小,这也负责根据子窗口的 size_hint 调整其子窗口的大小。 MDGridLayout 的子级的 size_hint_x 应该为 1,或者 size_hint 为 (1, None)。

因此,您应该为每个 Hero 小部件提供一个大小提示(1,None),以使其水平延伸

图像顺序看起来不错。我看到具有最大标签 ID 的英雄小部件显示在底部。

MDSmartTile 上的大小提示应为 1,1,因为您希望它占用其英雄父级允许的尽可能多的空间。你应该依赖kivy语言;它的存在是为了让您的生活更轻松。

在您基于代码的演示示例中,图块的大小绑定到 Hero 小部件的大小。每当 Hero 小部件尺寸发生变化时,它会自动更新 Tile 小部件的尺寸。 我尝试使用您的代码手动执行此操作,但没有成功。我不确定为什么,但在这种情况下使用 kivy 语言肯定更好。

以下与动画相关的步骤也有帮助:

  1. 将图块的大小提示更改为 (1,1)
  2. 将其更改为 (None, None) 在过渡动画之前
  3. 在过渡动画之后
  4. 将其改回 (1,1)
  5. 这些步骤与在演示代码中添加 MDSharedAxisTransition 相结合,使动画不再那么令人不快。所以,我认为它并不完美。

还请记住:

涉及的主要更改在 on_transform_in 和 on_transform_out 方法内部。
  • 动画中有一个
  • 错误
  • 。当您第一次使用 Hero 小部件转到屏幕 B 时,就会发生这种情况。当你第一次进入屏幕 B 时,动画会按预期播放,然后你返回,当你使用同一个英雄再次进入时,它将播放一个看起来不同的动画。经过数小时的调试却一无所获。
  • from kivy.animation import Animation from kivy.clock import Clock from kivy.lang import Builder from kivy.metrics import dp from kivy.properties import StringProperty, ObjectProperty from kivymd.app import MDApp from kivymd.uix.hero import MDHeroFrom from kivymd.uix.transition import MDSharedAxisTransition KV = ''' <HeroItem> size_hint_x: 1 size_hint_y: None height: "200dp" radius: "24dp" MDSmartTile: id: tile size_hint: None, None size: root.size on_release: root.on_release() MDSmartTileImage: id: image source: 'https://github.com/kivymd/internal/raw/main/logo/kivymd_logo_blue.png' radius: dp(24) MDSmartTileOverlayContainer: id: overlay md_bg_color: 0, 0, 0, .5 adaptive_height: True padding: "8dp" spacing: "8dp" radius: [0, 0, dp(24), dp(24)] MDLabel: text: root.tag theme_text_color: "Custom" text_color: "white" adaptive_height: True MDScreenManager: md_bg_color: self.theme_cls.backgroundColor transition: app.transition MDScreen: name: "screen A" ScrollView: MDGridLayout: id: box cols: 2 spacing: "12dp" padding: "12dp" adaptive_height: True MDScreen: name: "screen B" heroes_to: [hero_to] MDBoxLayout: orientaion: 'horizontal' MDHeroTo: id: hero_to size_hint: 1, None height: "220dp" pos_hint: {"top": 1} MDButton: pos_hint: {"center_x": .5} y: "36dp" on_release: root.current_heroes = [hero_to.tag] root.current = "screen A" MDButtonText: text: "Move Hero To Screen A" ''' def set_size_hint_one(widget): widget.ids.tile.size_hint = (1, 1) def set_size_hint_none(widget): widget.ids.tile.size_hint = (None, None) class HeroItem(MDHeroFrom): text = StringProperty() manager = ObjectProperty() def __init__(self, **kwargs): super().__init__(**kwargs) self.ids.image.ripple_duration_in_fast = 0.05 def on_transform_in(self, instance_hero_widget, duration): set_size_hint_none(self) for instance in [ instance_hero_widget, instance_hero_widget._overlay_container, instance_hero_widget._image, ]: Animation(radius=[0, 0, 0, 0], duration=duration).start(instance) Clock.schedule_once(lambda x: set_size_hint_one(self), duration+0.1) def on_transform_out(self, instance_hero_widget, duration): set_size_hint_none(self) for instance, radius in { instance_hero_widget: [dp(24), dp(24), dp(24), dp(24)], instance_hero_widget._overlay_container: [0, 0, dp(24), dp(24)], instance_hero_widget._image: [dp(24), dp(24), dp(24), dp(24)], }.items(): Animation( radius=radius, duration=duration, ).start(instance) Clock.schedule_once(lambda x: set_size_hint_one(self), duration+0.1) def on_release(self): def switch_screen(*args): self.manager.current_heroes = [self.tag] self.manager.ids.hero_to.tag = self.tag self.manager.current = "screen B" Clock.schedule_once(switch_screen, 0.2) class Example(MDApp): def __init__(self, **kwargs): super().__init__(**kwargs) self.transition = MDSharedAxisTransition() self.transition.transition_axis = "z" self.transition.duration = 0.2 def build(self): return Builder.load_string(KV) def on_start(self): for i in range(12): hero_item = HeroItem( text=f"Item {i + 1}", tag=f"Tag {i}", manager=self.root ) if not i % 2: hero_item.md_bg_color = "lightgrey" self.root.ids.box.add_widget(hero_item) Example().run()
	
© www.soinside.com 2019 - 2024. All rights reserved.