Pengembangan aplikasi seluler dengan Python. Perpustakaan KivyMD


Salam! Hari ini kita kembali akan berbicara tentang perpustakaan KivyMD - satu set widget untuk pengembangan lintas platform di Python dalam gaya Desain Material. Dalam artikel ini, saya tidak akan meninjau widget KivyMD, seperti pada artikel baru - baru ini , tetapi lebih lanjut tentang memposisikan widget. Sesuatu seperti tutorial tentang mengembangkan aplikasi seluler dengan Python untuk pemula tidak akan ada di sini, jadi jika Anda pertama kali mendengar tentang kerangka kerja Kivy, Anda tidak mungkin tertarik dengan semua ini. Yah, kami melaju di bawah luka!

Suatu hari saya mengunduh aplikasi demo Flutter UIKit dari Google Play:


Dan sekarang kita akan mencoba mengulang satu layar dari aplikasi ini. Mari kita lihat hasilnya segera: Mengepak di sebelah kiri, Kivy & KivyMD di sebelah kanan.

Beberapa elemen UI berbeda, bukan karena beberapa fitur teknis, karena itu tidak mungkin untuk mendapatkan hasil yang identik, tetapi saya hanya berpikir itu akan lebih organik (misalnya, Toolbar hitam, menurut pendapat saya, tidak terlihat sama sekali).

Jadi! Apa yang mencolok ketika melihat layar yang akan kita mainkan? Tata letak depan latar belakang transparan. Di Kivy, opsi ini disediakan oleh FloatLayout, yang memungkinkan Anda menempatkan widget dan mengontrol satu di atas yang lain sebagai berikut:


Secara skematis, layar kita akan terlihat seperti ini:


Tata letak layar ini cukup sederhana:


Mengapa saya berbicara tentang FloatLayout jika layar kami diwarisi dari Layar?

<ProductScreen@Screen>: ... 

Hanya karena Layar -> RelativeLayout -> FloatLayout.

Semua widget di FloatLayout diposisikan dari sudut kiri bawah, yaitu, di layar mereka secara otomatis diberi posisi (0, 0). Di markup, tidak sulit untuk melacak urutan penambahan elemen ke layar dari atas ke bawah:


Jika seseorang memperhatikan, maka kami mengindikasikan posisi hanya satu widget:

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

Selain koordinat tertentu (x, y), setiap widget di Kivy dapat diberi petunjuk posisi:

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

Jadi, gambar latar belakang bawah ...

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

... berkat widget FitImage (perpustakaan KivyMD), widget ini secara otomatis direntangkan ke semua ruang yang dialokasikan untuknya sambil mempertahankan proporsi gambar:



Secara default, setiap widget dan tata letak di Kivy diberikan 100% dari ruang, kecuali ditentukan lain. Misalnya, jika Anda ingin menambahkan satu tombol ke layar, Anda jelas akan melakukan hal berikut:

 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() 

Dan dapatkan hasilnya:


Tombol ini menghabiskan 100% ruang. Untuk menempatkan tombol di tengah layar, Anda perlu, pertama, untuk mengatur ukuran yang diperlukan untuk itu dan, kedua, untuk menunjukkan di mana ia akan berada:

 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() 

Sekarang gambar telah berubah:


Anda juga dapat menentukan properti size_hint , dari 0 hingga 1, (setara dengan 0-100%), yaitu petunjuk ukuran:

 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() 


