Reputation: 27
I am using Python 3.8.12, Kivy 2.0.0 & KivyMD-0.104.2 I am running my app on PyCharm on Ubuntu 18.04 LTS on a ASUS ROG STRIX GL503VD. My issue is that every time i use a for loop to generate content in KivyMD BottomNavgation using RecycleView, no matter what content (might be even a for i in range(100)), the app is starting to move very slow (when manually resizing it takes around 10 seconds to resize correctly). Also i have FPS under 50 on the tab in which i generated the data while in the empty ones i get @80 FPS. The issue doesn't seem to happen when i run lets say for i in range(100) in Kivy 2.0.0, but i would prefer to stick to KivyMD.
I've been looking in the last week on the internet for solutions but no luck and is a bit hard to understand kivy documentation regarding RecycleView.
Below is my code, please correct me if i did something out of "good practice". I just started to learn Kivy and i'm a beginner in Python (@1 year).
Thank you very much.
EDIT: Also when deployed to Android it works below 30 FPS on a Xiaomi Redmi Note8 Pro.
main.py
from kivy.lang import Builder
from kivymd.app import MDApp as md
from kivymd.uix.list import TwoLineListItem
import json as js
#from kivy.utils import platform
from kivy.core.window import Window
'''
if platform == "android":
try:
from android.permissions import request_permissions, Permission
request_permissions([Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE])
except:
pass
'''
class MainApp(md):
def build(self):
Window.size = (491, 1064)
self.theme_cls.primary_palette = 'Red'
self.theme_cls.primary_hue = '50'
layouts = Builder.load_file("layouts.kv")
return layouts
def on_start(self):
for key, value in self.read_list().items():
self.root.ids.container1.add_widget(TwoLineListItem(text=f"{key}", secondary_text="Tests : {}".format(len(value))))
self.fps_monitor_start()
def read_list(self):
with open('tests.json', 'r') as read_test:
#82 lines in test_list dict
test_list = js.load(read_test)
return test_list
if __name__ == '__main__':
MainApp().run()
layouts.kv
<MainLayout>
#:import get_color_from_hex kivy.utils.get_color_from_hex
MDGridLayout:
cols: 3
size_hint: 1, 1
MDBottomNavigation:
panel_color: get_color_from_hex("#008080")
text_color_active: get_color_from_hex("#FFFFFF")
MDBottomNavigationItem:
name: 'Item1'
text: 'item_1'
icon: 'language-python'
MDGridLayout:
cols: 1
RecycleView:
MDList:
id: container1
MDBottomNavigationItem:
name: 'Item2'
text: 'item_2'
icon: 'language-cpp'
MDBoxLayout:
RecycleView:
MDList:
id: container2
MDBottomNavigationItem:
name: 'Item3'
text: 'item_3'
icon: 'language-javascript'
MDBoxLayout:
RecycleView:
MDList:
id: container3
Upvotes: 0
Views: 518
Reputation: 38992
You are not actually using the RecycleView
. To use a RecycleView
, you must have a RecycleLayout
as its child, a viewclass
, and a data
list that indicates the items in the RecycleLayout
.
Here is one way to use the RecycleView
in your App
. First, modify the kv
to indicate the RecycleLayout
and the viewclass
:
MDGridLayout:
cols: 3
size_hint: 1, 1
MDBottomNavigation:
panel_color: get_color_from_hex("#008080")
text_color_active: get_color_from_hex("#FFFFFF")
MDBottomNavigationItem:
name: 'Item1'
text: 'item_1'
icon: 'language-python'
MDGridLayout:
cols: 1
RecycleView:
id: container1
viewclass: 'TwoLineListItem'
RecycleBoxLayout:
default_size: None, dp(75)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
The above moves the container1
id to the RecycleView
and adds the needed properties to allow the RecycleView
to operate.
Then the on_start()
method can be modified to create the data
list for the RecycleView
:
def on_start(self):
data = []
for key, value in self.read_list().items():
data.append({'text': f"{key}", 'secondary_text': "Tests : {}".format(len(value))})
self.root.ids.container1.data = data
self.fps_monitor_start()
Upvotes: 1