Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/193.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何在Kivy的ScrollView中正确创建长文本标签?_Android_Python_Ios_Kivy - Fatal编程技术网

Android 如何在Kivy的ScrollView中正确创建长文本标签?

Android 如何在Kivy的ScrollView中正确创建长文本标签?,android,python,ios,kivy,Android,Python,Ios,Kivy,我试图创建MWE来演示我的问题,结果我对这个问题更加困惑 我想创建一个应用程序与几个小部件。其中一个小部件将保存长文本,我预计它将跨越大约3行。我希望包含此文本的标签增加其高度以调整文本大小 这就是我目前得到的 layout = BoxLayout(orientation='horizontal') subLayout = TwoLabelCombo() subLayout.label1.text = ('foo:') subLayout.label2.text

我试图创建MWE来演示我的问题,结果我对这个问题更加困惑

我想创建一个应用程序与几个小部件。其中一个小部件将保存长文本,我预计它将跨越大约3行。我希望包含此文本的标签增加其高度以调整文本大小

这就是我目前得到的

    layout = BoxLayout(orientation='horizontal')
    subLayout = TwoLabelCombo()
    subLayout.label1.text = ('foo:')
    subLayout.label2.text = 'bar'*50
    subLayout.label2.width = int(Window.width*0.8)
    subLayout.label2.text_size = [subLayout.label2.width,None]
    subLayout.label2.size_hint_y = None
    subLayout.label2.height = subLayout.label2.texture_size[1]
    subLayout.height = subLayout.label2.texture_size[1]
    layout.height = subLayout.height

TwoLabelCombo是一种方向设置为水平的BoxLayout,用于保存大小设置为0.2和0.8的标签。layout在应用程序中保留一整行,其前后和下方都有类似的布局。文本确实跨越了几行,但布局不随文本更新,因此与其他小部件重叠。打印纹理大小我知道它的高度是0。如何获得正确的文本大小

所以这里有两个问题。首先,根据标签内容调整标签大小的问题

基于纹理大小指定高度的方法是正确的。但问题是,当您第一次创建标签时,纹理尚未渲染,因此您无法知道大小。关键是使用,然后每次纹理大小改变时,高度都会更新

因此,以Kivy中定义UI的首选方式:

Label:
    text: 'some really really really long text here'
    size_hint_y: None
    height: self.texture_size[1]
    text_size: self.width, None
属性在kv中引用时会自动绑定。但在Python中也可以这样做:

lbl = Label(text='some really really really long text here',
            size_hint_y=None)
lbl.bind(texture_size=lambda instance, value: setattr(instance, 'height', value[1]))
lbl.bind(width=lambda instance, value: setattr(instance, 'text_size', (value, None)))
第二,是布局的问题。即使将这些标签设置为正确的大小,它们所在的BoxLayouts仍将正常布局。以下是BoxLayout的替代品,当适当设置size_hint时,它将根据其子项的大小调整自身大小:

class CollapsingBoxLayout(BoxLayout):
    def __init__(self, **kwargs):
        super(CollapsingBoxLayout, self).__init__(**kwargs)
        self._trigger_update_size = Clock.create_trigger(self._update_size)

    def on_children(self, *_):
        for c in self.children:
            c.bind(size=self._trigger_update_size)
        self._update_size()

    def _update_size(self, *_):
        if self.size_hint_y is None:
            self.height = max(c.height for c in self.children) if self.children else 0
        if self.size_hint_x is None:
            self.width = max(c.width for c in self.children) if self.children else 0
最后是一个完整的工作示例:

import kivy
kivy.require('1.8.0')

from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label

class CollapsingBoxLayout(BoxLayout):
    def __init__(self, **kwargs):
        super(CollapsingBoxLayout, self).__init__(**kwargs)
        self._trigger_update_size = Clock.create_trigger(self._update_size)

    def on_children(self, *_):
        for c in self.children:
            c.bind(size=self._trigger_update_size)
        self._trigger_update_size()

    def _update_size(self, *_):
        if self.size_hint_y is None:
            self.height = max(c.height for c in self.children) if self.children else 0
        if self.size_hint_x is None:
            self.width = max(c.width for c in self.children) if self.children else 0

