© Khmer Angkor Academy - sophearithput168

Flutter Widgets

Flutter Widgets សំខាន់ៗ

Widgets គឺជា building blocks នៃ Flutter UI។ ក្នុង Flutter គ្រប់យ៉ាងជា Widget - ចាប់ពី buttons, text, icons រហូតដល់ layouts, themes, និង animations។

📘 Widget Theory

Widget Lifecycle & Rendering

នៅពេលអ្នកបង្កើត widget Flutter ធ្វើការតាមជំហានទាំងនេះ:

1. Widget (Configuration)
   - Immutable description of UI
   - Contains properties (color, size, etc.)
   
2. Element (Instance)
   - Manages widget lifecycle
   - Links widget to RenderObject
   - Tracks state changes
   
3. RenderObject (Rendering)
   - Performs layout calculation
   - Paints pixels on screen
   - Handles hit testing

Widget Tree vs Element Tree vs Render Tree

Widget Tree          Element Tree         Render Tree
    Text                StatelessElement     RenderParagraph
    │                         │                     │
Container           ContainerElement      RenderDecoratedBox
    │                         │                     │
  Column              ColumnElement         RenderFlex

🎨 Widget Types

1. Stateless Widgets (មិនផ្លាស់ប្តូរ)

  • Immutable - properties cannot change
  • UI does not change over time
  • Better performance (no state tracking)
  • Examples: Text, Icon, Image

2. Stateful Widgets (អាចផ្លាស់ប្តូរ)

  • Mutable state that can change
  • UI rebuilds when setState() is called
  • Examples: Checkbox, TextField, AnimatedContainer

3. Inherited Widgets (ចែករំលែក data)

  • Share data down the widget tree
  • Efficient propagation of changes
  • Examples: Theme, MediaQuery, Provider

📋 Widget Categories

ប្រភេទ ឧទាហរណ៍ មុខងារ
Layout Container, Row, Column, Stack រៀបចំ widgets
Text Text, RichText, SelectableText បង្ហាញអត្ថបទ
Input TextField, Checkbox, Radio, Switch ទទួលយក input
Button ElevatedButton, TextButton, IconButton ប៊ូតុង
Display Image, Icon, CircleAvatar បង្ហាញមាតិកា
List ListView, GridView, ListTile បញ្ជី
Dialog AlertDialog, BottomSheet, SnackBar បង្ហាញសារ

📝 TextField Widget

TextField(
  decoration: InputDecoration(
    labelText: 'ឈ្មោះ',
    hintText: 'បញ្ចូលឈ្មោះរបស់អ្នក',
    prefixIcon: Icon(Icons.person),
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(12),
    ),
    filled: true,
    fillColor: Colors.grey[200],
  ),
  keyboardType: TextInputType.text,
  maxLength: 50,
  onChanged: (value) {
    print('Input: $value');
  },
  onSubmitted: (value) {
    print('Submitted: $value');
  },
)

✅ Checkbox, Radio, Switch

class FormExample extends StatefulWidget {
  @override
  _FormExampleState createState() => _FormExampleState();
}

class _FormExampleState extends State<FormExample> {
  bool isChecked = false;
  int selectedRadio = 1;
  bool isSwitched = false;
  
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // Checkbox
        CheckboxListTile(
          title: Text('យល់ព្រមលើកិច្ចព្រមព្រៀង'),
          value: isChecked,
          onChanged: (value) {
            setState(() {
              isChecked = value ?? false;
            });
          },
        ),
        
        // Radio Buttons
        RadioListTile(
          title: Text('ប្រុស'),
          value: 1,
          groupValue: selectedRadio,
          onChanged: (value) {
            setState(() {
              selectedRadio = value ?? 1;
            });
          },
        ),
        RadioListTile(
          title: Text('ស្រី'),
          value: 2,
          groupValue: selectedRadio,
          onChanged: (value) {
            setState(() {
              selectedRadio = value ?? 2;
            });
          },
        ),
        
        // Switch
        SwitchListTile(
          title: Text('បើក Notifications'),
          value: isSwitched,
          onChanged: (value) {
            setState(() {
              isSwitched = value;
            });
          },
        ),
      ],
    );
  }
}

📜 ListView Widget

Basic ListView

ListView(
  padding: EdgeInsets.all(16),
  children: [
    Text('Item 1'),
    Text('Item 2'),
    Text('Item 3'),
  ],
)

ListView.builder (សម្រាប់ list ធំ)

