Skip to content

Aiogram 3: Текстовая клавиатура

https://habr.com/ru/articles/820733/

Текстовая клавиатура

Текстовая клавиатура отображается под полем набора сообщения. Основная её особенность в том, что она не содержит никакой информации, кроме текста на кнопках.

Другими словами, текст на кнопке отправляется боту, который реагирует на это сообщение, например, через F.text ==.

Начнем с кода. Реализуем его в файле all_kb.py, который находится в пакете keyboards.

Создадим простую клавиатуру главного меню. Для разнообразия сделаем так, чтоб у администраторов была дополнительная кнопка "Админ Панель" после выполнения простого фильтра.

Импорты в all_kb.py:

python
from aiogram.types import KeyboardButton, ReplyKeyboardMarkup
from create_bot import admins

Создание клавиатуры "Главное меню":

python
def main_kb(user_telegram_id: int):
    kb_list = [
        [KeyboardButton(text="📖 О нас"), KeyboardButton(text="👤 Профиль")],
        [KeyboardButton(text="📝 Заполнить анкету"), KeyboardButton(text="📚 Каталог")]
    ]
    if user_telegram_id in admins:
        kb_list.append([KeyboardButton(text="⚙️ Админ панель")])
    keyboard = ReplyKeyboardMarkup(keyboard=kb_list, resize_keyboard=True, one_time_keyboard=True)
    return keyboard

Функция main_kb принимает один аргумент user_telegram_id типа int, который представляет собой ID пользователя в Telegram.

Создание списка кнопок:

python
kb_list = [
    [KeyboardButton(text="📖 О нас"), KeyboardButton(text="👤 Профиль")],
    [KeyboardButton(text="📝 Заполнить анкету"), KeyboardButton(text="📚 Каталог")]
]
  • kb_list: список списков с объектами KeyboardButton.
  • Первая строка кнопок: 📖 О нас и 👤 Профиль.
  • Вторая строка кнопок: 📝 Заполнить анкету и 📚 Каталог.

Добавление кнопки для админов:

python
if user_telegram_id in admins:
    kb_list.append([KeyboardButton(text="⚙️ Админ панель")])

Если user_telegram_id присутствует в списке admins, добавляется строка с кнопкой ⚙️ Админ панель.

Создание и возврат объекта клавиатуры:

python
keyboard = ReplyKeyboardMarkup(keyboard=kb_list, resize_keyboard=True, one_time_keyboard=True)
return keyboard

Функция возвращает созданную клавиатуру, которую мы затем привязываем к сообщению.

Привязка клавиатуры к сообщению (handlers/start.py):

python
from aiogram import Router, F
from aiogram.filters import CommandStart
from aiogram.types import Message
from keyboards.all_kb import main_kb

start_router = Router()

@start_router.message(CommandStart())
async def cmd_start(message: Message):
    await message.answer('Запуск сообщения по команде /start используя фильтр CommandStart()',
                         reply_markup=main_kb(message.from_user.id))

Для нашего фильтра мы вытянули телеграм айди пользователя из объекта message (message.from_user.id).

Импортируем клавиатуру из пакета keyboards и при помощи reply_markup привязываем её к сообщению. Давайте посмотрим что у нас получилось:

img.png

Так как у нас кнопок было достаточно много — они у нас получились более-менее обычного размера, но, если бы это была всего 1 кнопка, то тут бы вышло такое:

img_1.png

На любителя. Давайте исправим.

Улучшение клавиатуры

python
def main_kb(user_telegram_id: int):
    kb_list = [
        [KeyboardButton(text="📖 О нас"), KeyboardButton(text="👤 Профиль")],
        [KeyboardButton(text="📝 Заполнить анкету"), KeyboardButton(text="📚 Каталог")]
    ]
    if user_telegram_id in admins:
        kb_list.append([KeyboardButton(text="⚙️ Админ панель")])
    keyboard = ReplyKeyboardMarkup(
        keyboard=kb_list,
        resize_keyboard=True,
        one_time_keyboard=True,
        input_field_placeholder="Воспользуйтесь меню:"
    )
    return keyboard
  • resize_keyboard=True: клавиатура будет автоматически изменять размер.
  • one_time_keyboard=True: клавиатура скрывается после одного использования.
  • input_field_placeholder: заменяет стандартную подпись «Написать сообщение...» на пользовательскую.

Смотрим что получилось:

img_2.png

Красиво, правда?

Особые текстовые кнопки

