Klaviatura — KeyboardAvoidingView, fokus, yopish

~12 daq · React Native · Ro'yxatlar va formalar

Muammodan boshlaylik

Kirish ekrani: pastda "Kirish" tugmasi. Foydalanuvchi parol maydoniga bosadi — klaviatura chiqadi va parol maydonini ham, tugmani ham yopib qo'yadi. U nima yozayotganini ko'rmaydi va tugmaga yetolmaydi. Klaviaturani yopish uchun esa hech qanday yo'l yo'q.

Mobil ilovalarda eng ko'p shikoyat qilinadigan muammolardan biri. Yechim — bir nechta oddiy usul.


KeyboardAvoidingView

Klaviatura chiqqanda kontentni yuqoriga siljitadi:

import { KeyboardAvoidingView, Platform, ScrollView } from 'react-native';

export default function Kirish() {
  return (
    <KeyboardAvoidingView
      style={{ flex: 1 }}
      behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
    >
      <ScrollView
        contentContainerStyle={{ flexGrow: 1, justifyContent: 'center', padding: 24, gap: 14 }}
        keyboardShouldPersistTaps="handled"
      >
        <TextInput placeholder="Email" style={styles.input} />
        <TextInput placeholder="Parol" secureTextEntry style={styles.input} />
        <Tugma matn="Kirish" onPress={kirish} />
      </ScrollView>
    </KeyboardAvoidingView>
  );
}
behavior Nima qiladi
padding Pastga klaviatura balandligicha padding qo'shadi — iOS uchun
height Konteyner balandligini kamaytiradi — Android uchun
position Butun konteynerni siljitadi

Platformaga qarab behavior — standart naqsh. Android ning o'zi ham ko'pincha oynani klaviaturaga moslaydi (softwareKeyboardLayoutMode — app.json da "resize" standart).

flexGrow: 1 — flex: 1 emas: kontent qisqa bo'lsa ekranni to'ldiradi (markazlash ishlaydi), uzun bo'lsa — aylanadi.

Sarlavha bilan — keyboardVerticalOffset

Stack sarlavhasi bor ekranda kontent biroz kam siljiydi. Tuzatish:

import { useHeaderHeight } from '@react-navigation/elements';

const sarlavha = useHeaderHeight();
<KeyboardAvoidingView behavior="padding" keyboardVerticalOffset={sarlavha} style={{ flex: 1 }}>

Klaviaturani yopish

Bo'sh joyni bosganda

import { Keyboard, Pressable } from 'react-native';

<Pressable style={{ flex: 1 }} onPress={Keyboard.dismiss} accessible={false}>
  {/* forma */}
</Pressable>

ScrollView da — surganda yopilish

<ScrollView keyboardDismissMode="on-drag">   {/* iOS: 'interactive' — barmoq bilan tortib */}

keyboardShouldPersistTaps

Klaviatura ochiq paytda tugmani bosasiz — tugma ishlamaydi, faqat klaviatura yopiladi. Ikkinchi bosish kerak. Juda bezovta.

<ScrollView keyboardShouldPersistTaps="handled">
Qiymat Klaviatura ochiq paytda bosilganda
never (standart) Faqat klaviatura yopiladi
handled Tugma ishlaydi; bo'sh joy bosilsa — klaviatura yopiladi ✅
always Har doim bosish ishlaydi, klaviatura yopilmaydi

Formali har bir ScrollView / FlatList ga — keyboardShouldPersistTaps="handled".

Yuborishda

async function yuborish() {
  Keyboard.dismiss();
  // ...
}

Klaviatura hodisalari

useEffect(() => {
  const ochildi = Keyboard.addListener('keyboardDidShow', (e) => {
    console.log('Balandlik:', e.endCoordinates.height);
  });
  const yopildi = Keyboard.addListener('keyboardDidHide', () => {});
  return () => { ochildi.remove(); yopildi.remove(); };
}, []);

Masalan, klaviatura ochiqligida pastki tab panelni yashirish yoki chatda oxirgi xabarga scroll qilish.


