right-to-left (RTL) in flutter - layout

I was using Flutter more than a week, and wanted to create an Arabic (right-to-left) app.
I was reading Internationalizing Flutter Apps, but it didn't mention how to set the layout direction.
So, how to show right-to-left (RTL) layout in Flutter?

you have two choices :
1. force a locale ( and direction ) on all devices
-- method 1: with localization
add flutter_localizations package to your pubspec.yml
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
then
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
MaterialApp(
localizationsDelegates: [
GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
Locale("fa", "IR"), // OR Locale('ar', 'AE') OR Other RTL locales
],
locale: Locale("fa", "IR") // OR Locale('ar', 'AE') OR Other RTL locales,
.
.
.
);
-- method 2: without localization
MaterialApp(
.
.
.
builder: (context, child) {
return Directionality(
textDirection: TextDirection.rtl,
child: child,
);
},
.
.
.
);
2. set layout direction according to device locale
( if user phone locale is a RTL language and exist in supportedLocales, your app run in RTL mode, otherwise your app is LTR )
add flutter_localizations package to your pubspec.yml
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
then
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
MaterialApp(
localizationsDelegates: [
GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
Locale("en", "US"),
Locale("fa", "IR"), // OR Locale('ar', 'AE') OR Other RTL locales
],
.
.
.
);
note : rtl languages in flutter are:
[
'ar', // Arabic
'fa', // Farsi
'he', // Hebrew
'ps', // Pashto
'ur', // Urdu
];

The best and shortest way to set RTL configuration for the entire app.
void main() {
runApp(
MaterialApp(
home: Directionality( // add this
textDirection: TextDirection.rtl, // set this property
child: HomePage(),
),
),
);
}

You need to create a Builder and pass it the layout direction using TextDirection.rtl
new MaterialApp(
title: 'Flutter RTL',
color: Colors.grey,
builder: (BuildContext context, Widget child) {
return new Directionality(
textDirection: TextDirection.rtl,
child: new Builder(
builder: (BuildContext context) {
return new MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaleFactor: 1.0,
),
child: child,
);
},
),
);
},
.
.
.
);

If you need to display text in reverse direction then just set it's textdirection property to TextDirection.rtl.
Example code for TextField widget,
TextField(
textDirection: TextDirection.rtl,
decoration: InputDecoration(
labelText: "Enter Pashto Name",
),
),
Example code for Text widget,
Text(
"This text is in the other direction!"
textDirection: TextDirection.rtl,
),

Just append this to your material app:
builder: (BuildContext context, Widget child) {
return new Directionality(
textDirection: TextDirection.rtl,
child: new Builder(
builder: (BuildContext context) {
return new MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaleFactor: 1.0,
),
child: child,
);
},
),
);
},

if you use flutter_localizations:
sdk: flutter
add these line to change your app direction
supportedLocales: [
Locale("fa", "IR"),
Locale("en", 'US'),
],
locale: Locale("fa", "IR") // this is important line if not add this Apps will not change direction

GetMaterialApp( textDirection: TextDirection.rtl, home: SignUpScreen() // const HomeExpert() );

Related

How to make flutter animation play full-screen when modal bottom sheet has been raised?

I am trying to add a confetti animation to modal bottom sheet using confetti package when it is raised. But it is not working as intended - animation is being cut in the middle of the screen. It works as intended when I call the animation from button press. Desired result is like on button press, but should be when modal bottom sheet is raised.
I have tried wrapping ConfettiWidget inside Expanded, Positioned.fill, also Flexible, but these don't work.
EDIT:
Did some testing and it seems that the problem is present only on iOS devices. Also, it probably is worth mentioning that the animation is way slower on Android device (both physical and virtual) than it is on an iPhone.
See gifs below:
On Build:
On button press:
(How it should look on the build)
Code:
#override
void initState() {
confController = ConfettiController(duration: Duration(seconds: 5));
WidgetsBinding.instance!.addPostFrameCallback((_) {
confController.play();
});
super.initState();
}
#override
void dispose() {
confController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return Container(
color: Colors.black,
child: Stack(
children: [
Align(
alignment: Alignment.topCenter,
child: ConfettiWidget(
confettiController: confController,
blastDirectionality: BlastDirectionality.explosive,
particleDrag: 0.05,
emissionFrequency: 0.1,
gravity: 0.3,
colors: [
Colors.red,
], // manually specify the colors to be used
),
),
Container(
width: 500,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RawMaterialButton(
onPressed: () {
confController.play();
},
fillColor: Colors.white,
)
],
),
)
],
),
);
}
Needed to set the ConfettiWidget parameter canvas to MediaQuery.of(context).size * 2. Works as intended now (tested on both smaller and bigger devices (biggest was iPad 12.9-inch)). Code looks like this now:
ConfettiWidget(
confettiController: confController,
blastDirectionality: BlastDirectionality.explosive,
particleDrag: 0.05,
emissionFrequency: 0.1,
gravity: 0.3,
canvas: MediaQuery.of(context).size * 2,
colors: [
Colors.red,
],
)

