如何让KivyMD的MDList与ScrollView滚动至列表底部
KivyMD ScrollView 无法滚动至底部的修复方案
问题
原本MDList和ScrollView可正常滚动,在列表下方添加包含TextInput、Label的BoxLayout组件后,列表无法滚动至底部,仅能滚动到第一条不可见行就回弹。
相关代码
main.py
import itertools from ctypes import windll, c_int64 windll.user32.SetProcessDpiAwarenessContext(c_int64(-4)) # Has to be here before kivy import. 4k fix from kivy.core.window import Window from kivy.metrics import sp from kivy.uix.boxlayout import BoxLayout from kivy.uix.textinput import TextInput from kivymd.app import MDApp from kivymd.uix.list import OneLineListItem from skimage.io import imread import os import struct # C:\WPy64-31040\python-3.10.4.amd64\python.exe main.py import kivy; print(kivy.__version__) def clickme(list_item): print(list_item.text) class MyLayout(BoxLayout): pass class MyTextInput(TextInput): def __init__(self, **kwargs): super(MyTextInput, self).__init__(**kwargs) self.size_hint = (None, None) self.foreground_color = (0, 0, 0, 1) # Text is black. self.background_color = (0.6, 0.6, 0.6, 0.3) # Background is transparent and therefore not visible. self.cursor_color = (0, 0, 0, 0) # Hide the cursor by making it transparent. self.font_size = sp(24) # Left, right center. self.halign = 'center' # self.padding_x = [self.center[0] - self._get_text_width(max(self._lines, key=len), self.tab_width, self._label_cached) / 2.0, # 0] if self.text else [self.center[0], 0] # Top, bottom center. Moved to kv file. # self.padding_y = [self.height / 2.0 - (self.line_height / 2.0) * len(self._lines), 0] # Deprecated. Use padding instead. # self.padding = [self.padding[0], self.height / 2.0 - (self.line_height / 2.0) * len(self._lines), self.padding[2], 0] def keyboard_on_textinput(self, window, text): """Upper case and always one letter only.""" self.text = text.upper() class CrosswordApp(MDApp): def build(self): return MyLayout() def on_start(self): # List of possible crossword candidates. for i in range(20): self.root.ids.lst_matches.add_widget( OneLineListItem(text=f"Single-line item {i} very very very very very long string that hopefully is long enough", on_release=clickme, divider="Full", font_style="Caption")) # Get black and white blocks. # tex = self.root.ids.img_crossword.texture # for y in range(0, tex.size[1], 5): # for x in range(0, tex.size[0], 5): # print(self.get_color_value(x, y, tex)) # Read crossword image using path relative to this file's path. img = imread(os.path.dirname(os.path.realpath(__file__)) + r"\images\Huisgenoot20220605P.png") dcol = {} ysize = int(img.shape[0] / 23) # Also len(img) xsize = int(img.shape[1] / 18) # Also len(img[0]) for y, x in itertools.product(range(23), range(18)): cnt = r = g = b = 0 for y2, x2 in itertools.product(range(y * ysize, y * ysize + ysize - 1), range(x * xsize, x * xsize + xsize - 1)): cnt = cnt + 1 r = r + img[y2][x2][0] g = g + img[y2][x2][1] b = b + img[y2][x2][2] dcol[(x, y)] = [int(r / cnt), int(g / cnt), int(b / cnt)] for row in range(23): for col in range(18): v = dcol[col, row] if v[0] > 230 and v[1] > 230 and v[2] > 230: print(" ", end="") elif 167 <= v[0] <= 187 and 203 <= v[1] <= 223 and 203 <= v[2] <= 223: print("B", end="") else: print("#", end="") print("") print(dcol[0, 0]) print(dcol[1, 0]) print(dcol[2, 0]) print(dcol[3, 0]) print(dcol[6, 1]) print(dcol[17, 0]) def get_color_value(self, x, y, texture): """Get the rgba (0..255) value at x and y of an image texture.""" pixel = texture.get_region(x, y, 1, 1) bp = pixel.pixels return struct.unpack('4B', bp) # tuple [c for c in struct.unpack('4B', bp)] # / 255.0 if __name__ == '__main__': Window.maximize() CrosswordApp().run()
crossword.kv(原代码)
#:kivy 2.1.0 <MyTextInput> <MyLayout> BoxLayout: orientation: 'horizontal' size: root.width, root.height padding: 0 spacing: 0 Image: id: img_crossword source: 'images/Huisgenoot20220605P.png' size_hint: None, None size: img_crossword.image_ratio * root.height, root.height allow_stretch: True keep_ratio: True BoxLayout: orientation: 'vertical' size_hint: None, None size: root.width - (img_crossword.image_ratio * root.height), root.height padding: 0 spacing: 0 ScrollView: # size_hint: None, 1 width: root.width - (img_crossword.image_ratio * root.height) do_scroll_x: False do_scroll_y: True bar_color: 0, 0, 255, 1 bar_width: 12 MDList: id: lst_matches size_hint: None, 0.8 width: root.width - (img_crossword.image_ratio * root.height) height: self.height spacing: dp(0) padding: dp(0) BoxLayout: orientation: 'horizontal' size_hint: None, 0.2 width: root.width - (img_crossword.image_ratio * root.height) padding: 0 spacing: 0 TextInput: id: txt_clue size_hint: 0.4, 0.2 text: 'Clue' Label: id: lbl_clue size_hint: 0.4, 0.2 color: 0, 0, 0, 1 text: 'Clue' TextInput: id: txt_word size_hint: 0.2, 0.2 text: 'Word' FloatLayout: MyTextInput: text: 'A' pos: img_crossword.pos[0] + img_crossword.width / 18 * 16, img_crossword.pos[1] + img_crossword.height / 23 * 5 size: img_crossword.width / 18, img_crossword.height / 23 padding: [self.padding[0], self.height / 2.0 - (self.line_height / 2.0) * len(self._lines), self.padding[2], 0]
修复方案
问题根源在于ScrollView和MDList的尺寸配置错误,导致ScrollView无法正确识别可滚动区域。修改crossword.kv中的以下部分:
- ScrollView:设置
size_hint_y: 0.8,移除手动指定的width(继承父容器宽度即可),让它在垂直方向占据80%的空间。 - MDList:设置
size_hint_y: None,并将height: self.height改为height: self.minimum_height,这样列表会根据内部项的总高度自动计算自身高度,确保ScrollView能滚动到所有内容。 - 底部BoxLayout:将
size_hint: None, 0.2改为size_hint_y: 0.2,保持垂直方向占据20%的空间,和上方ScrollView的占比匹配。
修改后的crossword.kv相关部分代码:
<MyLayout> BoxLayout: # ... 其他代码保持不变 ... BoxLayout: orientation: 'vertical' size_hint: None, None size: root.width - (img_crossword.image_ratio * root.height), root.height padding: 0 spacing: 0 ScrollView: size_hint_y: 0.8 do_scroll_x: False do_scroll_y: True bar_color: 0, 0, 255, 1 bar_width: 12 MDList: id: lst_matches size_hint_y: None width: root.width - (img_crossword.image_ratio * root.height) height: self.minimum_height spacing: dp(0) padding: dp(0) BoxLayout: orientation: 'horizontal' size_hint_y: 0.2 width: root.width - (img_crossword.image_ratio * root.height) padding: 0 spacing: 0 # ... 内部TextInput、Label代码不变 ... # ... FloatLayout部分代码不变 ...
修改后,ScrollView会正确识别MDList的完整高度,允许滚动至底部。
内容的提问来源于stack exchange,提问作者Superdooperhero
相关产品推荐
相关产品推荐

