如何在运行时根据纹理大小调整RecycleView中的标签大小?

huangapple go评论78阅读模式
英文:

How to make Labels in RecycleView change size according to texture size during runtime?

问题

我有一个RecycleView,其中包含标签和一个MDSlider,我在运行时使用它来更改这些标签的font_size。我想知道是否可能将标签的大小与其texture_size属性对齐。准确地说,每当我更改font_size时,会导致标签的texture_size溢出其当前大小,我希望增加标签的大小以适应文本。由于标签位于RecycleView内部,我不确定应该如何解决这个问题。我最初将height设置为RecycleBoxLayoutself.minimum_height,我认为它应该在过程中更新。我注意到我可以在运行时手动更改RecycleBoxLayoutdefault_size,但不确定应该如何传递标签的texture_size来调整大小。我尝试使用on_sizeon_texture方法传递属性并用于计算default_size,但事情变得非常复杂,我总是最终在标签之间产生间隙。理想情况下,我希望使用标签大小/纹理的某种绑定解决方案(类似于我已经使用app.fontSize实现的绑定),这样我就可以获得自动调整大小,因为任何手动计算RecycleView属性及其后续更新都会显著减慢我的程序在测试Android时的速度。

有什么想法吗?

编辑:我没有提到,我只对高度调整感兴趣。宽度无关紧要。

from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.screenmanager import Screen
from kivymd.uix.boxlayout import MDBoxLayout
from kivy.properties import StringProperty

kv = """
<MyLabel@MDLabel>:
    font_size: app.fontSize
    halign: 'center'
    # Using these settings would be awesome, but cannot make it happen.
    # Or there might be more elegant solution?
    #size: self.texture_size
    #size_hint_y: None
    #text_size: self.width, None
    

<DailyService>:
    day: ''
    service: ''
    
    MDGridLayout:
        rows: 2
        MyLabel:
            id: firstLabelId
            text: root.day
            md_bg_color: app.theme_cls.accent_color

        MyLabel:
            id: secondLabelId
            md_bg_color: app.theme_cls.primary_dark
            text: root.service
    
<MainScreen>:
    name: 'mainScreen'
    myRv: rvId

    MDRelativeLayout:
        orientation: 'vertical'

        MDRecycleView:
            viewclass: 'DailyService'
            id: rvId
            rbl: rblId
            
            RecycleBoxLayout:
                id: rblId
                default_size: None, dp(200)
                default_size_hint: 1, None
                size_hint_y: None
                height: self.minimum_height
                orientation: 'vertical'

        MDSlider:
            color: 'white'
            orientation: 'horizontal'
            size_hint: (0.2, 0.2)
            pos_hint: {"x":0.4, "top": 1}
            min: 10
            value: 20
            max: 150
            on_value_normalized: root.fontSizeSlider(self.value)


MyScreenManager:
    mainScreen: mainScreenId
        
    MainScreen:
        id: mainScreenId
"""

class DailyService(MDBoxLayout):
    pass

class MainScreen(Screen):
    def __init__(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)

    def fontSizeSlider(self, value):
        app = MDApp.get_running_app()
        app.fontSize = str(int(value)) + 'dp'
        self.myRv.refresh_from_data()
    
class MyScreenManager(ScreenManager):    
    def __init__(self, **kwargs):
        super(MyScreenManager, self).__init__(**kwargs)


class MyApp(MDApp):
    fontSize = StringProperty('20dp')
    
    def on_start(self):
        data = []
        for i in range(10):
            data.append({'day': 'DAY\nDAY',
                         'service': 'SERVICE\nSERVICE'})
        self.root.ids.mainScreenId.myRv.data = data

    def build(self):
        self.theme_cls.theme_style = 'Dark'
        self.theme_cls.primary_palette = 'Blue'
        self.theme_cls.accent_palette = 'Amber'
        return Builder.load_string(kv)

if __name__ == '__main__':
    MyApp().run()
英文:

I have a RecycleView which consists of labels and a MDSlider which I use to change font_size of those labels during runtime. I'm wondering if it's possible to align labels' size to their texture_size property. Precisely, whenever I change the font_size which would cause label's texture_size to overflow its current size, I would want to increase the label size so the text fits. Since labels live inside the RecycleView, I'm not sure how should I approach the problem. I'm initially setting height to self.minimum_height of the RecycleBoxLayout which I presume should be updated in the process. I noticed that I can manually change the RecycleBoxLayout&#39;s default_size during runtime, but not sure how exactly I should pass the texture_size of the label to adjust the size. I tried with on_size and on_texture methods to pass the property and use to calculate default_size, but things get really complicated and I always end up getting gaps between the labels. Ideally I would want the solution that uses some kind of binding of labels sizes/texture (similarly like I already have with the app.fontSize) so I would get automatic resizing because any manual calculations of RecycleView properties and it's consequential update significantly slows down my program in the end when testing on Android.