How do I define RadioListTitles horizontally?

can you help me with my problem? My app have 2 RadioListTitle, they are located vertically, but I need to locate them horizontally. How to do it?
RadioListTile(
title: const Text('Мужской'),
value: GenderList.male,
groupValue: _gender,
onChanged: (GenderList value) {setState(() { _gender = value;});},
),
RadioListTile(
title: const Text('Женский'),
value: GenderList.female,
groupValue: _gender,
onChanged: (GenderList value) {setState(() { _gender = value;});},
),
Wrap it with Row and Expanded
Row(
children:[
Expanded(child: RadioListTile(...) ),
Expanded(child: RadioListTile(...) ),
],
)

Building my own drawer with ListView occurs tileWidth != leadingSize.width

I use ListView instead of Drawer and I want to make it collapsible, just like Dashboard style Drawer.
My solution is click a button, and setState the width of the SizedBox.
Somehow it spits out tileWidth != leadingSize.width
is there any solution to this error?
Widget _menu(bool isOpen) {
return SizedBox(
width: isOpen ? 250 : 0,
child: ListView(
children: [
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("MENU"),
ListTile(title:Text('item1')),
ListTile(title:Text('item2')),
],
),
],
),
);
}
Change ListTile to simple Text widget won't cause any issue.
I am making a project on flutter web.
You can try by this Container inside ListTile
ListTile(
leading: Container(
width: 64,
// ..
),
// ..
);

Unhandled Exception: MissingPluginException(No implementation found for method listenForCode on channel sms_autofill)

