auto text direction (based on the entered text) in flutter text and text field widgets

Viewed 2180

I'm make a multi language application in flutter (ar/en), so i want to display my content in these languages, my problem is the text direction is based on the ui language, i want to change the direction dynamically based on the content if ar should be rtl, other wise ltr.

My current view My current view

desired effect desired effect

class ArticleCard extends StatelessWidget {
  const ArticleCard({
    Key key,
    @required this.article,
    @required this.isAuthor,
    @required this.onDelete,
    @required this.onEdit,
    this.allowComments = true,
  }) : super(key: key);
  final ArticleModel article;
  final bool isAuthor;
  final bool allowComments;
  final VoidCallback onDelete;
  final VoidCallback onEdit;

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: EdgeInsets.only(bottom: 10),
      child: Column(
        children: <Widget>[
          InkWell(
            onTap: () {
              ExtendedNavigator.ofRouter<Router>().pushNamed(
                Routes.article,
                arguments: ArticleScreenArguments(article: article),
              );
            },
            child: Column(
              children: <Widget>[
                ListTile(
                  leading: CircleAvatar(
                    backgroundImage:
                        CachedNetworkImageProvider(article.owner.avatar),
                  ),
                  title: Text(article.title),
                  subtitle: Text(
                    article.owner.name,
                    textScaleFactor: .75,
                  ),
                  trailing: Text(
                    '${DateFormat('d, MMMM y  h:mm a', 'ar').format(article.createdAt)}',
                    textScaleFactor: .7,
                  ),
                ),
                SizedBox(
                  width: MediaQuery.of(context).size.width,
                  child: Padding(
                    padding: EdgeInsets.symmetric(horizontal: 8),
                    child: Text(
                      article.content,
                      textAlign: TextAlign.start,
                    ),
                  ),
                ),
              ],
            ),
          ),
          SizedBox(height: 10),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              FavoriteButton(
                isFavorite: article.isFavorite,
                count: article.favoriteCount,
                type: FavoriteType.article,
                targetId: article.id,
              ),
              _buildLabeledIcon(
                icon: Icon(Icons.message),
                label: '${article.commentsCount}',
              ),
              _buildLabeledIcon(
                icon: Icon(Icons.share),
                label: '${article.shares}',
              ),
              _buildLabeledIcon(
                icon: Icon(Icons.remove_red_eye),
                label: '${article.views}',
              ),
            ],
          ),
          SizedBox(height: 10),
          Container(
            height: 1.5,
            color: Colors.black12,
          ),
          if (isAuthor)
            _buildAuthorRow(),
          // Divider(),
          if (allowComments) ...[
            SizedBox(height: 10),
            _buildCommentsSection(context),
          ]
        ],
      ),
    );
  }

  Row _buildAuthorRow() {
    return Row(
      children: <Widget>[
        Expanded(
          child: InkWell(
            onTap: onEdit,
            child: Container(
              height: 50,
              alignment: Alignment.center,
              child: Text(
                'تعديل',
                style: TextStyle(
                  color: appTheme.accentColor,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ),
        Container(
          width: 1.5,
          height: 50,
          color: Colors.black12,
        ),
        Expanded(
          child: InkWell(
            onTap: onDelete,
            child: Container(
              height: 50,
              alignment: Alignment.center,
              child: Text(
                'حذف',
                style: TextStyle(
                  color: appTheme.errorColor,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ),
      ],
    );
  }

  Row _buildLabeledIcon({Widget icon, String label}) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: <Widget>[
        icon,
        SizedBox(width: 5),
        Text(
          label,
          textScaleFactor: .75,
        ),
      ],
    );
  }

  Widget _buildCommentsSection(BuildContext context) {
    return Column(
      children: [
        if (article.comments.isNotEmpty)
          CommentTile(comment: article.comments.first),
        _buildCommentTextInput(context),
      ],
    );
  }

  Widget _buildCommentTextInput(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Row(
        children: <Widget>[
          IconButton(
            icon: Icon(FontAwesomeIcons.paperPlane),
            onPressed: () {},
          ),
          Flexible(
            child: TextField(
              decoration: InputDecoration(
                hintText: 'كتابة تعليق',
                filled: true,
                fillColor: Color(0xFFEFEFEF),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(Radius.circular(50)),
                  borderSide: BorderSide.none,
                ),
                contentPadding: EdgeInsets.all(12),
              ),
              onSubmitted: (_) {},
              onTap: () {},
            ),
          ),
        ],
      ),
    );
  }
}

class CommentTile extends StatelessWidget {
  final CommentModel comment;

  const CommentTile({Key key, this.comment}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        ListTile(
          leading: CircleAvatar(
            backgroundImage: CachedNetworkImageProvider(comment.user.avatar),
          ),
          title: Text(comment.user.name),
          subtitle: Text(
            DateFormat.yMEd().format(comment.createdAt),
            textScaleFactor: .75,
          ),
        ),
        SizedBox(
          width: MediaQuery.of(context).size.width,
          child: Padding(
            padding: EdgeInsets.symmetric(horizontal: 8),
            child: Text(
              comment.text,
              textAlign: TextAlign.end,
            ),
          ),
        ),
      ],
    );
  }
}
2 Answers

You must add intl package to your project, and use this code as AppTextField whole of your app:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl;

class AppTextField extends StatefulWidget {
  final int maxLines;
  final String title;
  final TextInputType? textInput;
  final bool autoFocus;
  final TextInputAction inputAction;

  AppTextField(this.title,
      {this.maxLines: 1,
      this.textInput,
      this.autoFocus: false,
      this.inputAction: TextInputAction.next});

  @override
  State<StatefulWidget> createState() => AppTextFieldSate();
}

class AppTextFieldSate extends State<AppTextField> {
  String? text = '';

  bool isRTL(String text) {
    return intl.Bidi.detectRtlDirectionality(text);
  }

  @override
  Widget build(BuildContext context) => Container(
      margin: EdgeInsets.symmetric(vertical: 10),
      child: TextField(
          textDirection: isRTL(text!) ? TextDirection.rtl : TextDirection.ltr,
          textInputAction: widget.inputAction,
          keyboardType: widget.textInput,
          autofocus: widget.autoFocus,
          maxLines: widget.maxLines,
          decoration: InputDecoration(
            labelText: widget.title,
          ),
          onChanged: (value) {
            setState(() {
              text = value;
            });
          }));
}

I hope it is useful :)

  • If you have no way of detecting the current language the user of the app is using, you can try the firebase ml lnaguage detection kit which will help you detect the language of the post

  • With that based on the detected language you set the textAlign property of the Text widget to TextAlign.left or TextAlign.right

i.e

Text("$content", textAlign: lang=='ar'?TextAlign.right:TextAlign.left )
Related