class ItemListPage extends StatelessWidget {
  final List<String> items = List.generate(100, (index) => 'Item ' + (index + 1).toString());
  
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        return ListTile(
          leading: CircleAvatar(
            child: Text((index + 1).toString()),
          ),
          title: Text(items[index]),
          subtitle: Text('Description'),
          trailing: Icon(Icons.arrow_forward_ios),
          onTap: () {
            print('Tapped: ' + items[index]);
          },
        );
      },
    );
  }
}

ListView.separated

ListView.separated(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(items[index]),
    );
  },
  separatorBuilder: (context, index) {
    return Divider(thickness: 1);
  },
)

🔲 GridView Widget

GridView.count(
  crossAxisCount: 2,  // ចំនួន columns
  crossAxisSpacing: 10,
  mainAxisSpacing: 10,
  padding: EdgeInsets.all(16),
  children: List.generate(10, (index) {
    return Container(
      decoration: BoxDecoration(
        color: Colors.blue[100],
        borderRadius: BorderRadius.circular(12),
      ),
      child: Center(
        child: Text(
          'Item ' + (index + 1).toString(),
          style: TextStyle(fontSize: 18),
        ),
      ),
    );
  }),
)

🔔 Dialog Widgets

AlertDialog

void showAlertDialog(BuildContext context) {
  showDialog(
    context: context,
    builder: (context) {
      return AlertDialog(
        title: Text('បញ្ជាក់'),
        content: Text('តើអ្នកពិតជាចង់លុបមែនទេ?'),
        actions: [
          TextButton(
            onPressed: () {
              Navigator.pop(context);
            },
            child: Text('បោះបង់'),
          ),
          ElevatedButton(
            onPressed: () {
              // Perform delete
              Navigator.pop(context);
            },
            child: Text('លុប'),
            style: ElevatedButton.styleFrom(
              backgroundColor: Colors.red,
            ),
          ),
        ],
      );
    },
  );
}

SnackBar

void showSnackBar(BuildContext context) {
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(
      content: Text('រក្សាទុកបានជោគជ័យ'),
      duration: Duration(seconds: 2),
      action: SnackBarAction(
        label: 'មិនធ្វើវិញ',
        onPressed: () {
          // Undo action
        },
      ),
    ),
  );
}

BottomSheet

void showBottomSheet(BuildContext context) {
  showModalBottomSheet(
    context: context,
    builder: (context) {
      return Container(
        padding: EdgeInsets.all(20),
        height: 200,
        child: Column(
          children: [
            Text(
              'ជ្រើសរើសជម្រើស',
              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 20),
            ListTile(
              leading: Icon(Icons.share),
              title: Text('ចែករំលែក'),
              onTap: () {
                Navigator.pop(context);
              },
            ),
            ListTile(
              leading: Icon(Icons.edit),
              title: Text('កែ'),
              onTap: () {
                Navigator.pop(context);
              },
            ),
          ],
        ),
      );
    },
  );
}

🖼️ Card Widget

Card(
  elevation: 4,
  margin: EdgeInsets.all(16),
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(12),
  ),
  child: Padding(
    padding: EdgeInsets.all(16),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            CircleAvatar(
              backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
            ),
            SizedBox(width: 12),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'សុខា',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
                Text(
                  '2 hours ago',
                  style: TextStyle(color: Colors.grey, fontSize: 12),
                ),
              ],
            ),
          ],
        ),
        SizedBox(height: 12),
        Text('នេះជាមាតិកានៃ Card widget។'),
        SizedBox(height: 12),
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            TextButton.icon(
              icon: Icon(Icons.thumb_up_outlined),
              label: Text('Like'),
              onPressed: () {},
            ),
            TextButton.icon(
              icon: Icon(Icons.comment_outlined),
              label: Text('Comment'),
              onPressed: () {},
            ),
            TextButton.icon(
              icon: Icon(Icons.share_outlined),
              label: Text('Share'),
              onPressed: () {},
            ),
          ],
        ),
      ],
    ),
  ),
)

⏳ CircularProgressIndicator

// Loading indicator
CircularProgressIndicator()

// With custom color and size
SizedBox(
  width: 50,
  height: 50,
  child: CircularProgressIndicator(
    valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
    strokeWidth: 6,
  ),
)

// Linear progress indicator
LinearProgressIndicator(
  value: 0.7,  // 70% complete
  backgroundColor: Colors.grey[300],
  valueColor: AlwaysStoppedAnimation<Color>(Colors.green),
)

💡 ជំនួយ: ពិនិត្យមើល Flutter widget catalog នៅ docs.flutter.dev/ui/widgets សម្រាប់ widgets ទាំងអស់។