使用Python进行移动应用开发。 KivyMD库


问候! 今天,我们将再次讨论KivyMD库-一组Material Design风格的Python跨平台开发小部件。 在本文中,我不会像最近的文章那样回顾KivyMD窗口小部件,而是更多地介绍如何定位窗口小部件。 像针对初学者使用Python开发移动应用程序的教程之类的东西将不在这里,因此,如果您第一次了解Kivy框架,那么您不太可能对这一切感兴趣。 好吧,我们开车经过削减!

前几天,我从Google Play下载了Flutter UIKit演示应用程序:


现在,我们将尝试从此应用程序重复一个屏幕。 让我们立即查看结果:左侧为Flutter,右侧为Kivy&KivyMD。

UI的某些元素有所不同,并不是由于某些技术功能而导致的,因此无法获得相同的结果,但我只是认为它会更加有机(例如,我认为黑色的工具栏根本看不到)。

这样啊 观看我们将要播放的屏幕时,会发生什么? 透明背景前布局。 在Kivy中,此功能由FloatLayout提供,它使您可以将小部件和控件相互放置在内部,如下所示:


从示意图上看,我们的屏幕如下所示:


该屏幕的布局非常简单:


如果我们的屏幕是从Screen继承的,为什么还要谈论FloatLayout?

<ProductScreen@Screen>: ... 

只是因为屏幕-> RelativeLayout-> FloatLayout。

FloatLayout中的所有小部件都从左下角定位,也就是说,它们在屏幕上会自动分配位置(0,0)。 在标记中,从顶部到底部跟踪添加元素到屏幕的顺序并不困难:


如果有人关注,那么我们仅将位置指示给一个小部件:

 MDToolbar: ... pos_hint: {"top": 1} 

除了特定的坐标(x,y),还可以为Kivy中的每个小部件提供位置提示:

 pos_hint: {"top": 1} #    pos_hint: {"bottom": 1} #    pos_hint: {"right": 1} #    pos_hint: {"center_y": .5} #     pos_hint: {"center_x": .2} #   20 %       ... ... 

因此,底部背景图片...

  BoxLayout: size_hint_y: None height: root.height - toolbar.height FitImage: source: "smokestackheather.jpeg" 

...感谢FitImage小部件(KivyMD库),它会自动拉伸到为其分配的所有空间,同时保持图像比例:



默认情况下,除非另有说明,否则Kivy中的每个小部件和布局都会获得100%的空间。 例如,如果您想在屏幕上添加一个按钮,显然您将执行以下操作:

 from kivy.app import App from kivy.lang import Builder KV = """ Button: text: "Button" """ class MyApp(App): def build(self): return Builder.load_string(KV) MyApp().run() 

并得到结果:


该按钮占用了100%的空间。 要将按钮放在屏幕中央,首先,需要给它提供所需的大小,其次,要指出按钮的位置:

 from kivy.app import App from kivy.lang import Builder KV = """ Button: text: "Button" size_hint: None, None size: 100, 50 pos_hint: {"center_y": .5, "center_x": .5} """ class MyApp(App): def build(self): return Builder.load_string(KV) MyApp().run() 

现在,情况发生了变化:


您还可以指定size_hint属性,范围从0到1(相当于0-100%),即大小提示:

 from kivy.app import App from kivy.lang import Builder KV = """ BoxLayout: Button: text: "Button" size_hint_y: .2 Button: text: "Button" size_hint_y: .1 Button: text: "Button" """ class MyApp(App): def build(self): return Builder.load_string(KV) MyApp().run() 


或相同的东西,但宽度提示( size_hint_x ):

 from kivy.app import App from kivy.lang import Builder KV = """ BoxLayout: Button: text: "Button" size_hint_x: .2 Button: text: "Button" size_hint_x: .1 Button: text: "Button" """ class MyApp(App): def build(self): return Builder.load_string(KV) MyApp().run() 


MDToolbar的高度为56dp,无法占据所有空间,如果您不告诉它其位置在顶部,它将自动粘贴在屏幕底部:


卡的列表-OrderProductLayout(我们将在下面讨论)-是带有MDCard元素的ScrollView,它占据了屏幕的整个高度,但是由于填充(缩进值在低位),它似乎位于屏幕中心的上方。 好吧,默认情况下,MDBottomAppBar将锚点拖放到屏幕的下边框。 因此,只有MDToolbar指示了它的位置。

