Auto-strecksatsen, med Reagera Native TextInput på iOS

Auto-strecksatsen, med Reagera Native TextInput på iOS

Logotyp av vår app Codepress

På ett av våra projekt, Codepress, användare ska kunna lösa kodning utmaningar på sina mobila enheter. Detta gör det möjligt för människor att öva för tekniska intervjuer om att gå på sin egen bekvämlighet. En av de frågor som användarna uttryckte var att det var en plåga att gå in i fyra utrymmen på tangentbordet i stället för fliken.

just nu håller vi på att utveckla appen med Expo som stöder inte användning av anpassade tangentbord. Innan vi bestämmer oss för att mata ut från Expo och skapa ett eget tangentbord som har en flik knappen vi undersöker andra alternativ. Ett av dessa alternativ är att ha auto-strecksatsen i Reagera Native s TextInput komponent.

Vår TextInput-komponent ser ut så här

<TextInput 
style={stilar.code}
flerradigt={true}
onChangeText={(kod) => detta.onChangeText(kod)}
value={detta.stat.code}
autoCapitalize='none'
autokorrigering={false}
autoGrow={true}
onKeyPress={detta.handleKeyDown}
onSelectionChange={detta.getCursor}
/>

för det Första måste vi fånga de förändringar som användaren gör i TextInput-komponent

onChangeText = (kod) => {
om (detta.stat.lastAction !== "Enter") {
detta.setState({
- kod: kod
})
}
}

setState är insvept i en if-sats där den senaste åtgärden inte lika komma in eftersom vi genomför automatisk indrag som utlöses när enter trycks in så vi behöver för att fånga detta fall på olika sätt vilket kommer att förklaras senare.

Nu att vi kan fånga upp de förändringar som användaren gör för att koden i TextInput-komponent kan vi börja arbeta på automatisk indrag. Placeringen av markören behöver tas fram så att vi kan korrekt auto-strecksatsen nästa rad baserat på den tidigare linjen att enter trycks.

Detta är gjort med onSelectionChange prop där vår funktion ser ut så här

getCursor = (e) => {
var cursor = e.nativeEvent.urval;
var cursorPosition;
om (markören.start - > cursor.slut) {
cursorPosition = markören.start;
} else {
cursorPosition = markören.slut
}
detta.setState({
cursorPosition: cursorPosition
})
}

Denna funktion kommer att hålla uppdatera markörens position och spara det till staten så att vi kan bestämma plats i strängen när enter trycks.

nästa del av koden behandlar onKeyPressed prop. Detta är den funktion i sin helhet och jag kommer att bryta ner det i delar för att förstå vad som är happenning

handleKeyDown = (e) => {
om (e.nativeEvent.key == "Retur") {
var tempCode = detta.stat.koden
var beforeEnter = tempCode.substring(0, detta.stat.cursorPosition)
var afterEnter = tempCode.substring(det här.stat.cursorPosition)
var index = beforeEnter.lastIndexOf('\n') + 1
var previousLine = beforeEnter.substring(index)

var tabLevel = 0
om (previousLine.trim().skiva(-1) === ':') {
var prevTabLevel = previousLine.sök(/\S|$/) / 4
tabLevel = prevTabLevel + 1
} else {
tabLevel = previousLine.sök(/\S|$/) / 4
}

tempCode = beforeEnter + '\n'

 for (var i = 0; i < tabLevel; i++) {
tempCode = tempCode + ' '
}
 tempCode = tempCode + afterEnter
 här.setState({
- kod: tempCode,
lastAction: e.nativeEvent.nyckeln,
})
} else {
detta.setState({
lastAction: e.nativeEvent.nyckeln
})
}
}

Den första delen till denna funktion är if-else-uttryck

om (e.nativeEvent.key == "Retur") {
// Kod
} else {
// Kod
}

e.nativeEvent.nyckel talar om för oss vilken tangent har tryckts ned. Eftersom vi genomför automatisk indrag den viktigaste nyckeln vi är fokuserade på är “Skriv” . Resten av knapparna är grupperade tillsammans.

