Flutter e direzionalità (RTL)
Come evitare gli errori comuni tenendo bene a mente il supporto RTL
English version here
Cosa è RTL?
Alcune lingue, come l’Arabo, sono pensate per essere lette da destra verso sinistra invece che da sinistra verso destra.
Questo non è solo un cambio a livello testuale infatti tutta l’interfaccia, comprese azioni e icone, deve adeguarsi.
Flutter ci aiuta nel supporto di tutte le lingue RTL (Right to left) in modo da realizzare le nostre applicazioni senza troppi sforzi! Per una panoramica più accurata sui concetti principali del RTL, vi invito a consultare la pagina sul sito Material Design.
Come implementarlo in Flutter
Durante la scrittura del codice possiamo utilizzare Directionality.of(context)
per sapere l’attuale direzione del testo e con i valori che ci verranno restituiti da questa chiamata (TextDirection.ltr
o TextDirection.rtl
), sarà nostra accortezza far in modo che la nostra applicazione venga disegnata in modo opportuno.
Per nostra fortuna, molti Widget sono già pensati per questo.
Rows e Columns
Rows e Columns sono già predisposti alla direzione RTL di default. Usando start
e end
come allineamento il contenuto verrà mostrato nel modo appropriato.
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("A"),
Text("B"),
],);
}
}
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("A"),
Text("B"),
],);
}
}
Alignment Geometry
Tutti i widget che gestiscono un AlignmentGeometry
(come Container
, Align
e qualche altro Widget) possono essere facilmente convertiti utilizzando AlignmentDirectional
al posto del più comune Alignment
Senza supporto RTL
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.centerLeft,
child: Container(
width: 20,
height: 20,
color: Colors.red,
));
}
}
Con supporto RTL
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Align(
alignment: AlignmentDirectional.centerStart,
child: Container(
width: 20,
height: 20,
color: Colors.red,
));
}
}
Margini e Paddings
Tutti i margini e i padding possono supportare l’RTL facilmente utilizzando EdgeInsetsDirectional
al posto di EdgeInsets
.
Per esempio, invece di usare EdgeInsets.only(left: x)
possiamo sostituirlo con EdgeInsetsDirectional.only(start: x)
per essere sicuri che venga rispettato nelle lingue RTL.
L’utilizzo di EdgeInsets.all
o EdgeInsets.symmetric
è già sicuro, in quanto i valori di left e right saranno sempre coincidenti
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsetsDirectional.only(start: 30),
child: Container(
color: Colors.red,
));
}
}
Icone
La gestione delle icone può risultare un po’ più complessa, perché alcune icone sono già RTL safe, mentre altre no. Un modo sicuro per scoprirlo è controllare la documentazione ufficiale della classe Icons: Icons class — material library — Dart API e vedere se l’icona che vogliamo utilizzare ha il parametro matchTextDirection
valorizzato a true; per esempio guardando Icons.arrow_back
noteremo le seguenti informazioni:
matchTextDirection: true
vuol dire che la nostra icona verrà ribaltata nelle lingue che utilizzano l’RTL e mentre questo si verifica per arrow_back
, per altre icone come wheelchair_pickup
no.
Questo non vuol necessariamente dire che non possiamo avere le icone specchiate quando viene utilizzata una lingua RTL, ma semplicemente che avremmo bisogno di un pizzico di impegno in più.
Invece di usare la direttamente la costante dentro Icons
possiamo usare i suoi parametri per istanziare un nuovo IconData
con i valori presi dalla stessa costante e aggiungendo il parametro matchTextDirection: true
, come in questo esempio:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Icon(IconData(
Icons.wheelchair_pickup.codePoint,
fontFamily: Icons.wheelchair_pickup.fontFamily,
matchTextDirection: true,
)),
);
}
}
Attenzione però, il fatto che sia possibile aggiungere il parametro a tutte le icone non vuol sempre dire che sia il caso di farlo! Non tutte le icone DEVONO essere specchiate nell’RTL, infatti una regola di base è quella che dice che le icone che comunicano una direzione come frecce o simili, vanno specchiate, mentre le altre non sempre. Per altre informazioni su quando ribaltare le icone e quando no, suggerisco sempre di controllare il sito Material Design
Altri widgets
Alcuni widget che sembrano non supportare la direzionalità, hanno spesso una controparte che gestisce il supporto RTL in modo semplice. Solitamente questi widget hanno lo stesso nome seguito da Directional
; un esempio di questa convenzione è dato dal widget Positioned
utilizzato dentro Stack
, questo infatti non supporta la Direzionalità ma se abbiamo bisogno del supporto RTL per la nostra applicazione, possiamo semplicemente sostituirlo con il Widget PositionedDirectional
PositionedDirectional class - widgets library - Dart API .
Conclusioni
Lavorare sull’internazionalizzazione della propria applicazione non vuol dire semplicemente cambiare le stringhe necessarie alla traduzione, ma richiede un approccio più completo e ragionato, Flutter si dimostra anche in questo caso abbastanza flessibile da riuscire a coprire la maggior parte dei casi d’uso con i quali possiamo trovarci faccia a faccia.
Bisogna porre particolare attenzione ai casi limite, durante i quali non specchiare l’interfaccia è fondamentale, un esempio potrebbe essere quello delle direzioni stradali, dove l’indicazione “a destra” deve necessariamente rimanere una freccia che indica nella direzione corretta!
Se volete conoscere altro su di me, seguitemi su Twitter