Теперь создадим клавиатуру с "особыми кнопками". На примере будут кнопки:

  • Поделиться контактами
  • Поделиться локацией
  • Создать викторину/опрос

Создание специальной клавиатуры:

python
def create_spec_kb():
    kb_list = [
        [KeyboardButton(text="Отправить гео", request_location=True)],
        [KeyboardButton(text="Поделиться номером", request_contact=True)],
        [KeyboardButton(text="Отправить викторину/опрос", request_poll=KeyboardButtonPollType())]
    ]
    keyboard = ReplyKeyboardMarkup(keyboard=kb_list,
                                   resize_keyboard=True,
                                   one_time_keyboard=True,
                                   input_field_placeholder="Воспользуйтесь специальной клавиатурой:")
    return keyboard
  • request_location=True: позволяет пользователю отправить геолокацию.
  • request_contact=True: позволяет отправить контактный номер.
  • request_poll=KeyboardButtonPollType(): позволяет создать викторину или опрос. Может принимать один из параметров type = «quiz» (викторина) или «regular» (опрос). В нашем случае и то и то будет обработано.

Привязка специальной клавиатуры под обработчик /start_2:

python
@start_router.message(Command('start_2'))
async def cmd_start(message: Message):
    await message.answer('Запуск сообщения по команде /start_2 используя фильтр Command()',
                         reply_markup=create_spec_kb())

Смотрим что получилось:

img_3.png

Визуально ничем не отличается от обычной текстовой клавиатуры.

Геолокацию можно отправить только со смартфона. При вызове этой опции через пк - получим такое сообщение:

img_4.png

Со смартфона данные передаются корректно, и теперь остается только обработать гео-данные. Как это сделать мы подробно обговорим в теме про FSM.

При клике на "Поделиться номером" (текст может быть любой). Пользователь увидит всплывающее окно:

img_5.png

Так выглядит всплывающее окно на этом этапе.

После клика на "Поделиться" произойдет отправка номера телефона, который привязан к профилю телеграмм. Далее останется захватить ответ. Как это сделать мы тоже подробно обговорим в теме про FSM.

img_6.png

Так выглядит универсально окно. Давайте создадим опрос.

img_7.png

Пример

Штуку с викториной и опросником удобно использовать в группах и телеграмм каналах, которые будет администрировать ваш бот.

Использование ReplyKeyboardBuilder

Теперь давайте воспользуемся нововведением в aiogram 3, а именно строителем текстовых клавиатур. Для начала сделаем импорт:

python
from aiogram.utils.keyboard import ReplyKeyboardBuilder

Давайте сгенирируем некую шкалу голосования в котором результаты у нас записаны в виде баллов от 1 до 10. Пример кода:

python
def create_rat():
    builder = ReplyKeyboardBuilder()
    for item in [str(i) for i in range(1, 11)]:
        builder.button(text=item)
    builder.button(text='Назад')
    builder.adjust(4, 4, 2, 1)
    return builder.as_markup(resize_keyboard=True)

Описание функции create_rat

Создаем объект ReplyKeyboardBuilder(), который будет использоваться для построения клавиатуры.

Добавление кнопок с оценками

python
for item in [str(i) for i in range(1, 11)]:
        builder.button(text=item)

Создаем список строк от '1' до '10' с помощью генератора списка.

Для каждого элемента в этом списке добавляем кнопку с текстом, равным этому элементу.

Настройка расположения кнопок

adjust(4, 4, 2, 1) указывает, что кнопки должны быть размещены в строках по 4, 4, 2 и 1 кнопке соответственно.

  • Первая строка будет содержать 4 кнопки.
  • Вторая строка будет содержать 4 кнопки.
  • Третья строка будет содержать 2 кнопки.
  • Четвертая строка будет содержать 1 кнопку ("Назад").

Возврат разметки клавиатуры

python
return builder.as_markup(resize_keyboard=True)

Преобразуем построенную клавиатуру в объект ReplyKeyboardMarkup с помощью метода as_markup.

Указываем параметр resize_keyboard=True, чтобы клавиатура автоматически изменяла размер в зависимости от количества и размера кнопок.

Привяжем клавиатуру к команде /start_3

python
@start_router.message(F.text == '/start_3')
async def cmd_start(message: Message):
    await message.answer('Запуск сообщения по команде /start_3 используя магический фильтр F.text!',
                         reply_markup=create_rat())

Смотрим что получилось:

img_8.png

Contacts: teffal@mail.ru