I'm working on a project and before merging the code with my teammates, package sms_autofill runs normally, but after the code got merged, I've already run flutter clean but it still shows two erros as below:
Unhandled Exception: MissingPluginException(No implementation found for method listenForCode on channel sms_autofill)
and
Unhandled Exception: MissingPluginException(No implementation found for method getAppSignature on channel sms_autofill)
My code:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:rentto_tenant/model/auth.dart';
import 'package:rentto_tenant/repository/auth_repository.dart';
import 'package:rentto_tenant/util/exception/ResponseException.dart';
import 'package:rentto_tenant/view/welcome/welcome.dart';
import 'package:rentto_tenant/view/home/home.dart';
import 'package:rentto_tenant/widget/loaders/color_loader_3.dart';
import 'package:rentto_tenant/widget/loaders/color_loader_4.dart';
import 'package:rentto_tenant/widget/loading_widget.dart';
import 'package:sms_autofill/sms_autofill.dart';
import 'package:pin_code_text_field/pin_code_text_field.dart';
import '../../constant/color.dart';
import '../../constant/dimen.dart';
class SMSVerificationPage extends StatefulWidget {
final String uuid;
final String phoneNumber;
final String password;
final String requestType;
const SMSVerificationPage(
{Key key, this.uuid, this.phoneNumber, this.password, this.requestType})
: super(key: key);
#override
_SMSVerificationPageState createState() => _SMSVerificationPageState();
}
class _SMSVerificationPageState extends State<SMSVerificationPage>
with CodeAutoFill {
TextEditingController pinCodeController = new TextEditingController();
TextEditingController autoFillCodeController = new TextEditingController();
_resendCode() async {
_loadingController.startLoading();
try {
String _uuid =
await AuthUserRepository.of(context).resendCode(widget.phoneNumber);
_loadingController.stopLoading();
setState(() {
_codeResent = true;
_codeExpiresInXMin = 5;
});
startTimer();
print(_uuid);
} on ResponseException catch (e) {
print(e.response.statusCode);
print(e.response.body);
} catch (e) {
print(e.toString());
} finally {
_loadingController.stopLoading();
}
}
_verifyCode() async {
_loadingController.startLoading();
try {
AuthUser auth = await AuthUserRepository.of(context).verifyUser(
widget.uuid,
pinCodeController.text,
widget.password,
widget.requestType);
// store Auth Tokens
print(auth.toJson());
// navigate
_loadingController.stopLoading();
if (widget.requestType == "reset_password") {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => HomePage()),
(route) => false);
} else {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => WelcomePage()),
(route) => false);
}
} on ResponseException catch (e) {
_codeErr = true;
print(e.response.statusCode);
print(e.response.body);
} catch (e) {
_codeErr = true;
print(e.toString());
throw (e);
} finally {
_loadingController.stopLoading();
}
}
String appSignature;
String otpCode;
bool _codeErr = false;
bool _codeResent = false;
Timer _timer;
int _codeExpiresInXMin = 5;
void startTimer() {
const oneMin = const Duration(minutes: 1);
_timer = new Timer.periodic(
oneMin,
(Timer timer) => setState(
() {
if (_codeExpiresInXMin < 1) {
timer.cancel();
} else {
_codeExpiresInXMin = _codeExpiresInXMin - 1;
}
},
),
);
}
#override
void codeUpdated() {
setState(() {
otpCode = code;
pinCodeController.text = code;
});
}
#override
void initState() {
startTimer();
listenForCode();
SmsAutoFill().getAppSignature.then((signature) {
setState(() {
appSignature = signature;
});
});
super.initState();
}
#override
void dispose() {
_timer.cancel();
cancel();
super.dispose();
}
final _loadingController = LoadingController();
#override
Widget build(BuildContext context) {
return LoadingWidget(
controller: _loadingController,
child: Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(top: 15.0, bottom: 8.0),
child: Image(
image: AssetImage(
"assets/images/Logo.png",
),
width: 93,
height: 110,
),
),
Container(
margin: EdgeInsets.only(bottom: 30),
child: Text(
"RENTTO",
style: Theme.of(context).textTheme.headline4.copyWith(
color: AppColors.genericColor,
),
textAlign: TextAlign.center,
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
"Enter Verifcation code",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline5,
),
),
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Text(
"If you're having any issue, contact to RENTTO",
textAlign: TextAlign.center,
),
),
Padding(
padding: const EdgeInsets.only(top: 40, bottom: 25),
child: PinCodeTextField(
controller: pinCodeController,
maxLength: 6,
pinBoxWidth: 50,
pinBoxHeight: 50,
pinBoxRadius: 10,
pinBoxBorderWidth: 1,
autofocus: true,
highlight: true,
highlightColor: AppColors.genericColor,
hasError: _codeErr,
errorBorderColor: Colors.red,
pinTextStyle: TextStyle(
color: AppColors.genericColor,
fontSize: 25,
fontWeight: FontWeight.bold),
keyboardType: TextInputType.number,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: _codeResent
? Text(
'OTP Code has been resent! Please fill in the code in ' +
_codeExpiresInXMin.toString() +
' minutes.',
style: TextStyle(
fontSize: 14,
color: AppColors.genericColor,
),
textAlign: TextAlign.center,
)
: Text(
'OTP Code has been sent! Please check your message and fill in the code in ' +
_codeExpiresInXMin.toString() +
' minutes.',
style: TextStyle(
fontSize: 14,
color: AppColors.genericColor,
),
textAlign: TextAlign.center,
),
),
FlatButton(
onPressed: () {
setState(() {
_loadingController.startLoading();
});
_resendCode();
},
child: Text("Resend Code",
style: TextStyle(
fontSize: 17,
color: AppColors.genericColor,
fontWeight: FontWeight.w600)),
),
Padding(
padding: const EdgeInsets.only(top: 30.0, bottom: 30.0),
child: RaisedButton(
padding: EdgeInsets.symmetric(
horizontal: 120, vertical: 15),
onPressed: () {
setState(() {
_loadingController.startLoading();
});
_verifyCode();
},
child: Text(
"CONTINUE",
style: TextStyle(
fontSize: AppDimens.btnTextSize,
),
),
color: AppColors.primaryColors,
),
)
],
),
),
),
),
),
);
}
}
flutter doctor -v:
[✓] Flutter (Channel master, 1.21.0-6.0.pre.3, on Linux, locale en_US.UTF-8)
• Flutter version 1.21.0-6.0.pre.3 at /home/veasnawt/Flutter/flutter
• Framework revision ddb8e6e3bf (24 hours ago), 2020-07-22 20:00:07 -0700
• Engine revision dcc9a4048d
• Dart version 2.9.0 (build 2.9.0-21.0.dev 9dca49e71e)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
• Android SDK at /home/veasnawt/Android/Sdk
• Platform android-30, build-tools 29.0.3
• Java binary at: /snap/android-studio/90/android-studio/jre/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
• All Android licenses accepted.
[✓] Chrome - develop for the web
• Chrome at google-chrome
[✓] Linux toolchain - develop for Linux desktop
• clang version 10.0.0-4ubuntu1
• cmake version 3.16.3
• ninja version 1.10.0
• pkg-config version 0.29.1
[✓] Android Studio (version 3.6)
• Android Studio at /snap/android-studio/88/android-studio
• Flutter plugin version 44.0.2
• Dart plugin version 192.7761
• Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b4-5784211)
[✓] Android Studio (version 4.0)
• Android Studio at /snap/android-studio/90/android-studio
• Flutter plugin version 47.0.2
• Dart plugin version 193.7361
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
[✓] Connected device (4 available)
• AOSP on IA Emulator (mobile) • emulator-5554 • android-x86 • Android 9 (API 28) (emulator)
• Linux (desktop) • linux • linux-x64 • Linux
• Web Server (web) • web-server • web-javascript • Flutter Tools
• Chrome (web) • chrome • web-javascript • Google Chrome 81.0.4044.129
• No issues found!
pubspec.yaml:
name: rentto_tenant
description: A new Flutter project.
# The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages.
publish_to: "none" # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
flutter_i18n: ^0.18.0
json_annotation: ^3.0.1
http: ^0.12.2
provider: ^4.3.1
flutter_dotenv: ^2.1.0
pin_code_text_field: ^1.2.1
sms_autofill: ^1.2.1
font_awesome_flutter: ^8.8.1
flutter_facebook_login: ^3.0.0
intro_slider: ^2.3.1
fluttertoast: ^7.0.1
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.3
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^1.10.0
json_serializable: ^3.3.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- .env
- assets/images/
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
I don't know what's wrong with it, I've tried searching on the internet and it seems there is no solution related to it. enter code here
Finally, I know what the problem is.
The package sms_autofill itself is not the cause of the problem, the problem is that the package flutter_facebook_login was installed and being unused. Remove or use it properly will solve the problem.

