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.utils import platform Builder.load_string(''' : orientation: 'vertical' spacing: dp(5) # Плашка результатов BoxLayout: id: result_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: result_label text: 'Результат поиска' color: 1, 1, 1, 1 font_size: dp(16) bold: True halign: 'center' # Основная область контента с кнопками ScrollView: id: main_scroll size_hint_y: 1 do_scroll_y: not search_panel.is_raised BoxLayout: id: content_box orientation: 'vertical' size_hint_y: None height: self.minimum_height spacing: dp(5) padding: dp(10) # Поисковая панель BoxLayout: id: search_panel size_hint_y: None height: dp(60) pos_hint: {'x': 0, 'y': 0} padding: dp(10) spacing: dp(5) is_raised: False TextInput: id: search_input hint_text: 'Введите запрос...' 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(*args) on_text_validate: root.do_search() Button: id: action_button text: 'Добавить' 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_result_panel() ''') class SearchAppUI(BoxLayout): def __init__(self, **kwargs): super().__init__(**kwargs) Window.bind(on_keyboard=self.on_keyboard) self.keyboard_height = dp(300) self.create_content_buttons() # Для Android добавляем обработчик кнопки назад if platform == 'android': from android.runnable import run_on_ui_thread from jnius import autoclass self._activity = autoclass('org.kivy.android.PythonActivity').mActivity Window.bind(on_keyboard=self.on_keyboard) def on_keyboard(self, window, key, *args): if key == 27: # ESC или кнопка назад на Android # Если поисковая панель поднята - сначала опускаем её if self.ids.search_panel.is_raised: self.ids.search_input.focus = False return True # Иначе выходим из приложения App.get_running_app().stop() return True def create_content_buttons(self): """Создаем кнопки контента""" content_box = self.ids.content_box for i in range(1, 21): btn = Button( text=f'Кнопка {i}', size_hint_y=None, height=dp(50), background_normal='', background_color=(0.4, 0.4, 0.6, 1), on_press=self.on_button_press ) content_box.add_widget(btn) def on_button_press(self, instance): self.ids.result_label.text = f"Выбрано: {instance.text}" if self.ids.result_panel.height == 0: self.toggle_result_panel(show=True) def on_search_focus(self, instance, focused): if focused: self.ids.search_panel.is_raised = True Animation( y=self.keyboard_height + dp(10), duration=0.2, t='out_quad' ).start(self.ids.search_panel) Animation( scroll_y=0, duration=0.3 ).start(self.ids.main_scroll) else: self.ids.search_panel.is_raised = False Animation( y=0, duration=0.2, t='out_quad' ).start(self.ids.search_panel) def toggle_result_panel(self, show=None): """Переключает видимость панели результатов""" result_panel = self.ids.result_panel action_button = self.ids.action_button search_input = self.ids.search_input if show is None: show = result_panel.height == 0 if show: Animation(height=dp(35), opacity=1, duration=0.3).start(result_panel) action_button.text = "Убрать" action_button.background_color = (0.8, 0.3, 0.3, 1) # Красный цвет для "Убрать" else: Animation(height=0, opacity=0, duration=0.3).start(result_panel) action_button.text = "Добавить" action_button.background_color = (0.4, 0.6, 0.4, 1) # Зеленый цвет для "Добавить" # Закрываем клавиатуру только если поле ввода не в фокусе if not search_input.focus: search_input.focus = False def do_search(self): """Выполняет поиск по введенному тексту""" query = self.ids.search_input.text.strip() if query: self.ids.result_label.text = f"Найдено: {query}" if self.ids.result_panel.height == 0: self.toggle_result_panel(show=True) # Не снимаем фокус с поля ввода после поиска # self.ids.search_input.focus = False class SearchApp(App): def build(self): Window.clearcolor = (0.4, 0.4, 0.4, 1) return SearchAppUI() if __name__ == '__main__': SearchApp().run()