Any ideas?

EDIT: I haven't mentioned it, I'm only interested in the height resizing. Width doesn't matter.

from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.screenmanager import Screen
from kivymd.uix.boxlayout import MDBoxLayout
from kivy.properties import StringProperty
kv = &quot;&quot;&quot;
&lt;MyLabel@MDLabel&gt;:
font_size: app.fontSize
halign: &#39;center&#39;
# Using these settings would be awesome, but cannot make it happen.
# Or there might be more elegant solution?
#size: self.texture_size
#size_hint_y: None
#text_size: self.width, None
&lt;DailyService&gt;:
day: &#39;&#39;
service: &#39;&#39;
MDGridLayout:
rows: 2
MyLabel:
id: firstLabelId
text: root.day
md_bg_color: app.theme_cls.accent_color
MyLabel:
id: secondLabelId
md_bg_color: app.theme_cls.primary_dark
text: root.service
&lt;MainScreen&gt;:
name: &#39;mainScreen&#39;
myRv: rvId
MDRelativeLayout:
orientation: &#39;vertical&#39;
MDRecycleView:
viewclass: &#39;DailyService&#39;
id: rvId
rbl: rblId
RecycleBoxLayout:
id: rblId
default_size: None, dp(200)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: &#39;vertical&#39;
MDSlider:
color: &#39;white&#39;
orientation: &#39;horizontal&#39;
size_hint: (0.2, 0.2)
pos_hint: {&quot;x&quot;:0.4, &quot;top&quot;: 1}
min: 10
value: 20
max: 150
on_value_normalized: root.fontSizeSlider(self.value)
MyScreenManager:
mainScreen: mainScreenId
MainScreen:
id: mainScreenId
&quot;&quot;&quot;
class DailyService(MDBoxLayout):
pass
class MainScreen(Screen):
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
def fontSizeSlider(self, value):
app = MDApp.get_running_app()
app.fontSize = str(int(value)) + &#39;dp&#39;
self.myRv.refresh_from_data()
class MyScreenManager(ScreenManager):    
def __init__(self, **kwargs):
super(MyScreenManager, self).__init__(**kwargs)
class MyApp(MDApp):
fontSize = StringProperty(&#39;20dp&#39;)
def on_start(self):
data = []
for i in range(10):
data.append({&#39;day&#39;: &#39;DAY\nDAY&#39;,
&#39;service&#39;: &#39;SERVICE\nSERVICE&#39;})
self.root.ids.mainScreenId.myRv.data = data
def build(self):
self.theme_cls.theme_style = &#39;Dark&#39;
self.theme_cls.primary_palette = &#39;Blue&#39;
self.theme_cls.accent_palette = &#39;Amber&#39;
return Builder.load_string(kv)
if __name__ == &#39;__main__&#39;:
MyApp().run()

答案1

得分: 1

from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.screenmanager import Screen
from kivymd.uix.boxlayout import MDBoxLayout
from kivy.properties import StringProperty

kv = """
<MyLabel@MDLabel>:
    font_size: app.fontSize
    halign: 'center'
    # Using these settings would be awesome, but cannot make it happen.
    # Or there might be more elegant solution?
    #size: self.texture_size
    #size_hint_y: None
    #text_size: self.width, None


<DailyService>:
    day: ''
    service: ''
    
    MDGridLayout:
        rows: 2
        size_hint_y:None
        height:app.MyHeight
        MyLabel:
            id: firstLabelId
            text: root.day
            md_bg_color: app.theme_cls.accent_color

        MyLabel:
            id: secondLabelId
            md_bg_color: app.theme_cls.primary_dark
            text: root.service

<MainScreen>:
    name: 'mainScreen'
    myRv: rvId

    MDRelativeLayout:
        orientation: 'vertical'

        MDRecycleView:
            viewclass: 'DailyService'
            id: rvId
            rbl: rblId
            
            RecycleBoxLayout:
                id: rblId
                default_size: None, app.MyHeight
                default_size_hint: 1, None
                size_hint_y: None
                height: self.minimum_height
                orientation: 'vertical'

        MDSlider:
            color: 'white'
            orientation: 'horizontal'
            size_hint: (0.2, 0.2)
            pos_hint: {"x":0.4, "top": 1}
            min: 10
            value: 20
            max: 150
            on_value_normalized: root.fontSizeSlider(self.value)


MyScreenManager:
    mainScreen: mainScreenId
        
    MainScreen:
        id: mainScreenId
"""

class DailyService(MDBoxLayout):
    pass

class MainScreen(Screen):
    def __init__(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)

    def fontSizeSlider(self, value):
        app = MDApp.get_running_app()
        app.fontSize = str(int(value)) + 'dp'
        app.MyHeight = str(  int(value) * 10 ) + 'dp'
        self.myRv.refresh_from_data()

class MyScreenManager(ScreenManager):    
    def __init__(self, **kwargs):
        super(MyScreenManager, self).__init__(**kwargs)


class MyApp(MDApp):
    fontSize = StringProperty('20dp')
    MyHeight = StringProperty('200dp')
    def on_start(self):
        data = []
        for i in range(10):
            data.append({'day': 'DAY\nDAY',
                         'service': 'SERVICE\nSERVICE'})
        self.root.ids.mainScreenId.myRv.data = data

    def build(self):
        self.theme_cls.theme_style = 'Dark'
        self.theme_cls.primary_palette = 'Blue'
        self.theme_cls.accent_palette = 'Amber'
        return Builder.load_string(kv)

if __name__ == '__main__':
    MyApp().run()
英文:
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.screenmanager import Screen
from kivymd.uix.boxlayout import MDBoxLayout
from kivy.properties import StringProperty
kv = &quot;&quot;&quot;
&lt;MyLabel@MDLabel&gt;:
font_size: app.fontSize
halign: &#39;center&#39;
# Using these settings would be awesome, but cannot make it happen.
# Or there might be more elegant solution?
#size: self.texture_size
#size_hint_y: None
#text_size: self.width, None
&lt;DailyService&gt;:
day: &#39;&#39;
service: &#39;&#39;
MDGridLayout:
rows: 2
size_hint_y:None
height:app.MyHeight
MyLabel:
id: firstLabelId
text: root.day
md_bg_color: app.theme_cls.accent_color
MyLabel:
id: secondLabelId
md_bg_color: app.theme_cls.primary_dark
text: root.service
&lt;MainScreen&gt;:
name: &#39;mainScreen&#39;
myRv: rvId
MDRelativeLayout:
orientation: &#39;vertical&#39;
MDRecycleView:
viewclass: &#39;DailyService&#39;
id: rvId
rbl: rblId
RecycleBoxLayout:
id: rblId
default_size: None, app.MyHeight
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: &#39;vertical&#39;
MDSlider:
color: &#39;white&#39;
orientation: &#39;horizontal&#39;
size_hint: (0.2, 0.2)
pos_hint: {&quot;x&quot;:0.4, &quot;top&quot;: 1}
min: 10
value: 20
max: 150
on_value_normalized: root.fontSizeSlider(self.value)
MyScreenManager:
mainScreen: mainScreenId
MainScreen:
id: mainScreenId
&quot;&quot;&quot;
class DailyService(MDBoxLayout):
pass
class MainScreen(Screen):
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
def fontSizeSlider(self, value):
app = MDApp.get_running_app()
app.fontSize = str(int(value)) + &#39;dp&#39;
app.MyHeight = str(  int(value) * 10 ) + &#39;dp&#39;
self.myRv.refresh_from_data()
class MyScreenManager(ScreenManager):    
def __init__(self, **kwargs):
super(MyScreenManager, self).__init__(**kwargs)
class MyApp(MDApp):
fontSize = StringProperty(&#39;20dp&#39;)
MyHeight = StringProperty(&#39;200dp&#39;)
def on_start(self):
data = []
for i in range(10):
data.append({&#39;day&#39;: &#39;DAY\nDAY&#39;,
&#39;service&#39;: &#39;SERVICE\nSERVICE&#39;})
self.root.ids.mainScreenId.myRv.data = data
def build(self):
self.theme_cls.theme_style = &#39;Dark&#39;
self.theme_cls.primary_palette = &#39;Blue&#39;
self.theme_cls.accent_palette = &#39;Amber&#39;
return Builder.load_string(kv)
if __name__ == &#39;__main__&#39;:
MyApp().run()

huangapple
  • 本文由 发表于 2023年8月9日 02:28:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76862275.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定