I have a problem adding an image to a flutter project

I am experimenting with a flutter web project (might not make a difference but worth mentioning), i want to add an image but i get an error every time i try,
I have added the right assets to the pubspec.yaml file and the files are in the folder.
i have tried restarting my ide, and flutter clean.
There was no change at all.
class _homePageState extends State<homePage> {
#override
Widget build(BuildContext context) {
var textStyle = TextStyle(
color: Colors.black,
fontSize: 30,
fontWeight: FontWeight.w100,
);
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
fontFamily: "MontSerrat"
),
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.grey[400],
title: Text("Example",
style: TextStyle(
color: Colors.black,
fontSize: 40,
fontWeight: FontWeight.w100,
),
)
),
body:
Container(
color: Colors.grey[400],
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset('assets/images/first_image.jpg')
],
),
)
),
);
}
}
the pubspec.yaml looks like:
name: epq_webapp
description: An app built using Flutter for web
environment:
# You must be using Flutter >=1.5.0 or Dart >=2.3.0
sdk: '>=2.3.0-dev.0.1 <3.0.0'
dependencies:
flutter_web: any
flutter_web_ui: any
dev_dependencies:
build_runner: ^1.4.0
build_web_compilers: ^2.0.0
pedantic: ^1.0.0
dependency_overrides:
flutter_web:
git:
url: https://github.com/flutter/flutter_web
path: packages/flutter_web
flutter_web_ui:
git:
url: https://github.com/flutter/flutter_web
path: packages/flutter_web_ui
flutter:
fonts:
- family: MontSerrat
fonts:
- asset: assets\fonts\montserrat\Montserrat-Regular.ttf
assets:
- assets/
- assets/images/first_image.jpg
i expect my code to display an image, however i get an error message,
Unable to load asset: assets/images/first_image.jpg
Flutter uses the pubspec.yaml file, located at the root of your project, to identify assets required by an app.
flutter:
assets:
- assets/my_icon.png
- assets/background.png
make sure you have your image in the assets directory
then
Widget build(BuildContext context) {
// ...
return DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/background.png'),
// ...
),
// ...
),
);
//
}
You should get your image rendered
update your pubspec.yaml with this
`
fonts:
- family: MontSerrat
fonts:
- asset: assets\fonts\montserrat\Montserrat-Regular.ttf
uses-material-design: true <--- line added ---
assets:
- assets/
- assets/images/first_image.jpg
you could also check this it might help you out
I solved my problem by putting the assets under the web folder instead of the root of the project. then used
Image.asset(filename)
to display them.
Pubspec.yaml should be like:
flutter:
uses-material-design: true
assets:
- assets/images/
Code Snippet:
Center(
child: Image.asset(
'assets/images/account.png',
width: heartbeatAnimation.value,
height: heartbeatAnimation.value,
),
)
Output:

Resources