root = Builder.load_string('''
BoxLayout:
    orientation: 'vertical'
    CollapsingBoxLayout:
        size_hint_y: None

        canvas.before:
            Color:
                rgba: 1, 0, 0, 0.2
            Rectangle:
                pos: self.pos
                size: self.size

        Label:
            text: 'Paragraph 1'
            size_hint_x: 0.2
            size_hint_y: None
            height: self.texture_size[1]
            text_size: self.width, None
        Label:
            canvas.before:
                Color:
                    rgba: 0, 1, 0, 0.2
                Rectangle:
                    pos: self.pos
                    size: self.size
            size_hint_x: 0.8
            text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sollicitudin dignissim orci. Pellentesque laoreet magna quis augue dictum fringilla. Vivamus nec adipiscing nunc. Aliquam pharetra auctor justo vel rutrum. Sed sodales nulla sed odio fermentum, vel pulvinar nibh hendrerit. Phasellus a volutpat leo. Donec id hendrerit velit. Curabitur eget suscipit neque, nec tincidunt nulla. Donec feugiat, urna quis porttitor aliquet, nibh est laoreet ligula, vitae vestibulum leo purus quis ante. Maecenas magna nisi, molestie eu ipsum quis, tempor tempor turpis. Vivamus a fringilla enim. Quisque aliquam elit tortor, nec mollis tellus facilisis accumsan. Phasellus sagittis commodo mauris in vestibulum. Mauris sed ultrices enim.'
            size_hint_y: None
            height: self.texture_size[1]
            text_size: self.width, None

    CollapsingBoxLayout:
        size_hint_y: None

        canvas.before:
            Color:
                rgba: 0, 0, 1, 0.2
            Rectangle:
                pos: self.pos
                size: self.size

        Label:
            text: 'Paragraph 2'
            size_hint_x: 0.2
            size_hint_y: None
            height: self.texture_size[1]
            text_size: self.width, None
        Label:
            canvas.before:
                Color:
                    rgba: 0, 1, 0, 0.2
                Rectangle:
                    pos: self.pos
                    size: self.size
            size_hint_x: 0.8
            text: 'Duis egestas dui lobortis ante rutrum, nec consectetur arcu sollicitudin. Phasellus ut felis facilisis, eleifend odio malesuada, placerat odio. Etiam convallis non mi at tempor. Nunc gravida est magna, a hendrerit nulla condimentum a. Proin tristique velit quis dui convallis, vitae sodales nunc condimentum. In sollicitudin eros augue, sit amet blandit neque accumsan eu. Mauris non risus at nisl vestibulum dignissim quis non arcu. Integer ullamcorper felis eu neque viverra placerat. Vivamus magna quam, porta ac tincidunt a, imperdiet sed purus. Phasellus tempus ac neque vel accumsan. Pellentesque ligula justo, auctor eget aliquet ultricies, volutpat scelerisque ligula. Maecenas dictum velit id neque rhoncus fermentum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur dictum enim nisl, ut elementum lectus viverra sit amet. Praesent vel tempor risus, at congue turpis. Praesent in justo lobortis, gravida lacus id, facilisis orci.'
            size_hint_y: None
            height: self.texture_size[1]
            text_size: self.width, None
''')

class TestApp(App):
    def build(self):
        lbl = Label(text=('hello this is some long long text! ' * 10), size_hint_y=None)
        lbl.bind(texture_size=lambda instance, value: setattr(instance, 'height', value[1]))
        lbl.bind(width=lambda instance, value: setattr(instance, 'text_size', (value, None)))
        root.add_widget(lbl)
        return root

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

问题可能是在纹理实际生成和显示之前,纹理大小不会更新,在方法结束时可能不会更新,但在下一帧之前可能会更新。因此,您通常希望绑定到属性,而不是获取它们的瞬时值

您的整个规则可以更简单地表达,并且有了这个免费的附加功能,在kv语言中,我对您在文章中没有包含的小部件添加进行了一些猜测,但是您应该看到了总体思路

: 尺寸提示:无 高度:标签2.纹理大小[1] 标签:label1 文本:“foo:” 标签:label2 id:label2 文本:“条”*50 宽度:intWindow.width*0.8这可能最好通过布局完成 文本大小:self.width,无

我也稍微改变了一些,设置了根BoxLayout的高度,而不是标签的高度,我认为这样会更好

当然,您也可以在python中这样做,通过使用widget的bind方法重新创建相关的绑定,这是kv在幕后所做的,但它更详细


我有一个视频介绍了其中的一些内容,以及其他内容。

以防其他人正在搜索一个包含BoxLayout或GridLayout的自扩展ScrollView的解决方案,作为参考,它实际上是一个自扩展的小部件。通过Ryan P的回答,我得到了大部分的答案;但后来我意识到,他在处理一个非常具体的用例,这就是他使用max函数的原因。 我需要的是一个随着新部件的添加而扩展的框。所以我只是将他的代码修改为_update_size:

def _update_size(self, *_):
    temp_height = 0
    if self.size_hint_y is None:
        for c in self.children:
            temp_height += c.height
        self.height = temp_height + 10  # Add a buffer to the bottom to prevent text clipping.
    if self.size_hint_x is None:
        self.width = max(c.width for c in self.children) if self.children else 0
我留下了一些注意事项,因为对于我的用例,这样做是有意义的,但是可以用类似的方式修改它

另外,使用此方法更改标签小部件大小的最简单方法是使用remove_小部件删除小部件,然后使用kivy.lang.Builder.load_字符串创建新小部件,并将该小部件添加到自扩展/折叠的BoxLayout或GridLayout中,它将重新计算其大小,从而适当调整滚动视图的滚动距离。不要忘记大小提示:None它必须等于None,否则不会应用更新


希望这些细节足以帮助任何人解决边缘问题。

谢谢您的评论。起初,我使用的是kivy语言,但我发现它非常混乱,我在python代码中找到的大多数示例/文档都是这样。