现在让我们看看什么是OrderProductLayout小部件:


如您所见,这是ScrillView中嵌入的四张卡。 与从FloatLayout继承的父屏幕不同,此处所有小部件都是从上到下读取的。


这非常方便,因为窗口小部件具有清晰的层次结构,树状结构,并且一目了然,可以确定哪个窗口小部件/控件属于哪个布局。 在Kivy中,最常用的布局是BoxLayout-一个允许您将小部件垂直或水平放置在自己内部的框(默认是最后一个):


从使用BoxLayout水平方向的下图可以更清楚地看出这一点:


我们禁止BoxLayout使用100%的空间-size_hint_y:无 ,说-您的高度将与嵌套在您内部的最高元素的高度-height:self.minimum_height完全相同

图片清单:


如果我们想使用列表的垂直滚动,则需要如下更改GridLayout:

  ScrollView: GridLayout: size_hint_y: None height: self.minimum_height cols: 1 

用列( cols )替换行(列),并至少指示宽度而不是高度:

 from kivy.app import App from kivy.lang import Builder from kivy.metrics import dp from kivy.uix.button import Button KV = """ ScrollView: GridLayout: id: box size_hint_y: None height: self.minimum_height spacing: "5dp" cols: 1 """ class MyApp(App): def build(self): return Builder.load_string(KV) def on_start(self): for i in range(20): self.root.ids.box.add_widget( Button( text=f"Label {i}", size_hint_y=None, height=dp(40), ) ) MyApp().run() 



以下卡是颜色和尺寸的选择(它们几乎相同):


Kv语言标记语言的一个独特功能不仅是小部件的清晰结构,还在于该语言支持Python语言的某些功能。 即:调用方法,创建/更改变量,逻辑,I / O和数学运算...


计算在Label中声明的 ...

  Label: value: 0 text: str(self.value) 

...直接发生在标记本身中:

  MDIconButton: on_release: label_value.value -= 1 if label_value.value > 0 else 0 

而且我永远也不会相信这个(Flutter代码)...



...比Kv语言代码更具逻辑性和可读性:


昨天我被问及Kivy在开发环境中的表现如何,是否有自动编译,热加载和其他便利设施? 使用自动补全功能,如果您使用PyCharm,一切都会很好:


至于热负荷……Python是一种解释语言。 Kivy使用Python。 因此,要查看结果,您无需编译代码,就可以运行它-查看/测试它。 就像我说的那样,Kivy不使用本机API来呈现UI,因此它允许您使用屏幕模块来模拟各种模型的设备和平台。 使用必要的参数运行项目就足够了,这样就可以像在真实设备上运行一样在计算机上打开经过测试的应用程序的窗口。 听起来很奇怪,但是由于Kivy在呈现UI时是从平台中抽象出来的,因此消除了对繁琐缓慢的仿真器进行测试的需求。 这仅适用于UI。 例如,本文描述的测试应用程序已使用-m屏幕选项进行了测试:droid2,portrait,scale = .75

在左侧-在移动设备上运行,在右侧-在计算机上:

屏幕模块参数的完整列表:
 devices = { # device: (name, width, height, dpi, density) 'onex': ('HTC One X', 1280, 720, 312, 2), 'one': ('HTC One', 1920, 1080, 468, 3), 'onesv': ('HTC One SV', 800, 480, 216, 1.5), 's3': ('Galaxy SIII', 1280, 720, 306, 2), 'note2': ('Galaxy Note II', 1280, 720, 267, 2), 'droid2': ('Motorola Droid 2', 854, 480, 240, 1.5), 'xoom': ('Motorola Xoom', 1280, 800, 149, 1), 'ipad': ('iPad (1 and 2)', 1024, 768, 132, 1), 'ipad3': ('iPad 3', 2048, 1536, 264, 2), 'iphone4': ('iPhone 4', 960, 640, 326, 2), 'iphone5': ('iPhone 5', 1136, 640, 326, 2), 'xperiae': ('Xperia E', 480, 320, 166, 1), 'nexus4': ('Nexus 4', 1280, 768, 320, 2), 'nexus7': ('Nexus 7 (2012 version)', 1280, 800, 216, 1.325), 'nexus7.2': ('Nexus 7 (2013 version)', 1920, 1200, 323, 2), # taken from design.google.com/devices # please consider using another data instead of # a dict for autocompletion to work # these are all in landscape 'phone_android_one': ('Android One', 854, 480, 218, 1.5), 'phone_htc_one_m8': ('HTC One M8', 1920, 1080, 432, 3.0), 'phone_htc_one_m9': ('HTC One M9', 1920, 1080, 432, 3.0), 'phone_iphone': ('iPhone', 480, 320, 168, 1.0), 'phone_iphone_4': ('iPhone 4', 960, 640, 320, 2.0), 'phone_iphone_5': ('iPhone 5', 1136, 640, 320, 2.0), 'phone_iphone_6': ('iPhone 6', 1334, 750, 326, 2.0), 'phone_iphone_6_plus': ('iPhone 6 Plus', 1920, 1080, 400, 3.0), 'phone_lg_g2': ('LG G2', 1920, 1080, 432, 3.0), 'phone_lg_g3': ('LG G3', 2560, 1440, 533, 3.0), 'phone_moto_g': ('Moto G', 1280, 720, 327, 2.0), 'phone_moto_x': ('Moto X', 1280, 720, 313, 2.0), 'phone_moto_x_2nd_gen': ('Moto X 2nd Gen', 1920, 1080, 432, 3.0), 'phone_nexus_4': ('Nexus 4', 1280, 768, 240, 2.0), 'phone_nexus_5': ('Nexus 5', 1920, 1080, 450, 3.0), 'phone_nexus_5x': ('Nexus 5X', 1920, 1080, 432, 2.6), 'phone_nexus_6': ('Nexus 6', 2560, 1440, 496, 3.5), 'phone_nexus_6p': ('Nexus 6P', 2560, 1440, 514, 3.5), 'phone_samsung_galaxy_note_4': ('Samsung Galaxy Note 4', 2560, 1440, 514, 3.0), 'phone_samsung_galaxy_s5': ('Samsung Galaxy S5', 1920, 1080, 372, 3.0), 'phone_samsung_galaxy_s6': ('Samsung Galaxy S6', 2560, 1440, 576, 4.0), 'phone_sony_xperia_c4': ('Sony Xperia C4', 1920, 1080, 400, 2.0), 'phone_sony_xperia_z_ultra': ('Sony Xperia Z Ultra', 1920, 1080, 348, 2.0), 'phone_sony_xperia_z1_compact': ('Sony Xperia Z1 Compact', 1280, 720, 342, 2.0), 'phone_sony_xperia_z2z3': ('Sony Xperia Z2/Z3', 1920, 1080, 432, 3.0), 'phone_sony_xperia_z3_compact': ('Sony Xperia Z3 Compact', 1280, 720, 313, 2.0), 'tablet_dell_venue_8': ('Dell Venue 8', 2560, 1600, 355, 2.0), 'tablet_ipad': ('iPad', 1024, 768, 132, 1.0), 'tablet_ipad_mini': ('iPad Mini', 1024, 768, 163, 1.0), 'tablet_ipad_mini_retina': ('iPad Mini Retina', 2048, 1536, 326, 2.0), 'tablet_ipad_pro': ('iPad Pro', 2732, 2048, 265, 2.0), 'tablet_ipad_retina': ('iPad Retina', 2048, 1536, 264, 2.0), 'tablet_nexus_10': ('Nexus 10', 2560, 1600, 297, 2.0), 'tablet_nexus_7_12': ('Nexus 7 12', 1280, 800, 216, 1.3), 'tablet_nexus_7_13': ('Nexus 7 13', 1920, 1200, 324, 2.0), 'tablet_nexus_9': ('Nexus 9', 2048, 1536, 288, 2.0), 'tablet_samsung_galaxy_tab_10': ('Samsung Galaxy Tab 10', 1280, 800, 148, 1.0), 'tablet_sony_xperia_z3_tablet': ('Sony Xperia Z3 Tablet', 1920, 1200, 282, 2.0), 'tablet_sony_xperia_z4_tablet': ('Sony Xperia Z4 Tablet', 2560, 1600, 297, 2.0)TodoList() app.run() } 


好吧,最后,最终结果是在移动设备上启动...


唯一令人不安的是发射速度。 在同一个Flutter中,她简直太神奇了!

我希望我对某人有用,很快再见!

Source: https://habr.com/ru/post/zh-CN480018/


All Articles