Archives
Trending
Support
Login
clear text
XML
Django
JavaScript
MATLAB
C
C++
Python
SQL
Shell
Markdown
YAML
JSON
CSS
PHP
Java
Ruby
Go
Rust
Swift
Kotlin
TypeScript
Perl
Lua
R
Scala
Haskell
Groovy
Dart
Clojure
VB.NET
Objective-C
PowerShell
Bash
CoffeeScript
Verilog
from kivy.config import Config Config.set('graphics', 'width', '360') Config.set('graphics', 'height', '640') Config.set('graphics', 'resizable', '0') from kivy.app import App from kivy.lang import Builder from kivy.animation import Animation from kivy.core.window import Window from kivy.metrics import dp from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button from kivy.uix.widget import Widget from kivy.uix.behaviors import ButtonBehavior from kivy.uix.label import Label from kivy.uix.modalview import ModalView from kivy.properties import StringProperty, NumericProperty from kivy.utils import platform from kivy.clock import Clock Builder.load_string('''
: canvas: Color: rgba: 0, 0, 0, 0.3 if self.active else 0 Rectangle: pos: self.pos size: self.size
: orientation: 'horizontal' size_hint_y: None height: dp(50) spacing: dp(5) padding: dp(5) canvas.before: Color: rgba: 0.4, 0.4, 0.6, 1 Rectangle: pos: self.pos size: self.size Label: id: title_label text: root.item_title size_hint_x: 0.8 halign: 'left' valign: 'middle' text_size: self.width, None color: 1, 1, 1, 1 font_size: dp(16) bold: True Button: id: info_button text: 'i' size_hint_x: 0.2 size_hint_y: 1 background_normal: '' background_color: 0.8, 0.8, 0.2, 1 font_size: dp(14) bold: True on_press: root.show_info()
: size_hint: (0.8, 0.8) auto_dismiss: True BoxLayout: orientation: 'vertical' padding: dp(20) spacing: dp(10) canvas.before: Color: rgba: 0.3, 0.3, 0.5, 1 Rectangle: pos: self.pos size: self.size Label: text: root.title font_size: dp(20) bold: True color: 1, 1, 1, 1 size_hint_y: 0.3 Label: text: root.description font_size: dp(16) color: 1, 1, 1, 1 text_size: self.width, None valign: 'top' halign: 'left' size_hint_y: 0.7 Button: text: 'Close' size_hint_y: 0.2 background_normal: '' background_color: 0.8, 0.3, 0.3, 1 on_press: root.dismiss()
: orientation: 'vertical' spacing: dp(5) padding: [0, 0, 0, root.keyboard_padding] BoxLayout: id: notification_panel size_hint_y: None height: 0 opacity: 0 canvas.before: Color: rgba: 0.2, 0.8, 0.4, 0.9 Rectangle: pos: self.pos size: self.size Label: id: notification_label text: '' color: 1, 1, 1, 1 font_size: dp(18) bold: True halign: 'center' padding: [dp(10), dp(5)] ScrollView: id: content_scroll size_hint_y: 1 do_scroll_y: True BoxLayout: id: items_container orientation: 'vertical' size_hint_y: None height: self.minimum_height spacing: dp(5) padding: [dp(10), dp(0)] BoxLayout: id: search_controls size_hint_y: None height: dp(60) padding: dp(10) spacing: dp(5) TextInput: id: search_field hint_text: 'Enter search query...' multiline: False size_hint_x: 0.8 padding: [dp(10), (self.height - self.line_height)/2] font_size: dp(16) on_focus: root.on_search_focus_changed(*args) on_text_validate: root.perform_search() Button: id: action_btn text: 'Add' size_hint_x: 0.2 font_size: dp(13) bold: True background_normal: '' background_color: (0.4, 0.6, 0.4, 1) on_press: root.toggle_notification_panel() ClickableOverlay: id: keyboard_dismiss_area size_hint: (1, 1) active: False on_press: root.hide_virtual_keyboard() self.active = False ''') class ClickableOverlay(ButtonBehavior, Widget): active = False class InfoDialog(ModalView): title = StringProperty('') description = StringProperty('') class ContentItem(ButtonBehavior, BoxLayout): item_title = StringProperty('') item_description = StringProperty('') def __init__(self, item_title="", item_description="", **kwargs): super().__init__(**kwargs) self.item_title = item_title self.item_description = item_description def on_press(self): app = App.get_running_app() app.root.ids.notification_label.text = f"Selected: {self.item_title}" if app.root.ids.notification_panel.height == 0: app.root.show_notification_panel() def show_info(self): dialog = InfoDialog(title=self.item_title, description=self.item_description) dialog.open() class SearchApplicationUI(BoxLayout): keyboard_height = NumericProperty(0) keyboard_padding = NumericProperty(0) def __init__(self, **kwargs): super().__init__(**kwargs) self._keyboard_listener = None self._keyboard_measured = False Window.bind(on_keyboard=self._on_keyboard) # Для Android настраиваем слушатель клавиатуры if platform == 'android': Clock.schedule_once(self._setup_keyboard_listener, 0.5) self.initialize_content() Window.clearcolor = (0.4, 0.4, 0.4, 1) def _setup_keyboard_listener(self, dt): """Установка слушателя клавиатуры для Android""" try: from android.runnable import run_on_ui_thread from jnius import autoclass @run_on_ui_thread def attach_listener(): View = autoclass('android.view.View') root_view = Window._get_activity().getWindow().getDecorView() root_view.getViewTreeObserver().addOnGlobalLayoutListener( KeyboardListener(self)) attach_listener() except Exception as e: print(f"Error setting up keyboard listener: {e}") def _on_keyboard(self, window, key, *args): """Обработка аппаратной клавиатуры""" if key == 27: # ESC key self.hide_virtual_keyboard() return True return False def on_search_focus_changed(self, instance, has_focus): """Измеряем высоту клавиатуры при фокусе""" if has_focus: if platform == 'android': Clock.schedule_once(self._measure_keyboard_height, 0.3) self.ids.keyboard_dismiss_area.active = True else: self.ids.keyboard_dismiss_area.active = False def _measure_keyboard_height(self, dt): """Точное измерение высоты клавиатуры""" try: input_field = self.ids.search_field pos = input_field.to_window(*input_field.pos) # Вычисляем видимую высоту над клавиатурой visible_height = pos[1] + input_field.height self.keyboard_height = max(0, Window.height - visible_height) # Обновляем отступ и показываем результат self.keyboard_padding = self.keyboard_height self.ids.notification_label.text = f"Keyboard: {self.keyboard_height:.1f}px" self.show_notification_panel() # Прокручиваем к полю ввода Clock.schedule_once(lambda dt: self.ids.content_scroll.scroll_to(input_field), 0.1) except Exception as e: print(f"Keyboard measurement error: {e}") def hide_virtual_keyboard(self): """Скрываем виртуальную клавиатуру""" self.ids.search_field.focus = False self.keyboard_padding = 0 def initialize_content(self): """Заполняем контент""" for i in range(1, 21): item = ContentItem( item_title=f'Item {i}', item_description=f'Detailed description for item {i}.' ) self.ids.items_container.add_widget(item) def toggle_notification_panel(self): """Переключаем панель уведомлений""" if self.ids.notification_panel.height == 0: query = self.ids.search_field.text.strip() if query: self.ids.notification_label.text = f"Added: {query}" self.show_notification_panel() else: self.hide_notification_panel() def show_notification_panel(self): """Показываем панель уведомлений""" Animation(height=dp(50), opacity=1, duration=0.3).start(self.ids.notification_panel) self.ids.action_btn.text = "Remove" self.ids.action_btn.background_color = (0.8, 0.3, 0.3, 1) def hide_notification_panel(self): """Скрываем панель уведомлений""" Animation(height=0, opacity=0, duration=0.3).start(self.ids.notification_panel) self.ids.action_btn.text = "Add" self.ids.action_btn.background_color = (0.4, 0.6, 0.4, 1) def perform_search(self): """Выполняем поиск""" query = self.ids.search_field.text.strip() if query: self.ids.notification_label.text = f"Found: {query}" if self.ids.notification_panel.height == 0: self.show_notification_panel() # Класс для слушателя клавиатуры Android if platform == 'android': from jnius import PythonJavaClass, java_method class KeyboardListener(PythonJavaClass): __javainterfaces__ = ['android/view/ViewTreeObserver$OnGlobalLayoutListener'] __javacontext__ = 'app' def __init__(self, root_widget): super().__init__() self.root_widget = root_widget @java_method('()V') def onGlobalLayout(self): Clock.schedule_once(lambda dt: self.root_widget._measure_keyboard_height(dt), 0) class SearchApplication(App): def build(self): return SearchApplicationUI() if __name__ == '__main__': SearchApplication().run()
Mark as private
for 30 minutes
for 6 hours
for 1 day
for 1 week
for 1 month
for 1 year