如何在kivy recycleview中select只有一个按钮

How to select only one button in kivy recycleview

我正在使用 kivy recycleview 创建一个 mp3 播放器,该应用程序的播放列表屏幕中有很多按钮,每当您单击一个按钮时,该按钮的图标就会从 'play' 变为 'pause' 反之亦然。

我想知道如何使单击另一个按钮将所有其他按钮图标更改为 'play' 只有所选按钮的图标应为 'pause'。

.py 文件:

from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.core.window import Window
from kivy.properties import StringProperty, ObjectProperty
from kivymd.theming import ThemableBehavior
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.screen import MDScreen
from kivymd.uix.behaviors import RectangularRippleBehavior
from kivy.uix.behaviors import ButtonBehavior

from kivy.clock import Clock

Builder.load_file('playlist.kv')

KV = """
#:import FadeTransition kivy.uix.screenmanager.FadeTransition

ScreenManager:
    transition: FadeTransition()

    Playlist:
        name: "playlist screen"

"""

class Playlist(ThemableBehavior, MDScreen):
    rv = ObjectProperty()
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Clock.schedule_once(self._finish_init)

    def music_list(self):
        return ['audio '+str(i) for i in range(1, 121)]

    def _finish_init(self, dt):
        self.set_list_musics()
        
    def set_list_musics(self):
        """Builds a list of audios for the screen Playlist."""
        print(self.ids)

        def add_music_item(num, sura, secText, icon):
            self.ids.rv.data.append(
                {
                    "viewclass": "MusicListItem",
                    "number": num,
                    "text": sura,
                    "secondary_text": secText,
                    "icon": icon,
                    "callback": lambda x:x})
    
        for i in range(len(self.music_list())):
            music = self.music_list()
            add_music_item(str(i+1), music[i], '00:00:00', 'play')
         
    
class MusicListItem(ThemableBehavior, RectangularRippleBehavior, ButtonBehavior, MDBoxLayout):
    text = StringProperty()
    secondary_text = StringProperty()
    number = StringProperty()
    icon = StringProperty()
    
    def on_release(self, *args):
        if self.icon == "play":
            self.icon = "pause"
        else:
            self.icon = "play"
    
    
class Mp3Player(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
       
    def build(self):
        self.theme_cls.primary_palette = "Purple"
        self.theme_cls.theme_style = "Dark"
        return Builder.load_string(KV)


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

.kv 文件:

#: import gch kivy.utils.get_color_from_hex
#: import StiffScrollEffect kivymd.effects.stiffscroll.StiffScrollEffect

<Playlist>
    md_bg_color: gch("#5D1049")
        
    MDGridLayout:
        cols: 1
        
        MDToolbar:
            left_action_items: [["menu", lambda x: x]]
            right_action_items: [["magnify", lambda x: x]]
            elevation: 10
            md_bg_color: 75/255, 6/255, 54/255, 1
            title: 'Playlist'
            pos_hint: {'top':1}
                    
        MDBoxLayout:
            orientation: 'vertical'
           
            RecycleView:
                id: rv
                effect_cls: 'ScrollEffect'
                viewclass: 'MusicListItem'

                RecycleBoxLayout:
                    padding: dp(10)
                    default_size: None, dp(60)
                    default_size_hint: 1, None
                    size_hint_y: None
                    height: self.minimum_height
                    orientation: 'vertical'

     
<MusicListItem>
    size_hint_y: None
    padding: dp(14)
    height: dp(60)

    canvas:
        Color:
            rgba:
                self.theme_cls.divider_color
        Line:
            points: (root.x+dp(10), root.y, root.x+self.width-dp(10)-0, root.y)

    MDBoxLayout:
        orientation: "horizontal"
        pos_hint: {"center_x": .5, "center_y": .5}

        MDBoxLayout:
            orientation: 'horizontal'
            MDBoxLayout:
                orientation: 'vertical'
                size_hint_x: .2
              
                MDLabel:
                    text: root.number
                    font_style: "H6"
                    adaptive_height: True
                
                MDLabel:
                    size_hint_y: .3
                 
            MDBoxLayout:
                orientation: 'vertical'
             
                MDLabel:
                    text: root.text
                    font_style: "Subtitle2"
                    adaptive_height: True
    
                MDLabel:
                    text: root.secondary_text
                    font_style: "Caption"
                    theme_text_color: "Hint"
                    adaptive_height: True

            MDIconButton:
                icon: root.icon          
    

谢谢

因此,据我了解,您希望将一个图标设置为 'pause',而将所有其他图标设置为 'play'。这样做的一种方法可能是,每次图标更改时,您都必须重新加载 RecyclView 数据

  1. 现在为 数据 提供图标参考(即 'play' 或 'pause'),我发现 number 属性合适,所以改成NumericProperty。因此 number = NumericProperty().

  2. 另外这需要kv的一些变化,

                MDLabel:
                    text: str(int(root.number))
                    font_style: "H6"
                    adaptive_height: True
  1. 为了让 Playlist 知道 number 引用,
    def set_list_musics(self, music_no = 0):
        """Builds a list of audios for the screen Playlist."""
        print(self.ids)
        self.ids.rv.data = [ ] # Since you are appending data and we need to reload everytime.
  1. 数据
  2. 中进行必要的更改
        for i in range(len(self.music_list())):
            new_icon = 'pause' if i+1 == music_no else 'play'
            music = self.music_list()
            add_music_item(str(i+1), music[i], '00:00:00', new_icon)
  1. 现在是最后一部分,通过按钮触发更改,
    def on_release(self, *args):
        if self.icon == "play":
            self.icon = "pause"
            pl = self.parent.parent.parent.parent.parent # Accessing the Playlist according to your design pattern.
            pl.set_list_musics(self.number)
        else:
            self.icon = "play"

请注意,我在 'pause' 图标中进行了此更改(即在 if self.icon == "play" 中),因此您也可以自由切换此图标。否则无法实现。

也许这可以用其他设计风格更系统地完成。我发现您的设计模式存在一些问题。这(例如在 for 循环中重复调用函数等)可能会随着 data 的增加而变慢一点。