0Pricing
Flutter Mobile Development · บทเรียน

เลย์เอาต์ RTL และการจัดการทิศทาง

สร้างเลย์เอาต์ที่กลับด้านได้ถูกต้องสำหรับภาษาจากขวาไปซ้ายด้วย Directionality

เลย์เอาต์ RTL และการจัดการทิศทาง เป็นบทเรียน Flutter Mobile Development ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Flutter Mobile Development และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Flutter Mobile Development มีบทเรียนทั้งหมด 4 บทเรียน

บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ

Why RTL Matters

Languages like Arabic, Hebrew, Persian, and Urdu read right-to-left (RTL). A UI built only for left-to-right (LTR) feels broken to those users: back arrows point the wrong way, text aligns to the wrong edge, and rows appear mirrored.

  • Goal: the entire layout should mirror when the locale is RTL.
  • Flutter handles most of this automatically through a concept called directionality.
  • Your job is to write direction-aware code instead of hard-coding left and right.

In this lesson you will learn how Flutter resolves direction and how to keep your widgets mirroring correctly.

The TextDirection Enum

At the core of RTL support is the TextDirection enum from dart:ui. It has exactly two values: ltr and rtl.

  • Every text-rendering and direction-aware widget needs a TextDirection to lay out.
  • In a real app it is normally derived from the device locale, but it is just a plain enum you can reason about in pure Dart.

Here is a tiny pure-Dart model that mirrors how Flutter picks a start edge from a direction.

enum TextDirection { ltr, rtl }

String startEdge(TextDirection dir) {
  return dir == TextDirection.rtl ? 'right' : 'left';
}

String endEdge(TextDirection dir) {
  return dir == TextDirection.rtl ? 'left' : 'right';
}

void main() {
  for (final dir in TextDirection.values) {
    print('$dir -> start=${startEdge(dir)}, end=${endEdge(dir)}');
  }
}

The Directionality Widget

In Flutter, the ambient text direction is provided by the Directionality widget. It sits high in the tree (usually inside MaterialApp) and exposes a direction to all descendants.

  • Widgets read it with Directionality.of(context).
  • MaterialApp automatically wraps your app in a Directionality based on the current locale.
  • You rarely create one yourself, except in tests or to force a subtree's direction.

Forcing a subtree to RTL is as simple as wrapping it.

Widget buildArabicSection() {
  return Directionality(
    textDirection: TextDirection.rtl,
    child: Row(
      children: const [
        Icon(Icons.star),
        SizedBox(width: 8),
        Text('مرحبا'),
      ],
    ),
  );
}

Start and End, Not Left and Right

The single most important rule for RTL-safe layouts: think in start/end, not left/right.

  • start = leading edge (left in LTR, right in RTL)
  • end = trailing edge (right in LTR, left in RTL)

Flutter gives you direction-aware versions of common APIs that resolve automatically:

  • EdgeInsetsDirectional instead of EdgeInsets
  • AlignmentDirectional instead of Alignment
  • BorderRadiusDirectional instead of BorderRadius

If you use these, your padding and alignment flip automatically when the direction changes.

Widget buildCard() {
  return Container(
    // 16 on the start edge mirrors to the right in RTL automatically
    padding: const EdgeInsetsDirectional.only(
      start: 16,
      end: 8,
      top: 12,
      bottom: 12,
    ),
    alignment: AlignmentDirectional.centerStart,
    child: const Text('Direction-aware padding'),
  );
}

Resolving Directional Insets in Pure Dart

To build intuition, here is how a directional inset resolves to physical left/right depending on direction. Flutter does this internally; modeling it in plain Dart makes the rule concrete.

  • In LTR: start -> left, end -> right.
  • In RTL: start -> right, end -> left.

Run this to see the same logical insets produce mirrored physical insets.

enum TextDirection { ltr, rtl }

class DirectionalInsets {
  final double start;
  final double end;
  const DirectionalInsets(this.start, this.end);

  Map<String, double> resolve(TextDirection dir) {
    if (dir == TextDirection.rtl) {
      return {'left': end, 'right': start};
    }
    return {'left': start, 'right': end};
  }
}

void main() {
  const insets = DirectionalInsets(16, 4);
  print('LTR: ${insets.resolve(TextDirection.ltr)}');
  print('RTL: ${insets.resolve(TextDirection.rtl)}');
}

Rows Mirror Automatically

A plain Row is already direction-aware. Its children are laid out from start to end, so the visual order flips in RTL without any extra code.

  • In LTR a Row of [A, B, C] shows A on the left.
  • In RTL the same Row shows A on the right.

This is why you should let widgets like Row, ListTile, and AppBar do the mirroring for you instead of manually positioning children.

Below, the leading icon and trailing chevron of a ListTile swap sides automatically.

Widget buildSettingsTile() {
  return const ListTile(
    leading: Icon(Icons.person),     // start edge
    title: Text('Profile'),
    trailing: Icon(Icons.chevron_right), // end edge
  );
}

Direction-Aware Icons

Some icons are inherently directional: back arrows, chevrons, and the send arrow should point toward the end of the reading direction.

  • Material provides mirrored variants, e.g. Icons.arrow_back has Icons.arrow_back_ios and the auto-mirroring Icons.arrow_back behaves well in BackButton.
  • For custom directional icons, wrap them so they flip in RTL using Transform.flip based on the resolved direction.

