材质Python。具有OpenGL效果的自定义卡


问候,亲爱的爱好者和Python专家!

在本文中,我将向您展示如果您在应用程序中使用跨平台工具(例如Kivy框架和该框架的材料设计库KivyMD)如何将OpenGL效果应用于自定义卡我们走吧!

KivyMD具有一个标准组件MDCard-用于创建各种自定义卡的基本类(Material Design规范,Cards)。如果您不讲细节,那么MDCard的下面就是常规的BoxLayout,它是一个允许您将其他小部件以垂直或水平方向放置的容器。也就是说,如果您需要制作某种卡(例如,有关用户的信息),则可以自己完成。MDCard仅实现ripple_behaviortouch_behavior和投射阴影:

显示空白卡的程序的示例如下:

from kivy.lang import Builder

from kivymd.app import MDApp

KV = '''
Screen:  #  

    MDCard:  # 
        #    
        size_hint: .6, .5
        pos_hint: {"center_x": .5, "center_y": .5}
'''


class TestCard(MDApp):
    def build(self):
        return Builder.load_string(KV)

TestCard().run()

结果:


看起来很简单。但是,如果我们希望获得焦点模糊的精美卡片怎么办?例如,在Flutter UI Designs应用程序中


必须自己动手!而且,这没有什么复杂的。首先,创建未来地图的基类:

class RestaurantCard(MDCard):
    source = StringProperty()  #     
    shadow = StringProperty()  #    -
    text = StringProperty()  #  

卡片的主要图片:


阴影影像:


现在,我们将使用特殊的Kv语言 DSL语言其属性是为了方便设计界面布局而设计)确定其属性的组件填充地图

<RestaurantCard>
    elevation: 12

    RelativeLayout:

        # ,       .
        FitImage:  #   
            source: root.source

        FitImage:  # -
            source: root.shadow
            size_hint_y: None
            height: "120dp"

        MDLabel:  #  
            text: root.text
            markup: True
            size_hint_y: None
            height: self.texture_size[1]
            x: "10dp"
            y: "10dp"
            theme_text_color: "Custom"
            text_color: 1, 1, 1, 1

我们在地图上放置了RelativeLayout小部件,通过这种方式,我们可以将各个组件混合在一起:


首先,我们放置主图像,在顶部放置阴影和文本。现在,如果我们运行代码:

from kivy.lang import Builder
from kivy.properties import StringProperty

from kivymd.app import MDApp
from kivymd.uix.card import MDCard

KV = """
<RestaurantCard>
    elevation: 12

    RelativeLayout:

        FitImage:
            source: root.source

        FitImage:
            source: root.shadow
            size_hint_y: None
            height: "120dp"

        MDLabel:
            text: root.text
            markup: True
            size_hint_y: None
            height: self.texture_size[1]
            x: "10dp"
            y: "10dp"
            theme_text_color: "Custom"
            text_color: 1, 1, 1, 1


Screen:

    RestaurantCard:
        text: "[size=23][b]Restaurant[/b][/size]\\nTuborg Havnepark 15, Hellerup 2900 Denmark"
        shadow: "shadow-black.png"
        source: "restourant.jpg"
        pos_hint: {"center_x": .5, "center_y": .5}
        size_hint: .7, .5
"""


class RestaurantCard(MDCard):
    source = StringProperty()
    text = StringProperty()
    shadow = StringProperty()


class BlurCard(MDApp):
    def build(self):
        return Builder.load_string(KV)

BlurCard().run()

...我们得到结果:


当然,结果与预期的结果相去甚远,因为我们不会在卡上看到任何模糊效果或圆形边缘。让我们从模糊效果开始。Kivy具有标准的EffectWidget小部件,可将各种图形效果应用于其子级。它通过使用自定义OpenGL着色器渲染Fbo实例来工作。我们需要对卡上的主图像和阴影图像应用模糊效果。因此,我们必须将它们的组件放在EffectWidget小部件中:

#:import effect kivy.uix.effectwidget.EffectWidget
#:import HorizontalBlurEffect kivy.uix.effectwidget.HorizontalBlurEffect

<RestaurantCard>

    ...

    RelativeLayout:
        
        #   ,      .
        EffectWidget:
            #  .
            effects: (HorizontalBlurEffect(size=root.blur),)

            FitImage:
                source: root.source

            FitImage:
                source: root.shadow
                size_hint_y: None
                height: "120dp"

    ...    

为模糊效果的值添加一个字段:

class RestaurantCard(MDCard):
    ...
    blur = NumericProperty(8)

我们开始看看:


当您将鼠标悬停在(如果是台式机)或点击(如果是移动机)时,将不会发生任何事情。为了使卡响应on_focus事件,我们必须在RestaurantCard规则的属性中启用对此事件的读取,并分配在注册此事件时将执行的方法:

#:import Animation kivy.animation.Animation

<RestaurantCard>
    focus_behavior: True  #    on_focus
    # ,       .
    #   Animation,    .
    on_enter: Animation(blur=0, d=0.3).start(self)
    on_leave: Animation(blur=8, d=0.3).start(self)

已经更好了:


为了修剪卡的角落,我决定对EffectWidget小部件应用一个模板(模板):

#:import Stencil kivymd.uix.graphics.Stencil


#   ,   EffectWidget  Stencil.
<Effect@EffectWidget+Stencil>
    radius: [20,]


<RestaurantCard>
    ...

    RelativeLayout:

        Effect:
            ...

现在一切都按我们的计划进行:


完整的示例代码
from kivy.lang import Builder
from kivy.properties import StringProperty, NumericProperty

from kivymd.app import MDApp
from kivymd.uix.card import MDCard

KV = """
#:import Stencil kivymd.uix.graphics.Stencil
#:import Animation kivy.animation.Animation
#:import effect kivy.uix.effectwidget.EffectWidget
#:import HorizontalBlurEffect kivy.uix.effectwidget.HorizontalBlurEffect


<Effect@EffectWidget+Stencil>
    radius: [20,]


<RestaurantCard>
    md_bg_color: 0, 0, 0, 0
    elevation: 12
    focus_behavior: True
    on_enter: Animation(blur=0, d=0.3).start(self)
    on_leave: Animation(blur=8, d=0.3).start(self)
    radius: [20,]

    RelativeLayout:

        Effect:
            effects: (HorizontalBlurEffect(size=root.blur),)

            FitImage:
                source: root.source

            FitImage:
                source: root.shadow
                size_hint_y: None
                height: "120dp"

        MDLabel:
            text: root.text
            markup: True
            size_hint_y: None
            height: self.texture_size[1]
            x: "10dp"
            y: "10dp"
            theme_text_color: "Custom"
            text_color: 1, 1, 1, 1


FloatLayout:

    RestaurantCard:
        text: "[size=23][b]Restaurant[/b][/size]\\nTuborg Havnepark 15, Hellerup 2900 Denmark"
        shadow: "shadow-black.png"
        source: "restourant.jpg"
        pos_hint: {"center_x": .5, "center_y": .5}
        size_hint: .7, .5
"""


class RestaurantCard(MDCard):
    source = StringProperty()
    text = StringProperty()
    shadow = StringProperty()
    blur = NumericProperty(8)


class BlurCard(MDApp):
    def build(self):
        return Builder.load_string(KV)


BlurCard().run()


好吧,最后,我想展示一个包含两个程序的视频:一个使用Flutter框架编写,第二个使用Kivy和KivyMD。在本文的结尾,我留下了一个调查,您需要在其中猜测使用哪种技术以及在哪里使用。


All Articles