Search code examples
python-3.xkivykivymdmd-card

How to position Async Images inside KivyMD's MDCard in .py File


I would like to position an Async Image inside the kivyMD's MDCard but for some reason the card gets positioned correctly using pos_hint in the x direction but doesn't work the same in the y direction

Code

from kivymd.app import MDApp
from kivymd.uix.screen import Screen
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDRectangleFlatButton
from kivymd.uix.card import MDCard, MDSeparator

from kivy.lang import Builder
from kivy.metrics import dp
from kivy.uix.image import AsyncImage

Builder.load_string("""
<AppScreen>:
    MDBoxLayout:
        canvas.before:
            Color:
                rgba:1,0,0,1 #Red
            Rectangle:
                size:self.size
                pos:self.pos

        orientation:'vertical'
        pos_hint: {'center_x':.5, 'center_y':.4}
        size_hint: (.75, .6)

        ScrollView:
            canvas.before:
                Color:
                    rgba: 0,1,0,.5 #Green
                Rectangle:
                    size:self.size
                    pos:self.pos 
            do_scroll_x:False
            do_scroll_y:True
            pos_hint:{'center_x':0.5, 'center_y':0.5}
            size_hint:(0.5,1)
            MDBoxLayout:
                canvas.before:
                    Color:
                        rgba: 0,0,1,.5
                    Rectangle:
                        size:self.size
                        pos:self.pos 
                orientation:'vertical'
                id:container
                size_hint_y:None #This makes the stuff scroll O.o
                height:self.minimum_height
                spacing:10

    MDRectangleFlatButton:
        text:"Press Me"
        pos_hint:{'center_x':0.5, 'center_y':.8}
        on_release:root.printing()
""")

class AppScreen(Screen):
    def __init__(self, **kwargs):
        super(AppScreen, self).__init__(**kwargs)
        self.scroll_id = self.ids.container
    def printing(self):
        for x in range(5):
            img=AsyncImage(
                source="https://i.redd.it/x1js663rq7s41.jpg",
                pos_hint={'center_x':0.9, 'center_y':0.5},
                size_hint_y=None,
                size=(dp(20), dp(30))
                )
            card = MDCard(
                orientation='vertical',
                pos_hint={'center_x':0.5},
                size_hint=(1, None),
                #size=(dp(100), dp(100)) #Size is required to view stuff in Cards

            )
            card.add_widget(img)
            self.scroll_id.add_widget(card)
class DemoApp(MDApp):
    def build(self):
        self.theme_cls.theme_style="Dark"
        return AppScreen()

DemoApp().run()

Solution

  • I used a another Screen inside the MDCard, and added the Async Image as a child to the new Screen created as layout

    Note: You may want to use GridLayout or BoxLayout if you have multiple widgets inside a MDCard. (GridLayout ignores the pos and size hint of it's children though)

    Solution :

        def __init__(self, **kwargs):
            super(AppScreen, self).__init__(**kwargs)
            self.scroll_id = self.ids.container
        def printing(self):
            for x in range(5):
    
                #New screen as a child of MDCard
                layout = Screen(
                    pos_hint={'center_x':0.5},
                    size_hint=(1,None)
    
                )
    
                img=AsyncImage(
                    source="https://i.redd.it/x1js663rq7s41.jpg",
                    pos_hint={'center_x':0.5, 'center_y':0.6},
                    size_hint = (.5,.5)
                    )
    
                card = MDCard(
                    orientation='vertical',
                    pos_hint={'center_x':0.5},
                    size_hint=(1, None),
                    #size=(dp(100), dp(100)) #Size is required to view stuff in Cards
    
                )
                layout.add_widget(img)
                card.add_widget(layout)
                self.scroll_id.add_widget(card)