Maak een Aangepaste Flutter Widget Bibliotheek voor Herbruikbare UI Componenten
description
Met deze prompt kun je een schaalbare en onderhoudbare Flutter widget bibliotheek creëren die ontwerpconsistentie en herbruikbaarheid over meerdere projecten afdwingt. Het helpt bij het aanpakken van uitdagingen in UI-standaardisatie en ontwikkelings-efficiëntie door je te begeleiden bij best practices in widgetontwerp, thematisering en documentatie. In tegenstelling tot algemene Flutter tutorials richt deze prompt zich op het bouwen van een gecentraliseerde componentbibliotheek die is afgestemd op jouw unieke ontwerpbehoeften, waardoor je tijd bespaart in toekomstige projecten.
prompt
Help me een aangepaste Flutter widget bibliotheek te maken die herbruikbare UI-componenten bevat voor mijn projecten. Ik wil widgets opnemen zoals <lijst met belangrijke widgets of componenttypes> die voldoen aan mijn ontwerp systeem richtlijnen: <beschrijf ...
try_prompt
generate_helper
disclaimerOnPageApi
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een overzicht en een voorbeeld van hoe je een aangepaste Flutter widget bibliotheek kunt structureren, inclusief voorbeelden voor knoppen, tekstinvoer en navigatiebalken, die voldoen aan jouw ontwerp systeem.
---
### 1. Structuur van de bibliotheek
**Projectstructuur:**
```
my_ui_library/
├── lib/
│ ├── src/
│ │ ├── buttons.dart
│ │ ├── input_fields.dart
│ │ ├── navigation_bars.dart
│ │ ├── themes.dart
│ │ └── widgets.dart
│ └── my_ui_library.dart
├── pubspec.yaml
└── README.md
```
**Uitleg:**
- `my_ui_library.dart`: Exporteert alle componenten.
- `src/`: Bevat de implementatiebestanden.
- `themes.dart`: Beheert de thematische styling en kleuren.
---
### 2. Thematische ondersteuning
Gebruik een `ThemeData`-extensie of een eigen `AppTheme` class om consistente kleuren en stijl te garanderen:
```dart
// lib/src/themes.dart
import 'package:flutter/material.dart';
class AppColors {
static const Color primaryBlue = Color(0xFF1565C0); // primaire blauwe kleur
static const Color background = Colors.white;
static const Color text = Colors.black87;
}
class AppTheme {
static ThemeData get theme {
return ThemeData(
primaryColor: AppColors.primaryBlue,
colorScheme: ColorScheme.fromSwatch(
primarySwatch: Colors.blue,
).copyWith(
primary: AppColors.primaryBlue,
),
buttonTheme: ButtonThemeData(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), // afgeronde hoeken
),
buttonColor: AppColors.primaryBlue,
textTheme: ButtonTextTheme.primary,
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
),
);
}
}
```
---
### 3. Reusable widgets maken
#### a) Button (Knop)
```dart
// lib/src/buttons.dart
import 'package:flutter/material.dart';
import 'themes.dart';
class CustomButton extends StatelessWidget {
final String label;
final VoidCallback onPressed;
const CustomButton({
Key? key,
required this.label,
required this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
primary: AppColors.primaryBlue,
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
onPressed: onPressed,
child: Text(label, style: TextStyle(color: Colors.white)),
);
}
}
```
#### b) Tekstinvoer
```dart
// lib/src/input_fields.dart
import 'package:flutter/material.dart';
class CustomTextField extends StatelessWidget {
final String hintText;
final TextEditingController controller;
const CustomTextField({
Key? key,
required this.hintText,
required this.controller,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextField(
controller: controller,
decoration: InputDecoration(
hintText: hintText,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
),
);
}
}
```
#### c) Navigatiebalk
```dart
// lib/src/navigation_bars.dart
import 'package:flutter/material.dart';
class CustomNavigationBar extends StatelessWidget {
final int currentIndex;
final Function(int) onTap;
const CustomNavigationBar({
Key? key,
required this.currentIndex,
required this.onTap,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return BottomNavigationBar(
currentIndex: currentIndex,
onTap: onTap,
backgroundColor: Colors.white,
selectedItemColor: AppColors.primaryBlue,
unselectedItemColor: Colors.grey,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Zoeken',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profiel',
),
],
);
}
}
```
---
### 4. Exporteer alle widgets
```dart
// lib/my_ui_library.dart
library my_ui_library;
export 'src/themes.dart';
export 'src/buttons.dart';
export 'src/input_fields.dart';
export 'src/navigation_bars.dart';
```
---
### 5. Gebruik in je app
```dart
import 'package:flutter/material.dart';
import 'package:my_ui_library/my_ui_library.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: AppTheme.theme,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _currentIndex = 0;
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Mijn App')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
CustomTextField(
hintText: 'Voer tekst in',
controller: _controller,
),
SizedBox(height: 16),
CustomButton(
label: 'Klik mij',
onPressed: () {
// actie
},
),
],
),
),
bottomNavigationBar: CustomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
),
);
}
}
```
---
### 6. Beste praktijken voor documentatie
- Voeg een `README.md` toe waarin je de doelen, installatie-instructies en voorbeelden beschrijft.
- Documenteer elke widget met docstrings (`///`) die uitleg geven over parameters en gebruik.
- Gebruik consistent naamgeving en commentaar.
- Overweeg om een voorbeeldproject toe te voegen dat laat zien hoe je de bibliotheek gebruikt.
---
### Samenvatting
Door je componenten goed te structureren, thematische ondersteuning te bieden via `ThemeData`, en duidelijke documentatie te schrijven, maak je een onderhoudbare, herbruikbare Flutter bibliotheek die in meerdere projecten makkelijk te integreren is.
Wil je dat ik een complete voorbeeldmapje opstel of verdere hulp bij specifieke widgets?
provider: deepseek
model: deepseek-chat
Zeker! Ik help je bij het opzetten van een aangepaste Flutter widgetbibliotheek. Hier is een complete handleiding:
## 📁 Bibliotheekstructuur
```
custom_ui_library/
├── lib/
│ ├── src/
│ │ ├── widgets/
│ │ │ ├── buttons/
│ │ │ ├── inputs/
│ │ │ ├── navigation/
│ │ │ └── base/
│ │ ├── theme/
│ │ │ ├── app_theme.dart
│ │ │ └── color_palette.dart
│ │ └── utils/
│ ├── custom_ui_library.dart
│ └── example/
├── pubspec.yaml
└── README.md
```
## 🎨 Thema Definitie
**lib/src/theme/color_palette.dart**
```dart
class CustomColors {
static const Color primaryBlue = Color(0xFF2196F3);
static const Color primaryDark = Color(0xFF1976D2);
static const Color primaryLight = Color(0xFFBBDEFB);
static const Color secondary = Color(0xFF757575);
static const Color background = Color(0xFFFAFAFA);
}
```
**lib/src/theme/app_theme.dart**
```dart
import 'package:flutter/material.dart';
import 'color_palette.dart';
class CustomTheme {
static ThemeData get lightTheme {
return ThemeData.light().copyWith(
primaryColor: CustomColors.primaryBlue,
colorScheme: ColorScheme.light(
primary: CustomColors.primaryBlue,
secondary: CustomColors.secondary,
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: CustomColors.primaryBlue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide(color: Colors.grey.shade400),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide(color: CustomColors.primaryBlue, width: 2),
),
),
);
}
}
```
## 🔘 Basis Widget Klasse
**lib/src/widgets/base/custom_base_widget.dart**
```dart
import 'package:flutter/material.dart';
abstract class CustomBaseWidget extends StatelessWidget {
const CustomBaseWidget({Key? key}) : super(key: key);
// Gemeenschappelijke eigenschappen
BorderRadius get defaultBorderRadius => BorderRadius.circular(8.0);
EdgeInsets get defaultPadding => const EdgeInsets.all(16.0);
@override
Widget build(BuildContext context) {
return buildWidget(context);
}
Widget buildWidget(BuildContext context);
}
```
## 🎯 Aangepaste Knoppen
**lib/src/widgets/buttons/custom_button.dart**
```dart
import 'package:flutter/material.dart';
import '../base/custom_base_widget.dart';
class CustomButton extends CustomBaseWidget {
final String text;
final VoidCallback? onPressed;
final ButtonType type;
final bool isLoading;
final IconData? icon;
const CustomButton({
Key? key,
required this.text,
required this.onPressed,
this.type = ButtonType.primary,
this.isLoading = false,
this.icon,
}) : super(key: key);
@override
Widget buildWidget(BuildContext context) {
final theme = Theme.of(context);
return ElevatedButton(
onPressed: isLoading ? null : onPressed,
style: _getButtonStyle(theme),
child: isLoading
? SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation(theme.colorScheme.onPrimary),
),
)
: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (icon != null) ...[
Icon(icon, size: 18),
const SizedBox(width: 8),
],
Text(
text,
style: theme.textTheme.labelLarge?.copyWith(
fontWeight: FontWeight.w600,
),
),
],
),
);
}
ButtonStyle _getButtonStyle(ThemeData theme) {
switch (type) {
case ButtonType.primary:
return ElevatedButton.styleFrom(
backgroundColor: theme.primaryColor,
shape: RoundedRectangleBorder(borderRadius: defaultBorderRadius),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
);
case ButtonType.secondary:
return ElevatedButton.styleFrom(
backgroundColor: Colors.transparent,
foregroundColor: theme.primaryColor,
shape: RoundedRectangleBorder(
borderRadius: defaultBorderRadius,
side: BorderSide(color: theme.primaryColor),
),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
);
}
}
}
enum ButtonType { primary, secondary }
```
## 📝 Tekst Invoer Widget
**lib/src/widgets/inputs/custom_text_field.dart**
```dart
import 'package:flutter/material.dart';
import '../base/custom_base_widget.dart';
class CustomTextField extends CustomBaseWidget {
final String label;
final String? hintText;
final TextEditingController? controller;
final bool obscureText;
final TextInputType keyboardType;
final String? errorText;
final Widget? suffixIcon;
final ValueChanged<String>? onChanged;
const CustomTextField({
Key? key,
required this.label,
this.hintText,
this.controller,
this.obscureText = false,
this.keyboardType = TextInputType.text,
this.errorText,
this.suffixIcon,
this.onChanged,
}) : super(key: key);
@override
Widget buildWidget(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
TextField(
controller: controller,
obscureText: obscureText,
keyboardType: keyboardType,
onChanged: onChanged,
decoration: InputDecoration(
hintText: hintText,
errorText: errorText,
suffixIcon: suffixIcon,
border: OutlineInputBorder(
borderRadius: defaultBorderRadius,
),
),
),
],
);
}
}
```
## 🧭 Navigatie Balk
**lib/src/widgets/navigation/custom_bottom_nav_bar.dart**
```dart
import 'package:flutter/material.dart';
import '../base/custom_base_widget.dart';
class CustomBottomNavBar extends CustomBaseWidget {
final int currentIndex;
final ValueChanged<int> onTap;
final List<BottomNavItem> items;
const CustomBottomNavBar({
Key? key,
required this.currentIndex,
required this.onTap,
required this.items,
}) : super(key: key);
@override
Widget buildWidget(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, -2),
),
],
),
child: ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
child: BottomNavigationBar(
currentIndex: currentIndex,
onTap: onTap,
items: items.map((item) => item.toBottomNavigationBarItem()).toList(),
type: BottomNavigationBarType.fixed,
selectedItemColor: Theme.of(context).primaryColor,
unselectedItemColor: Colors.grey.shade600,
),
),
);
}
}
class BottomNavItem {
final String label;
final IconData icon;
final IconData? activeIcon;
const BottomNavItem({
required this.label,
required this.icon,
this.activeIcon,
});
BottomNavigationBarItem toBottomNavigationBarItem() {
return BottomNavigationBarItem(
icon: Icon(icon),
activeIcon: Icon(activeIcon ?? icon),
label: label,
);
}
}
```
## 📦 Hoofd Export Bestand
**lib/custom_ui_library.dart**
```dart
library custom_ui_library;
// Thema
export 'src/theme/app_theme.dart';
export 'src/theme/color_palette.dart';
// Widgets
export 'src/widgets/buttons/custom_button.dart';
export 'src/widgets/inputs/custom_text_field.dart';
export 'src/widgets/navigation/custom_bottom_nav_bar.dart';
// Utils
export 'src/utils/widget_utils.dart';
```
## 📋 Pubspec.yaml
```yaml
name: custom_ui_library
description: Een herbruikbare UI component bibliotheek voor Flutter apps
version: 1.0.0
environment:
sdk: ">=2.18.0 <4.0.0"
flutter: ">=3.0.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
flutter:
```
## 💡 Gebruik in je App
```dart
import 'package:flutter/material.dart';
import 'package:custom_ui_library/custom_ui_library.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Mijn App',
theme: CustomTheme.lightTheme,
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
CustomTextField(
label: 'Email',
hintText: 'Voer je email in',
onChanged: (value) => print(value),
),
const SizedBox(height: 20),
CustomButton(
text: 'Inloggen',
onPressed: () => print('Knop geklikt'),
icon: Icons.login,
),
],
),
),
bottomNavigationBar: CustomBottomNavBar(
currentIndex: 0,
onTap: (index) => print('Tab: $index'),
items: const [
BottomNavItem(label: 'Home', icon: Icons.home),
BottomNavItem(label: 'Profiel', icon: Icons.person),
],
),
);
}
}
```
## 📚 Documentatie Best Practices
**1. Widget Documentatie Voorbeeld:**
```dart
/// Een aangepaste knop widget die het Material Design volgt
/// met primaire blauwe kleur en afgeronde hoeken.
///
/// ## Gebruik
/// ```dart
/// CustomButton(
/// text: 'Klik mij',
/// onPressed: () => print('Geklikt!'),
/// type: ButtonType.primary,
/// )
/// ```
///
/// ## Parameters
/// - [text]: De tekst die op de knop wordt weergegeven
/// - [onPressed]: Callback functie wanneer de knop wordt ingedrukt
/// - [type]: Het type knop (primair of secundair)
/// - [isLoading]: Toont een laadindicator wanneer true
class CustomButton extends CustomBaseWidget {
// ... implementatie
}
```
**2. README.md Template:**
```markdown
# Custom UI Library
Een herbruikbare Flutter widget bibliotheek met Material Design componenten.
## Installatie
Voeg toe aan je `pubspec.yaml`:
```yaml
dependencies:
custom_ui_library:
git:
url: https://github.com/jouw-username/custom_ui_library
```
## Gebruik
Importeer de bibliotheek:
```dart
import 'package:custom_ui_library/custom_ui_library.dart';
```
## Beschikbare Widgets
- `CustomButton` - Aanpasbare knoppen
- `CustomTextField` - Tekst invoer velden
- `CustomBottomNavBar` - Navigatie balk
```
## 🔧 Onderhoud Tips
1. **Versiebeheer**: Gebruik semantische versienummers
2. **Testing**: Schrijf unit tests voor alle widgets
3. **Documentatie**: Houd documentatie up-to-date
4. **Breaking Changes**: Gebruik `deprecated` annotatie voor wijzigingen
5. **Voorbeelden**: Zorg voor een uitgebreid voorbeeld project
Deze structuur zorgt voor een schaalbare, onderhoudbare bibliotheek die eenvoudig in meerdere projecten kan worden geïntegreerd!
error: Generation failed [deepseek] prompt_id=4902 locale=en err=DeepSeek connection/timeout | Generation failed [deepseek] prompt_id=4902 locale=es err=DeepSeek connection/timeout