Nästa vi kommer att gå vidare med det fall när enter har tryckts ned

var tempCode = detta.stat.koden
var beforeEnter = tempCode.substring(0, detta.stat.cursorPosition)
var afterEnter = tempCode.substring(det här.stat.cursorPosition)
var index = beforeEnter.lastIndexOf('\n') + 1
var previousLine = beforeEnter.substring(index)

Dessa rader i kod sätter upp de variabler som resten av den om fallet kommer att använda. beforeEnter – butiker delsträngen före markörens position när enter har tryckts ned och afterEnter – butiker delsträng efter markörens position när enter har tryckts ned. Index – butiker index i strängen strax efter den sista tecken för ny rad. Vi ökar index med 1 så att den nya linjen karaktär kommer inte att vara närvarande när vi räknar antalet platser i den tidigare linjen. previousLine är den variabel som lagrar linje precis ovanför den nya linje som vi försöker att automatisk indrag (linjen att användarens markör på när enter har tryckts ned.)

går vidare till den andra delen av denna if-sats, beräkningarna

var tabLevel = 0
if (previousLine.trim().skiva(-1) === ':') {
var prevTabLevel = previousLine.sök(/\S|$/) / 4
tabLevel = prevTabLevel + 1
} else {
tabLevel = previousLine.sök(/\S|$/) / 4
}

tempCode = beforeEnter + '\n'

for (var i = 0; i < tabLevel; i++) {
tempCode = tempCode + ' '
}
tempCode = tempCode + afterEnter

Denna del av koden gör beräkningar som gör automatisk indrag för oss. tabLevel är graden av flikar/indentions som för närvarande anges i vår användning i mål som fyra tecken.

if-satsen förutsätter att koda språk som användaren skriver i python, men kan anpassas för språk. previousLine.trim().skiva(-1) === ‘:' detta villkor är ute efter att se om den tidigare raden avslutas med ett semikolon eller inte. I python om en rad kod avslutas med ett semikolon nästa uppsättning linjer är indragna en nivå mer lik klamrar i Javascript. Om det var ett semikolon vi räknar tabLevel i den föregående raden med var prevTabLevel = previousLine.sök(/\S|$/) / 4, som kommer att räkna antalet mellanslag före en icke mellanslag och dela det med 4 ger den föregående fliken nivå. Eftersom den tidigare linjen hade ett semikolon på slutet vet vi att den nuvarande linjen måste vara auto-indragen med en mer nivå än den tidigare linjen så vi satte tabLevel i prevTabLevel + 1 .

Om den tidigare linjen inte har ett semikolon på slutet av raden så vi antar att tabLevel kommer att vara samma som den tidigare linjen.

Efter beräkning tabLevel – vi montera strängen kod där en for-loop används för att infoga den automatiska indrag baserat på tabLevel .

Den sista delen av den villkorliga när enter trycks ner är att spara ändringarna av auto-strecksatsen tillsammans med tangenten som trycktes.

här.setState({
- kod: tempCode,
lastAction: e.nativeEvent.nyckeln,
})

För det fall där enter-knappen inte trycks in, på den tangent som trycks sparas till staten

else {
detta.setState({
lastAction: e.nativeEvent.nyckeln
})
}

Med alla dessa funktioner på plats, auto-strecksatsen är klar och kommer att ge användaren en mer tillfredsställande användarupplevelse.

Observera: Den onKeyPress prop för TextInput bränder innan onChange callbacks som beskrivs i den Reagerar Native-dokument. Detta påverkar en del saker i vägen för att koden var skriven. För det första, markörens position tillgänglig för användning i onKeyPress funktion kommer att vara till markörens position på den tid ange var pressade och inte markörens position på den nya linjen. För det andra, eftersom onKeyPress är sparken först, onChangeText kommer fortfarande köra efter onKeyPress är klar. Det är därför vi spara ändringarna i rad kod i onKeyPress funktion, liksom att stoppa onChangeText funktion för att spara sina ändringar om enter har tryckts ned, annars auto-strecksatsen gjort i onKeyPress kommer att skrivas över av onChangeText funktion.