Button
Pendahuluan
Nylo Website menyediakan kelas Button dengan delapan gaya button siap pakai. Setiap button dilengkapi dengan dukungan bawaan untuk:
- Status loading async -- kembalikan
FuturedarionPresseddan button secara otomatis menampilkan indikator loading - Gaya animasi -- pilih dari efek clickable, bounce, pulse, squeeze, jelly, shine, ripple, morph, dan shake
- Gaya splash -- tambahkan umpan balik sentuh ripple, highlight, glow, atau ink
- Pengiriman formulir -- hubungkan button langsung ke instance
NyFormData
Anda dapat menemukan definisi button aplikasi Anda di lib/resources/widgets/buttons/buttons.dart. File ini berisi kelas Button dengan method statis untuk setiap tipe button, memudahkan Anda untuk menyesuaikan nilai default proyek Anda.
Penggunaan Dasar
Gunakan kelas Button di mana saja dalam widget Anda. Berikut contoh sederhana di dalam sebuah halaman:
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
children: [
Button.primary(
text: "Sign Up",
onPressed: () {
routeTo(SignUpPage.path);
},
),
SizedBox(height: 12),
Button.secondary(
text: "Learn More",
onPressed: () {
routeTo(AboutPage.path);
},
),
SizedBox(height: 12),
Button.outlined(
text: "Cancel",
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
),
);
}
Setiap tipe button mengikuti pola yang sama -- berikan label text dan callback onPressed.
Tipe Button yang Tersedia
Semua button diakses melalui kelas Button menggunakan method statis.
Primary
Button terisi dengan bayangan, menggunakan warna primer tema Anda. Terbaik untuk elemen call-to-action utama.
Button.primary(
text: "Sign Up",
onPressed: () {
// Handle press
},
)
Secondary
Button terisi dengan warna permukaan yang lebih lembut dan bayangan halus. Cocok untuk aksi sekunder di samping button primer.
Button.secondary(
text: "Learn More",
onPressed: () {
// Handle press
},
)
Outlined
Button transparan dengan garis tepi. Berguna untuk aksi yang kurang menonjol atau button batal.
Button.outlined(
text: "Cancel",
onPressed: () {
// Handle press
},
)
Anda dapat menyesuaikan warna garis tepi dan teks:
Button.outlined(
text: "Custom Outline",
borderColor: Colors.red,
textColor: Colors.red,
onPressed: () {},
)
Text Only
Button minimal tanpa latar belakang atau garis tepi. Ideal untuk aksi inline atau tautan.
Button.textOnly(
text: "Skip",
onPressed: () {
// Handle press
},
)
Anda dapat menyesuaikan warna teks:
Button.textOnly(
text: "View Details",
textColor: Colors.blue,
onPressed: () {},
)
Icon
Button terisi yang menampilkan ikon di samping teks. Ikon muncul sebelum teks secara default.
Button.icon(
text: "Add to Cart",
icon: Icon(Icons.shopping_cart),
onPressed: () {
// Handle press
},
)
Anda dapat menyesuaikan warna latar belakang:
Button.icon(
text: "Download",
icon: Icon(Icons.download),
color: Colors.green,
onPressed: () {},
)
Gradient
Button dengan latar belakang gradien linear. Menggunakan warna primer dan tersier tema Anda secara default.
Button.gradient(
text: "Get Started",
onPressed: () {
// Handle press
},
)
Anda dapat memberikan warna gradien kustom:
Button.gradient(
text: "Premium",
gradientColors: [Colors.purple, Colors.pink],
onPressed: () {},
)
Rounded
Button berbentuk pil dengan sudut yang sepenuhnya membulat. Radius border secara default adalah setengah dari tinggi button.
Button.rounded(
text: "Continue",
onPressed: () {
// Handle press
},
)
Anda dapat menyesuaikan warna latar belakang dan radius border:
Button.rounded(
text: "Apply",
backgroundColor: Colors.teal,
borderRadius: BorderRadius.circular(20),
onPressed: () {},
)
Transparency
Button bergaya kaca buram dengan efek blur latar belakang. Bekerja dengan baik saat ditempatkan di atas gambar atau latar belakang berwarna.
Button.transparency(
text: "Explore",
onPressed: () {
// Handle press
},
)
Anda dapat menyesuaikan warna teks:
Button.transparency(
text: "View More",
color: Colors.white,
onPressed: () {},
)
Status Loading Async
Salah satu fitur paling kuat dari button Nylo Website adalah manajemen status loading otomatis. Ketika callback onPressed Anda mengembalikan Future, button akan secara otomatis menampilkan indikator loading dan menonaktifkan interaksi hingga operasi selesai.
Button.primary(
text: "Submit",
onPressed: () async {
await sleep(3); // Simulates a 3 second async task
},
)
Selama operasi async berjalan, button akan menampilkan efek skeleton loading (secara default). Setelah Future selesai, button kembali ke status normalnya.
Ini bekerja dengan operasi async apa pun -- panggilan API, penulisan database, upload file, atau apa pun yang mengembalikan Future:
Button.primary(
text: "Save Profile",
onPressed: () async {
await api<ApiService>((request) =>
request.updateProfile(name: "John", email: "john@example.com")
);
showToastSuccess(description: "Profile saved!");
},
)
Button.secondary(
text: "Sync Data",
onPressed: () async {
await fetchAndStoreData();
await clearOldCache();
},
)
Tidak perlu mengelola variabel state isLoading, memanggil setState, atau membungkus apa pun dalam StatefulWidget -- Nylo Website menangani semuanya untuk Anda.
Cara Kerjanya
Ketika button mendeteksi bahwa onPressed mengembalikan Future, ia menggunakan mekanisme lockRelease untuk:
- Menampilkan indikator loading (dikendalikan oleh
LoadingStyle) - Menonaktifkan button untuk mencegah ketukan ganda
- Menunggu
Futureselesai - Mengembalikan button ke status normalnya
Gaya Animasi
Button mendukung animasi tekan melalui ButtonAnimationStyle. Animasi ini memberikan umpan balik visual saat pengguna berinteraksi dengan button. Anda dapat mengatur gaya animasi saat menyesuaikan button Anda di lib/resources/widgets/buttons/buttons.dart.
Clickable
Efek tekan 3D bergaya Duolingo. Button bergerak ke bawah saat ditekan dan memantul kembali saat dilepas. Terbaik untuk aksi utama dan UX bergaya permainan.
animationStyle: ButtonAnimationStyle.clickable()
Sesuaikan efeknya:
ButtonAnimationStyle.clickable(
translateY: 6.0, // How far the button moves down (default: 4.0)
shadowOffset: 6.0, // Shadow depth (default: 4.0)
duration: Duration(milliseconds: 100),
enableHapticFeedback: true,
)
Bounce
Mengecilkan button saat ditekan dan memantul kembali saat dilepas. Terbaik untuk button tambah-ke-keranjang, suka, dan favorit.
animationStyle: ButtonAnimationStyle.bounce()
Sesuaikan efeknya:
ButtonAnimationStyle.bounce(
scaleMin: 0.90, // Minimum scale on press (default: 0.92)
duration: Duration(milliseconds: 150),
curve: Curves.easeOutBack,
enableHapticFeedback: true,
)
Pulse
Denyut skala halus yang berkelanjutan saat button ditahan. Terbaik untuk aksi tekan-lama atau menarik perhatian.
animationStyle: ButtonAnimationStyle.pulse()
Sesuaikan efeknya:
ButtonAnimationStyle.pulse(
pulseScale: 1.08, // Max scale during pulse (default: 1.05)
duration: Duration(milliseconds: 800),
curve: Curves.easeInOut,
)
Squeeze
Memampatkan button secara horizontal dan memperluasnya secara vertikal saat ditekan. Terbaik untuk UI yang menyenangkan dan interaktif.
animationStyle: ButtonAnimationStyle.squeeze()
Sesuaikan efeknya:
ButtonAnimationStyle.squeeze(
squeezeX: 0.93, // Horizontal scale (default: 0.95)
squeezeY: 1.07, // Vertical scale (default: 1.05)
duration: Duration(milliseconds: 120),
enableHapticFeedback: true,
)
Jelly
Efek deformasi elastis yang bergoyang. Terbaik untuk aplikasi yang menyenangkan, kasual, atau hiburan.
animationStyle: ButtonAnimationStyle.jelly()
Sesuaikan efeknya:
ButtonAnimationStyle.jelly(
jellyStrength: 0.2, // Wobble intensity (default: 0.15)
duration: Duration(milliseconds: 300),
curve: Curves.elasticOut,
enableHapticFeedback: true,
)
Shine
Sorotan mengkilap yang menyapu melintasi button saat ditekan. Terbaik untuk fitur premium atau CTA yang ingin Anda tonjolkan.
animationStyle: ButtonAnimationStyle.shine()
Sesuaikan efeknya:
ButtonAnimationStyle.shine(
shineColor: Colors.white, // Color of the shine streak (default: white)
shineWidth: 0.4, // Width of the shine band (default: 0.3)
duration: Duration(milliseconds: 600),
)
Ripple
Efek riak yang diperbesar yang meluas dari titik sentuh. Terbaik untuk penekanan Material Design.
animationStyle: ButtonAnimationStyle.ripple()
Sesuaikan efeknya:
ButtonAnimationStyle.ripple(
rippleScale: 2.5, // How far the ripple expands (default: 2.0)
duration: Duration(milliseconds: 400),
curve: Curves.easeOut,
enableHapticFeedback: true,
)
Morph
Radius border button bertambah saat ditekan, menciptakan efek perubahan bentuk. Terbaik untuk umpan balik yang halus dan elegan.
animationStyle: ButtonAnimationStyle.morph()
Sesuaikan efeknya:
ButtonAnimationStyle.morph(
morphRadius: 30.0, // Target border radius on press (default: 24.0)
duration: Duration(milliseconds: 150),
curve: Curves.easeInOut,
)
Shake
Animasi goyang horizontal. Terbaik untuk status error atau aksi tidak valid -- goyangkan button untuk memberi sinyal bahwa ada yang salah.
animationStyle: ButtonAnimationStyle.shake()
Sesuaikan efeknya:
ButtonAnimationStyle.shake(
shakeOffset: 10.0, // Horizontal displacement (default: 8.0)
shakeCount: 4, // Number of shakes (default: 3)
duration: Duration(milliseconds: 400),
enableHapticFeedback: true,
)
Menonaktifkan Animasi
Untuk menggunakan button tanpa animasi:
animationStyle: ButtonAnimationStyle.none()
Mengubah Animasi Default
Untuk mengubah animasi default untuk tipe button, ubah file lib/resources/widgets/buttons/buttons.dart Anda:
class Button {
static Widget primary({
required String text,
VoidCallback? onPressed,
...
}) {
return PrimaryButton(
text: text,
onPressed: onPressed,
animationStyle: ButtonAnimationStyle.bounce(), // Change the default
);
}
}
Gaya Splash
Efek splash memberikan umpan balik sentuh visual pada button. Konfigurasikan melalui ButtonSplashStyle. Gaya splash dapat dikombinasikan dengan gaya animasi untuk umpan balik berlapis.
Gaya Splash yang Tersedia
| Splash | Factory | Deskripsi |
|---|---|---|
| Ripple | ButtonSplashStyle.ripple() |
Riak Material standar dari titik sentuh |
| Highlight | ButtonSplashStyle.highlight() |
Sorotan halus tanpa animasi riak |
| Glow | ButtonSplashStyle.glow() |
Cahaya lembut yang memancar dari titik sentuh |
| Ink | ButtonSplashStyle.ink() |
Percikan tinta cepat, lebih cepat dan lebih responsif |
| None | ButtonSplashStyle.none() |
Tanpa efek splash |
| Custom | ButtonSplashStyle.custom() |
Kontrol penuh atas factory splash |
Contoh
class Button {
static Widget outlined({
required String text,
VoidCallback? onPressed,
...
}) {
return OutlinedButton(
text: text,
onPressed: onPressed,
splashStyle: ButtonSplashStyle.ripple(),
animationStyle: ButtonAnimationStyle.clickable(),
);
}
}
Anda dapat menyesuaikan warna splash dan opasitas:
ButtonSplashStyle.ripple(
splashColor: Colors.blue,
highlightColor: Colors.blue,
splashOpacity: 0.2,
highlightOpacity: 0.1,
)
Gaya Loading
Indikator loading yang ditampilkan selama operasi async dikendalikan oleh LoadingStyle. Anda dapat mengaturnya per tipe button di file buttons Anda.
Skeletonizer (Default)
Menampilkan efek shimmer skeleton pada button:
loadingStyle: LoadingStyle.skeletonizer()
Normal
Menampilkan widget loading (secara default loader aplikasi):
loadingStyle: LoadingStyle.normal(
child: Text("Please wait..."),
)
None
Menjaga button tetap terlihat tetapi menonaktifkan interaksi selama loading:
loadingStyle: LoadingStyle.none()
Pengiriman Formulir
Semua button mendukung parameter submitForm, yang menghubungkan button ke NyForm. Saat diketuk, button akan memvalidasi formulir dan memanggil handler sukses Anda dengan data formulir.
Button.primary(
text: "Submit",
submitForm: (LoginForm(), (data) {
// data contains the validated form fields
print(data);
}),
onFailure: (error) {
// Handle validation errors
print(error);
},
)
Parameter submitForm menerima record dengan dua nilai:
- Instance
NyFormData(atau nama formulir sebagaiString) - Callback yang menerima data yang telah divalidasi
Secara default, showToastError bernilai true, yang menampilkan notifikasi toast saat validasi formulir gagal. Atur ke false untuk menangani error secara diam-diam:
Button.primary(
text: "Login",
submitForm: (LoginForm(), (data) async {
await api<AuthApiService>((request) => request.login(data));
}),
showToastError: false,
onFailure: (error) {
// Custom error handling
},
)
Ketika callback submitForm mengembalikan Future, button akan secara otomatis menampilkan status loading hingga operasi async selesai.
Menyesuaikan Button
Semua default button didefinisikan di proyek Anda di lib/resources/widgets/buttons/buttons.dart. Setiap tipe button memiliki kelas widget yang sesuai di lib/resources/widgets/buttons/partials/.
Mengubah Gaya Default
Untuk mengubah tampilan default sebuah button, edit kelas Button:
class Button {
static Widget primary({
required String text,
VoidCallback? onPressed,
(dynamic, Function(dynamic data))? submitForm,
Function(dynamic error)? onFailure,
bool showToastError = true,
double? width,
}) {
return PrimaryButton(
text: text,
onPressed: onPressed,
submitForm: submitForm,
onFailure: onFailure,
showToastError: showToastError,
loadingStyle: LoadingStyle.skeletonizer(),
width: width,
height: 52.0,
animationStyle: ButtonAnimationStyle.bounce(),
splashStyle: ButtonSplashStyle.glow(),
);
}
}
Menyesuaikan Widget Button
Untuk mengubah tampilan visual dari tipe button, edit widget yang sesuai di lib/resources/widgets/buttons/partials/. Misalnya, untuk mengubah radius border atau bayangan button primer:
// lib/resources/widgets/buttons/partials/primary_button_widget.dart
class PrimaryButton extends StatefulAppButton {
...
@override
Widget buildButton(BuildContext context) {
final theme = Theme.of(context);
final bgColor = backgroundColor ?? theme.colorScheme.primary;
final fgColor = contentColor ?? theme.colorScheme.onPrimary;
return Container(
width: width ?? double.infinity,
height: height,
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(8), // Change the radius
),
child: Center(
child: Text(
text,
style: TextStyle(
color: fgColor,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
);
}
}
Membuat Tipe Button Baru
Untuk menambahkan tipe button baru:
- Buat file widget baru di
lib/resources/widgets/buttons/partials/yang meng-extendStatefulAppButton. - Implementasikan method
buildButton. - Tambahkan method statis di kelas
Button.
// lib/resources/widgets/buttons/partials/danger_button_widget.dart
class DangerButton extends StatefulAppButton {
DangerButton({
required super.text,
super.onPressed,
super.submitForm,
super.onFailure,
super.showToastError,
super.loadingStyle,
super.width,
super.height,
super.animationStyle,
super.splashStyle,
});
@override
Widget buildButton(BuildContext context) {
return Container(
width: width ?? double.infinity,
height: height,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(14),
),
child: Center(
child: Text(
text,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
);
}
}
Kemudian daftarkan di kelas Button:
class Button {
...
static Widget danger({
required String text,
VoidCallback? onPressed,
(dynamic, Function(dynamic data))? submitForm,
Function(dynamic error)? onFailure,
bool showToastError = true,
double? width,
}) {
return DangerButton(
text: text,
onPressed: onPressed,
submitForm: submitForm,
onFailure: onFailure,
showToastError: showToastError,
loadingStyle: LoadingStyle.skeletonizer(),
width: width,
height: 52.0,
animationStyle: ButtonAnimationStyle.shake(),
);
}
}
Referensi Parameter
Parameter Umum (Semua Tipe Button)
| Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
text |
String |
wajib | Teks label button |
onPressed |
VoidCallback? |
null |
Callback saat button diketuk. Kembalikan Future untuk status loading otomatis |
submitForm |
(dynamic, Function(dynamic))? |
null |
Record pengiriman formulir (instance formulir, callback sukses) |
onFailure |
Function(dynamic)? |
null |
Dipanggil saat validasi formulir gagal |
showToastError |
bool |
true |
Tampilkan notifikasi toast saat error validasi formulir |
width |
double? |
null |
Lebar button (default lebar penuh) |
Parameter Khusus Tipe
Button.outlined
| Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
borderColor |
Color? |
Warna outline tema | Warna garis tepi |
textColor |
Color? |
Warna primer tema | Warna teks |
Button.textOnly
| Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
textColor |
Color? |
Warna primer tema | Warna teks |
Button.icon
| Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
icon |
Widget |
wajib | Widget ikon yang ditampilkan |
color |
Color? |
Warna primer tema | Warna latar belakang |
Button.gradient
| Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
gradientColors |
List<Color>? |
Warna primer dan tersier | Titik warna gradien |
Button.rounded
| Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
backgroundColor |
Color? |
Warna primary container tema | Warna latar belakang |
borderRadius |
BorderRadius? |
Bentuk pil (tinggi / 2) | Radius sudut |
Button.transparency
| Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
color |
Color? |
Adaptif tema | Warna teks |
Parameter ButtonAnimationStyle
| Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
duration |
Duration |
Bervariasi per tipe | Durasi animasi |
curve |
Curve |
Bervariasi per tipe | Kurva animasi |
enableHapticFeedback |
bool |
Bervariasi per tipe | Memicu umpan balik haptik saat ditekan |
translateY |
double |
4.0 |
Clickable: jarak tekan vertikal |
shadowOffset |
double |
4.0 |
Clickable: kedalaman bayangan |
scaleMin |
double |
0.92 |
Bounce: skala minimum saat ditekan |
pulseScale |
double |
1.05 |
Pulse: skala maksimum selama denyut |
squeezeX |
double |
0.95 |
Squeeze: kompresi horizontal |
squeezeY |
double |
1.05 |
Squeeze: ekspansi vertikal |
jellyStrength |
double |
0.15 |
Jelly: intensitas goyangan |
shineColor |
Color |
Colors.white |
Shine: warna sorotan |
shineWidth |
double |
0.3 |
Shine: lebar pita kilau |
rippleScale |
double |
2.0 |
Ripple: skala ekspansi |
morphRadius |
double |
24.0 |
Morph: radius border target |
shakeOffset |
double |
8.0 |
Shake: perpindahan horizontal |
shakeCount |
int |
3 |
Shake: jumlah osilasi |
Parameter ButtonSplashStyle
| Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
splashColor |
Color? |
Warna surface tema | Warna efek splash |
highlightColor |
Color? |
Warna surface tema | Warna efek highlight |
splashOpacity |
double |
0.12 |
Opasitas splash |
highlightOpacity |
double |
0.06 |
Opasitas highlight |
borderRadius |
BorderRadius? |
null |
Radius clip splash |