Murakkab holatlar: react-native-keyboard-controller

O'rnatilgan KeyboardAvoidingView ning cheklovlari bor: ikki platformada turlicha ishlaydi, animatsiya klaviatura bilan sinxron emas, uzun formalarda fokusdagi maydonga avtomatik scroll yo'q. Professional ilovalarda ko'pincha react-native-keyboard-controller:

npx expo install react-native-keyboard-controller
// app/_layout.tsx
import { KeyboardProvider } from 'react-native-keyboard-controller';
<KeyboardProvider><Stack /></KeyboardProvider>

// Formada
import { KeyboardAwareScrollView } from 'react-native-keyboard-controller';

<KeyboardAwareScrollView bottomOffset={20} contentContainerStyle={{ padding: 16, gap: 14 }}>
  {/* 15 ta maydon — fokuslangani har doim klaviatura ustida ko'rinadi */}
</KeyboardAwareScrollView>
  • Ikkala platformada bir xil
  • Fokusdagi maydonga avtomatik scroll
  • Klaviatura bilan sinxron, silliq animatsiya

[!INFO] Bu kutubxona native kod talab qiladi — Expo Go da ishlamasligi mumkin, development build kerak (48-dars). O'rganish bosqichida KeyboardAvoidingView yetarli.


Chat ekrani

Chatda xabar yozish maydoni klaviatura bilan birga ko'tarilishi kerak:

<KeyboardAvoidingView style={{ flex: 1 }} behavior={Platform.OS === 'ios' ? 'padding' : undefined}
  keyboardVerticalOffset={useHeaderHeight()}>
  <FlatList
    data={xabarlar}
    inverted                                  // yangi xabarlar pastda, ro'yxat pastdan boshlanadi
    keyboardDismissMode="interactive"
    keyboardShouldPersistTaps="handled"
    renderItem={...}
  />
  <XabarPaneli />
</KeyboardAvoidingView>

inverted — ro'yxat teskari: eng yangisi pastda, scroll pastdan boshlanadi. Har qanday chat ilovasining asosi.


Sinash ro'yxati

  • Har bir maydonga bosing — u klaviatura ustida ko'rinadimi?
  • Klaviatura ochiq paytda tugmani bir marta bosish yetadimi?
  • Klaviaturani yopish yo'li bormi?
  • Ikkala platformada (iOS va Android klaviaturalari turlicha balandlikda)
  • Kichik ekranli telefonda

Nima uchun shunday?

Nima uchun React Native klaviaturani avtomatik hal qilmaydi — brauzer kontentni o'zi siljitadi-ku?

Brauzer bitta sahifani boshqaradi va uni klaviatura ochilganda shunchaki scroll qiladi. Mobil ilova esa ko'pincha scroll siz ekranlardan iborat: flex bilan joylashgan sarlavha, kontent va pastki panel. Qaysi element yuqoriga ko'tarilishi kerak — butun ekranmi, faqat pastki panelmi, yoki ro'yxatmi? Bu dizayn qarori va har bir ekranda boshqacha. Bundan tashqari, iOS va Android klaviaturani butunlay boshqacha boshqaradi. Shuning uchun React Native vositalar beradi, qarorni esa sizga qoldiradi.


Xulosa

Eslab qoling:

  • KeyboardAvoidingView — behavior: iOS — padding, Android — height yoki yo'q
  • Ichida ScrollView + contentContainerStyle={{ flexGrow: 1 }}
  • Sarlavha bor bo'lsa — keyboardVerticalOffset={useHeaderHeight()}
  • keyboardShouldPersistTaps="handled" — tugmalar birinchi bosishda ishlasin
  • Yopish: Keyboard.dismiss(), keyboardDismissMode="on-drag"
  • Murakkab formalar — react-native-keyboard-controller
  • Chat — FlatList inverted
  • Ikkala platformada sinang

Keyingi dars

24-dars: 3-4 bo'lim mashqlari — kontaktlar ilovasi