Киви (Python): Как изменить высоту BoxLayout в зависимости от дочерних элементов? - PullRequest
0 голосов
/ 03 мая 2020

Я пишу новостное приложение в Киви, которое берет статьи с первой страницы веб-сайта и делает их видимыми в приложении. В зависимости от длины статьи размер и количество абзацев могут различаться. Поскольку для извлечения содержимого веб-сайта используется веб-браузер BS4, все программирование gui происходит на python, а не на языке .kv. Итак, мой вопрос, как я могу помешать Image зарезервировать место на экране (я хочу, чтобы надписи всегда были под ним), и как я могу изменить height BoxLayout на основе его дочерних элементов, чтобы достаточно места для всех, но не слишком много.

Вот упрощенная версия моего кода, которая демонстрирует мою проблему. В этом примере высота BoxLayout установлена ​​на 1000dp, что хорошо для примерно 4 абзацев, но если бы их было больше, это стало бы загроможденным. Есть ли способ избежать этой проблемы? Любая помощь будет полезна.

from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.label import MDLabel
from kivy.uix.screenmanager import Screen
from kivy.uix.scrollview import ScrollView
from kivy.uix.image import AsyncImage


class RootWidget(Screen):
    def __init__(self, **kw):
        super().__init__(**kw)
        self.update()

    def update(self):
        paragraphs_text = ["Lorem ipsum dolor sit amet,", "consectetur adipiscing elit, sed do eiusmod tempor incididunt ut"
                      " labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco "
                      "laboris nisi ut aliquip ex ea commodo consequat.", "Duis aute irure dolor in reprehenderit in"
                      " voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat "
                      "non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."]

        header_text = "Lorem ipsum dolor sit amet"

        header_image_src = "images/Cariboo_Peaks.jpg"

        date_of_publishing_text = "03.05.2020"

        scroll_widget_holder = ScrollView()
        widget_holder = BoxLayout(orientation="vertical", size_hint_y=None, padding=5)

        # minimum_height doesnt work in python, only in .kv language so is there a way to get the height automatically?
        # 1000dp works fine for this amount of paragrpahs but i there was twice as many as there are now it would all
        # become to cludderd and the image would be very small
        # on the other hand, if I make this number too big the wigets are too far apart from each other
        # So how can I fix this?
        widget_holder.height = "1000dp"

        header_image = AsyncImage(source=header_image_src, size_hint=(1, 1),
                                  allow_stretch=False, keep_ratio=True)

        header_label = MDLabel(text=header_text, size_hint_y=None, font_style="H6")

        # Thats what I came up with, if there is a better way of automatically asigning the height of a widget based
        # on its contents please let me know
        header_label.height = str(len(header_label.text)) + "dp"

        # This label is supossed to be right unter the header label(see the screens below to see my go to result created
        # in photoshop)
        header_date_label = MDLabel(text=date_of_publishing_text, size_hint_y=None, font_style="Caption", height="10dp")

        widget_holder.add_widget(header_image)
        widget_holder.add_widget(header_label)
        widget_holder.add_widget(header_date_label)

        for paragraph in paragraphs_text:
            text_paragraph = MDLabel(text=paragraph, size_hint_y=None,
                                     pos_hint={"center_x": .5}, halign="justify")
            text_paragraph.height = str(len(text_paragraph.text)) + "dp"

            widget_holder.add_widget(text_paragraph)

        scroll_widget_holder.add_widget(widget_holder)
        self.add_widget(scroll_widget_holder)


class TestApp(MDApp):
    def build(self):
        return RootWidget()


if __name__ == '__main__':
    TestApp().run()

1 Ответ

1 голос
/ 04 мая 2020

Вы можете самостоятельно вычислить высоту BoxLayout, просто добавив высоты всех его дочерних элементов (включая padding и spacing). Если вы знаете (или задаете) высоты детей, когда вы добавляете их во время метода update, вы можете просто установить высоту, используя:

widget_holder.height = new_height

, где new_height - это рассчитанная выше сумма. Если вы не знаете высоты детей, вы можете сделать что-то вроде:

def adjust_height(self, box, dt):
    # this does not handle padding and spacing
    new_height = 0
    for child in box.children:
        new_height += child.height
    box.height = new_height

И вы можете вызвать его в конце вашего update() метода как:

    Clock.schedule_once(partial(self.adjust_height, widget_holder))
...