我想在我的kivy应用中制作一个屏幕,让两个用户可以互相聊天,但我对如何在屏幕上显示聊天信息有问题。
以下是我想要的例子。(向下滚动约60%的页面即可看到)https:/medium.comflutter-communitybuilding-a-chat-app-with-flutter-and-firebase-from-scratch-9eaa7f41782e。
我曾用这个答案在屏幕左侧添加标签(用户发送的消息)。标签一直在滚动视图屏幕边缘运行 x轴 Kivy:
但我现在想知道如何在屏幕右侧添加标签(用户收到的消息)。我想我需要一个 GridLayout
有两列,我需要先添加一个白色标签,之后再添加信息标签,然后它应该出现在右边。我遇到的问题是如何让标签尽可能地出现在屏幕上的右边。
我也有问题,标签的大小取决于每个标签中文字的数量,我想我可能需要把每一行都添加为一个新的 "标签"。GridLayout
kivy肯定已经做了类似的事情,而且有一个指南可以遵循,但我找了一圈,我只能找到老式的UI聊天屏幕设计。
py文件
import kivy
from kivymd.app import MDApp
from kivy.properties import ObjectProperty, StringProperty, NumericProperty, ListProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.core.text import Label as CoreLabel
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDFillRoundFlatButton, MDRoundFlatIconButton, MDRaisedButton, MDTextButton, MDIconButton
from kivy.core.window import Window
Window.size = (481, 600)
Window.clearcolor = (1,1,1,1)
class Chat(Screen):
chat_layout = ObjectProperty(None)
def send_message(self):
if self.ids.message.text:
lab1 = Label()
# calculate max allowable width in the GridLayout
max_width = self.chat_layout.width - self.chat_layout.spacing[0] - self.chat_layout.padding[0] - \
self.chat_layout.padding[2]
# specify font and font_size (so that the CoreLabel uses the same)
self.chat_layout.add_widget(
SmoothLabel.create_sized_label(text=self.ids.message.text, max_width=max_width, font_name='Roboto',
font_size=15))
self.chat_layout.add_widget(lab1)
self.ids.message.text = ""
else:
pass
def recv_message(self):
if self.ids.message.text:
# calculate max allowable width in the GridLayout
max_width = self.chat_layout.width - self.chat_layout.spacing[0] - self.chat_layout.padding[0] - \
self.chat_layout.padding[2]
# specify font and font_size (so that the CoreLabel uses the same)
chat_label = SmoothLabel.create_sized_label(text=self.ids.message.text, max_width=max_width, font_name='Roboto',
font_size=15)
lab1 = Label(width=max_width)
self.chat_layout.add_widget(lab1)
self.chat_layout.add_widget(chat_label)
self.ids.message.text = ""
else:
pass
class SmoothLabel(Label):
@staticmethod
def create_sized_label(**kwargs):
max_width = kwargs.pop('max_width', 0)
if max_width <= 0:
# just create a SmoothLabel without a text_size
return SmoothLabel(**kwargs)
# calculate what the SmoothLabel size will be
core_label = CoreLabel(padding=[10,10], **kwargs) # use same padding as SmoothLabel
core_label.refresh()
if core_label.width > max_width:
# width is too big, use text_size to force wrapping
return SmoothLabel(text_size=(max_width,None), **kwargs)
else:
# width is OK, no need for text_size
return SmoothLabel(**kwargs)
class WindowManager(ScreenManager):
pass
class MyApp(MDApp):
def build(self):
kv = Builder.load_file("kivy.kv")
self.sm = WindowManager()
screens = [Chat(name="chat")]
for screen in screens:
self.sm.add_widget(screen)
self.sm.current = "chat"
return self.sm
if __name__ == '__main__':
MyApp().run()
kv文件
<Chat>:
name: "chat"
chat_layout: chat_layout
GridLayout:
cols: 1
GridLayout:
cols: 2
id: chat_layout
padding: 15
GridLayout:
cols: 3
MDRaisedButton:
on_release: root.send_message()
text: "send message"
TextInput:
id: message
size_hint: None, None
size: 150,50
hint_text:
"Send message"
MDRaisedButton:
on_release: root.recv_message()
text: "receive message"
<SmoothLabel>:
size_hint: None, None
size: self.texture_size
padding: 10, 10
multiline: True
background_color: 0,0,0,0
background_normal: ""
back_color: 1,0,1,1
border_radius: [6]
canvas.before:
Color:
rgba: 0.2,0.6,1,1 #This changes the label colour
RoundedRectangle:
size: self.size
pos: self.pos
radius: self.border_radius
我想您可以通过使用 BoxLayout
而非 GridLayout
,并使用 pos_hint
以将聊天标签定位在左边或右边。
import kivy
from kivymd.app import MDApp
from kivy.properties import ObjectProperty, StringProperty, NumericProperty, ListProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.core.text import Label as CoreLabel
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDFillRoundFlatButton, MDRoundFlatIconButton, MDRaisedButton, MDTextButton, MDIconButton
from kivy.core.window import Window
Window.size = (481, 600)
Window.clearcolor = (1,1,1,1)
class Chat(Screen):
chat_layout = ObjectProperty(None)
def send_message(self):
if self.ids.message.text:
# calculate max allowable width in the BoxLayout
max_width = (self.chat_layout.width - self.chat_layout.spacing - self.chat_layout.padding[0] - \
self.chat_layout.padding[2]) * 0.75
# specify font and font_size (so that the CoreLabel uses the same)
self.chat_layout.add_widget(
SmoothLabel.create_sized_label(text=self.ids.message.text, max_width=max_width, font_name='Roboto',
font_size=15, pos_hint={'x':0}))
self.ids.message.text = ""
self.ids.scroll.scroll_y = 0 # make sure last message is visible
else:
pass
def recv_message(self):
if self.ids.message.text:
# calculate max allowable width in the BoxLayout
max_width = (self.chat_layout.width - self.chat_layout.spacing - self.chat_layout.padding[0] - \
self.chat_layout.padding[2]) * 0.75
# specify font and font_size (so that the CoreLabel uses the same)
self.chat_layout.add_widget(
SmoothLabel.create_sized_label(text=self.ids.message.text, max_width=max_width, font_name='Roboto',
font_size=15, pos_hint={'right':1}))
self.ids.message.text = ""
self.ids.scroll.scroll_y = 0 # make sure last message is visible
else:
pass
class SmoothLabel(Label):
@staticmethod
def create_sized_label(**kwargs):
max_width = kwargs.pop('max_width', 0)
if max_width <= 0:
# just create a SmoothLabel without a text_size
return SmoothLabel(**kwargs)
# calculate what the SmoothLabel size will be
core_label = CoreLabel(padding=[10,10], **kwargs) # use same padding as SmoothLabel
core_label.refresh()
if core_label.width > max_width:
# width is too big, use text_size to force wrapping
return SmoothLabel(text_size=(max_width,None), **kwargs)
else:
# width is OK, no need for text_size
return SmoothLabel(**kwargs)
class WindowManager(ScreenManager):
pass
kv_str = '''
<Chat>:
name: "chat"
chat_layout: chat_layout
GridLayout:
cols: 1
ScrollView:
id: scroll
BoxLayout:
orientation: 'vertical'
id: chat_layout
padding: 15
spacing: 15
size_hint: 1, None
height: self.minimum_height
GridLayout:
cols: 3
MDRaisedButton:
on_release: root.send_message()
text: "send message"
TextInput:
id: message
size_hint: None, None
size: 150,50
hint_text:
"Send message"
MDRaisedButton:
on_release: root.recv_message()
text: "receive message"
<SmoothLabel>:
size_hint: None, None
size: self.texture_size
padding: 10, 10
multiline: True
background_color: 0,0,0,0
background_normal: ""
back_color: 1,0,1,1
border_radius: [6]
canvas.before:
Color:
rgba: 0.2,0.6,1,1 #This changes the label colour
RoundedRectangle:
size: self.size
pos: self.pos
radius: self.border_radius
'''
class MyApp(MDApp):
def build(self):
# kv = Builder.load_file("kivy.kv")
Builder.load_string(kv_str)
self.sm = WindowManager()
screens = [Chat(name="chat")]
for screen in screens:
self.sm.add_widget(screen)
self.sm.current = "chat"
return self.sm
if __name__ == '__main__':
MyApp().run()
我添加了 spacing
至 BoxLayout
并消除了空 Labels
不再需要的。
我曾经 Builder.load_string()
而不是 load_file()
只是为了我自己方便。