Reading the ambient direction lets you decide whether to mirror.

Widget buildSendIcon(BuildContext context) {
  final isRtl = Directionality.of(context) == TextDirection.rtl;
  return Transform(
    alignment: Alignment.center,
    transform: isRtl
        ? Matrix4.rotationY(3.1415926) // flip horizontally
        : Matrix4.identity(),
    child: const Icon(Icons.send),
  );
}

Text Alignment Follows Direction

For text, prefer TextAlign.start and TextAlign.end over TextAlign.left and TextAlign.right.

  • TextAlign.start aligns to the left in LTR and to the right in RTL.
  • A single mixed-direction string (Arabic with embedded English) is handled by the text engine's bidi algorithm, but the paragraph's base direction comes from the ambient Directionality.

Using start means your form labels and body text align to the correct edge in every locale.

Widget buildLabel() {
  return const Text(
    'Email address',
    textAlign: TextAlign.start, // mirrors with direction
    style: TextStyle(fontSize: 16),
  );
}

Testing Both Directions

The cleanest way to verify mirroring is to render the same subtree twice under each direction. Wrapping a widget in Directionality overrides the ambient value for that subtree only.

  • Great for widget tests and for a debug preview screen.
  • You can also flip the whole app by setting locale to an RTL locale like Locale('ar').

This helper builds an RTL preview of any child.

Widget rtlPreview(Widget child) {
  return Directionality(
    textDirection: TextDirection.rtl,
    child: child,
  );
}

Widget buildPreviewRow(Widget child) {
  return Row(
    children: [
      Expanded(child: child),                 // ambient direction
      Expanded(child: rtlPreview(child)),     // forced RTL
    ],
  );
}

Common RTL Mistakes

Most RTL bugs come from hard-coded sides. Watch for these:

  • EdgeInsets.only(left: 16) stays on the left even in RTL. Use EdgeInsetsDirectional.only(start: 16).
  • Alignment.centerLeft does not flip. Use AlignmentDirectional.centerStart.
  • Positioned(left: 0) in a Stack does not mirror. Use PositionedDirectional(start: 0).
  • Hard-coded TextAlign.left for body text.

Rule of thumb: if an API has a Directional sibling, prefer it.

// Mirrors correctly in RTL:
Widget buildBadge() {
  return Stack(
    children: const [
      Placeholder(),
      PositionedDirectional(
        top: 4,
        start: 4, // right side in RTL
        child: Icon(Icons.new_releases),
      ),
    ],
  );
}

Reading Direction in Logic

Sometimes your business logic needs the direction too, for example to choose a swipe gesture or an animation slide offset. Read it once and branch on a clean enum.

  • Compute a sign: +1 for LTR, -1 for RTL, then multiply offsets.
  • Keep this logic pure so it is easy to unit test.

This pure-Dart helper shows the pattern you would call with the resolved direction from Directionality.of(context).

enum TextDirection { ltr, rtl }

double slideOffset(TextDirection dir, double distance) {
  final sign = dir == TextDirection.rtl ? -1.0 : 1.0;
  return sign * distance;
}

void main() {
  const distance = 120.0;
  print('LTR slide: ${slideOffset(TextDirection.ltr, distance)}');
  print('RTL slide: ${slideOffset(TextDirection.rtl, distance)}');
}

Quick Check

You need a left padding in LTR that becomes right padding in RTL, automatically.

Recap

You learned how Flutter handles right-to-left layouts:

  • TextDirection (ltr/rtl) drives everything; Directionality provides it to the tree, and Directionality.of(context) reads it.
  • Think in start/end, not left/right. Prefer EdgeInsetsDirectional, AlignmentDirectional, BorderRadiusDirectional, and PositionedDirectional.
  • Row, ListTile, and most Material widgets mirror automatically; let them.
  • Use TextAlign.start for text, and mirror inherently directional custom icons.
  • Verify by wrapping subtrees in a forced Directionality or running under an RTL locale like Locale('ar').

Avoid hard-coded sides and your UI will feel native to RTL users with almost no extra work.

คำถามที่พบบ่อย

บทเรียน “เลย์เอาต์ RTL และการจัดการทิศทาง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “เลย์เอาต์ RTL และการจัดการทิศทาง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Flutter Mobile Development ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Flutter Mobile Development มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “เลย์เอาต์ RTL และการจัดการทิศทาง”

สร้างเลย์เอาต์ที่กลับด้านได้ถูกต้องสำหรับภาษาจากขวาไปซ้ายด้วย Directionality คุณปฏิบัติ Flutter Mobile Development ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Flutter Mobile Development หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Flutter Mobile Development บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “เลย์เอาต์ RTL และการจัดการทิศทาง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Flutter Mobile Development นี้ได้ไหม

ได้ บทเรียน Flutter Mobile Development ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ไฟล์ ARB และกระบวนการแปลภาษาด้วย gen_l10n
  2. พหูพจน์ เพศ และการจัดรูปแบบข้อความ ICU
  3. เลย์เอาต์ RTL และการจัดการทิศทาง
  4. ความหมาย ตัวอ่านหน้าจอ และวิดเจ็ตที่เข้าถึงได้
← กลับไปที่ Flutter Mobile Development