Atau hal yang sama, tetapi petunjuk lebar ( 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 memiliki ketinggian 56dp, tidak dapat menempati semua ruang, dan jika Anda tidak memberi tahu bahwa tempatnya ada di atas, MDToolbar akan secara otomatis menempel ke bagian bawah layar:


Daftar kartu - OrderProductLayout (kita akan membicarakannya di bawah ini) - adalah ScrollView dengan elemen MDCard dan menempati seluruh ketinggian layar, tetapi berkat bantalan (nilai indentasi dalam nilai terendah) tampaknya terletak sedikit di atas tengah layar. Nah, secara default MDBottomAppBar menjatuhkan jangkar ke batas bawah layar. Karena itu, hanya MDToolbar yang kami tunjukkan di mana tempatnya.

Sekarang mari kita lihat apa widget OrderProductLayout itu:


Seperti yang Anda lihat, ini adalah empat kartu yang tertanam di ScrillView. Berbeda dengan layar induk, yang diwarisi dari FloatLayout, di sini semua widget dibaca dari atas ke bawah.


Ini sangat nyaman, karena ada hierarki widget yang jelas, struktur pohon, dan sekilas jelas widget / kontrol mana yang termasuk tata letak mana. Di Kivy, tata letak yang paling umum digunakan adalah BoxLayout - kotak yang memungkinkan Anda menempatkan widget di dalam diri Anda secara vertikal atau horizontal (secara default - yang terakhir):


Ini bisa dilihat lebih jelas dari diagram berikut ini, di mana orientasi horisontal BoxLayout digunakan:


Kami melarang BoxLayout untuk menggunakan 100% ruang - size_hint_y: Tidak ada dan berkata - tinggi Anda akan persis sama dengan ketinggian elemen tertinggi yang bersarang di Anda - tinggi: self.minimum_height .

Daftar Gambar:


Jika kami ingin menggunakan pengguliran vertikal dari daftar, kami perlu mengubah GridLayout sebagai berikut:

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

Ganti baris (kolom) dengan kolom ( cols ) dan tunjukkan dalam minimum bukan lebar, tetapi tinggi:

 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() 



Kartu-kartu berikut adalah pilihan warna dan ukuran (mereka hampir identik):


Fitur khas bahasa markup Bahasa Kv tidak hanya struktur widget yang jelas, tetapi juga fakta bahwa bahasa ini mendukung beberapa fitur bahasa Python. Yaitu: memanggil metode, membuat / mengubah variabel, operasi logis, I / O dan matematika ...


Menghitung nilai yang dinyatakan dalam Label ...

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

... terjadi langsung di markup itu sendiri:

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

Dan saya tidak akan pernah percaya bahwa ini (kode Flutter) ...



... lebih logis dan dapat dibaca daripada kode Bahasa Kv:


Kemarin saya ditanya bagaimana kinerja Kivy dengan lingkungan pengembangan, apakah ada pelengkapan otomatis, hotload, dan fasilitas lainnya? Dengan pelengkapan otomatis, semuanya baik-baik saja jika Anda menggunakan PyCharm:


Adapun hotload ... Python adalah bahasa yang ditafsirkan. Kivy menggunakan Python. Dengan demikian, untuk melihat hasilnya, Anda tidak perlu mengkompilasi kode, jalankan - lihat / uji itu. Seperti yang saya katakan, Kivy tidak menggunakan API asli untuk rendering UI, oleh karena itu memungkinkan Anda untuk meniru berbagai model perangkat dan platform menggunakan modul layar . Cukup menjalankan proyek Anda dengan parameter yang diperlukan sehingga jendela aplikasi yang diuji terbuka di komputer seolah-olah sedang berjalan pada perangkat nyata. Kedengarannya aneh, tetapi karena Kivy abstrak dari platform dalam merender UI, ini menghilangkan kebutuhan akan emulator berat dan lambat untuk pengujian. Ini hanya berlaku untuk UI. Sebagai contoh, aplikasi pengujian yang dijelaskan dalam artikel ini diuji dengan opsi layar -m: droid2, potret, skala = .75 .

Di sebelah kiri - berjalan di perangkat seluler, di sebelah kanan - di komputer:

Daftar lengkap parameter modul layar:
 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() } 


Yah, dan akhirnya, hasil akhirnya adalah peluncuran di perangkat seluler ...


Satu-satunya hal yang mengecewakan adalah kecepatan peluncuran. Di Flutter yang sama dia sangat fenomenal!

Semoga bermanfaat bagi seseorang, sampai ketemu lagi!

Source: https://habr.com/ru/post/id480018/


All Articles