Tugas 13 - Pemrograman Perangkat Bergerak
Hesekiel Nainggolan
5025201054
PPB I
FLUTTER - MUSIC APPLICATION (MyArtist)
Pada pertemuan kali ini kita akan membuat sebuah aplikasi musik, MyArtist, sebuah aplikasi pemutar musik tempat penggemar dapat terus mengikuti kabar terbaru dari artis favoritnya. Bagian ini membahas cara memodifikasi desain aplikasi Anda agar terlihat bagus di berbagai platform. Code program dapat kita lihat pada link Github. Sebenarnya aplikasi ini sudah jadi dalam bentuk web dan windows, namun dalam bentuk android, bentuk dari aplikasi ini masih tidak bagus. Jadi pada pertemuan ini, kita akan coba memperbaiki tampilan aplikasinya dalam bentuk android.
- Menerapkan Kode
Buka lib/src/features/home/view/home_screen.dart, yang berisi hal berikut:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:adaptive_components/adaptive_components.dart'; | |
import 'package:flutter/material.dart'; | |
import '../../../shared/classes/classes.dart'; | |
import '../../../shared/extensions.dart'; | |
import '../../../shared/providers/providers.dart'; | |
import '../../../shared/views/views.dart'; | |
import '../../playlists/view/playlist_songs.dart'; | |
import 'view.dart'; | |
class HomeScreen extends StatefulWidget { | |
const HomeScreen({Key? key}) : super(key: key); | |
@override | |
State<HomeScreen> createState() => _HomeScreenState(); | |
} | |
class _HomeScreenState extends State<HomeScreen> { | |
@override | |
Widget build(BuildContext context) { | |
final PlaylistsProvider playlistProvider = PlaylistsProvider(); | |
final List<Playlist> playlists = playlistProvider.playlists; | |
final Playlist topSongs = playlistProvider.topSongs; | |
final Playlist newReleases = playlistProvider.newReleases; | |
final ArtistsProvider artistsProvider = ArtistsProvider(); | |
final List<Artist> artists = artistsProvider.artists; | |
return LayoutBuilder( | |
builder: (context, constraints) { | |
// Add conditional mobile layout | |
return Scaffold( | |
body: SingleChildScrollView( | |
child: AdaptiveColumn( | |
children: [ | |
AdaptiveContainer( | |
columnSpan: 12, | |
child: Padding( | |
padding: const EdgeInsets.all(2), // Modify this line | |
child: Row( | |
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |
children: [ | |
Expanded( | |
child: Text( | |
'Good morning', | |
style: context.displaySmall, | |
), | |
), | |
const SizedBox(width: 20), | |
const BrightnessToggle(), | |
], | |
), | |
), | |
), | |
AdaptiveContainer( | |
columnSpan: 12, | |
child: Column( | |
children: [ | |
const HomeHighlight(), | |
LayoutBuilder( | |
builder: (context, constraints) => HomeArtists( | |
artists: artists, | |
constraints: constraints, | |
), | |
), | |
], | |
), | |
), | |
AdaptiveContainer( | |
columnSpan: 12, | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: [ | |
Padding( | |
padding: const EdgeInsets.all(2), // Modify this line | |
child: Text( | |
'Recently played', | |
style: context.headlineSmall, | |
), | |
), | |
HomeRecent( | |
playlists: playlists, | |
), | |
], | |
), | |
), | |
AdaptiveContainer( | |
columnSpan: 12, | |
child: Padding( | |
padding: const EdgeInsets.all(2), // Modify this line | |
child: Row( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: [ | |
Flexible( | |
flex: 10, | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.start, | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: [ | |
Padding( | |
padding: | |
const EdgeInsets.all(2), // Modify this line | |
child: Text( | |
'Top Songs Today', | |
style: context.titleLarge, | |
), | |
), | |
LayoutBuilder( | |
builder: (context, constraints) => | |
PlaylistSongs( | |
playlist: topSongs, | |
constraints: constraints, | |
), | |
), | |
], | |
), | |
), | |
// Add spacer between tables | |
Flexible( | |
flex: 10, | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.start, | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: [ | |
Padding( | |
padding: | |
const EdgeInsets.all(2), // Modify this line | |
child: Text( | |
'New Releases', | |
style: context.titleLarge, | |
), | |
), | |
LayoutBuilder( | |
builder: (context, constraints) => | |
PlaylistSongs( | |
playlist: newReleases, | |
constraints: constraints, | |
), | |
), | |
], | |
), | |
), | |
], | |
), | |
), | |
), | |
], | |
), | |
), | |
); | |
}, | |
); | |
} | |
} |
File ini mengimpor material.dart dan menerapkan widget stateful menggunakan dua class:
- Pernyataan import akan menyediakan Komponen Material.
- Class HomeScreen merepresentasikan seluruh halaman yang ditampilkan.
- Metode build() class _HomeScreenState akan membuat root hierarki widget, yang memengaruhi cara pembuatan semua widget di UI.
- Memanfaatkan Tofografi
Kemudian kita akan mengganti simbol NavigationRail untuk ke page-page selanjutnya (Home, Playlists, Artists):
lib/src/shared/router.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const List<NavigationDestination> destinations = [ | |
NavigationDestination( | |
label: 'Home', | |
icon: Icon(Icons.home), // Modify this line | |
route: '/', | |
), | |
NavigationDestination( | |
label: 'Playlists', | |
icon: Icon(Icons.playlist_add_check), // Modify this line | |
route: '/playlists', | |
), | |
NavigationDestination( | |
label: 'Artists', | |
icon: Icon(Icons.people), // Modify this line | |
route: '/artists', | |
), | |
]; |
- Menetapkan Tema
Untuk memilih warna sumber aplikasi, buka Material Theme Builder dan coba berbagai warna untuk UI aplikasi kita. Setelah kita mengetahui nilai hex warna primer ke penyedia tema, kemudian ThemeProvider akan menghasilkan ThemeData yang berisi kumpulan warna pelengkap yang Anda lihat di Builder Tema Material:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
final settings = ValueNotifier(ThemeSettings( | |
sourceColor: Color(0xff00cbe6), // Replace this color | |
themeMode: ThemeMode.system, | |
)); |
Selain itu, Pengguna dapat menyesuaikan kecerahan aplikasi di setelan sistem perangkat. Di lib/src/shared/app.dart, jika perangkat disetel ke mode gelap, tampilkan tema gelap dan mode tema ke MaterialApp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
return MaterialApp.router( | |
debugShowCheckedModeBanner: false, | |
title: 'Flutter Demo', | |
theme: theme.light(settings.value.sourceColor), | |
darkTheme: theme.dark(settings.value.sourceColor), // Add this line | |
themeMode: theme.themeMode(), // Add this line | |
routeInformationParser: appRouter.routeInformationParser, | |
routerDelegate: appRouter.routerDelegate, | |
); |
- Menambah Desain Adaptif
Agar aplikasi Anda responsif, perkenalkan beberapa titik henti sementara adaptif (jangan samakan dengan titik henti sementara proses debug). Titik henti sementara ini menentukan ukuran layar tempat aplikasi akan mengubah tata letak. Layar yang lebih kecil tidak dapat menampilkan layar yang lebih besar tanpa mengecilkan konten. Agar aplikasi tidak terlihat seperti aplikasi desktop yang dikecilkan, buat tata letak terpisah untuk perangkat seluler yang menggunakan tab untuk membagi konten. Hal ini membuat aplikasi bersifat lebih native di perangkat seluler.
Metode ekstensi berikut dapat ditemukan di lib/src/shared/extensions.dart, merupakan tempat yang tepat untuk memulai saat mendesain tata letak yang dioptimalkan untuk berbagai perangkat target.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension BreakpointUtils on BoxConstraints { | |
bool get isTablet => maxWidth > 730; | |
bool get isDesktop => maxWidth > 1200; | |
bool get isMobile => !isTablet && !isDesktop; | |
} |
- Menambah Gerak dan Animasi
ThemeProvider menentukan PageTransitionsTheme dengan animasi transisi layar untuk platform seluler (iOS, Android). Pengguna desktop sudah mendapatkan masukan dari klik mouse atau trackpad, sehingga animasi transisi halaman tidak diperlukan.
Flutter menyediakan animasi transisi layar yang dapat dikonfigurasikan untuk aplikasi berdasarkan platform target seperti yang terlihat di lib/src/shared/providers/theme.dart:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
final pageTransitionsTheme = const PageTransitionsTheme( | |
builders: <TargetPlatform, PageTransitionsBuilder>{ | |
TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(), | |
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), | |
TargetPlatform.linux: NoAnimationPageTransitionsBuilder(), | |
TargetPlatform.macOS: NoAnimationPageTransitionsBuilder(), | |
TargetPlatform.windows: NoAnimationPageTransitionsBuilder(), | |
}, | |
); |
Teruskan PageTransitionsTheme ke tema terang dan gelap pada lib/src/shared/providers/theme.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ThemeData light([Color? targetColor]) { | |
final _colors = colors(Brightness.light, targetColor); | |
return ThemeData.light().copyWith( | |
pageTransitionsTheme: pageTransitionsTheme, // Add this line | |
colorScheme: ColorScheme.fromSeed( | |
seedColor: source(targetColor), | |
brightness: Brightness.light, | |
), | |
appBarTheme: appBarTheme(_colors), | |
cardTheme: cardTheme(), | |
listTileTheme: listTileTheme(), | |
tabBarTheme: tabBarTheme(_colors), | |
scaffoldBackgroundColor: _colors.background, | |
); | |
} | |
ThemeData dark([Color? targetColor]) { | |
final _colors = colors(Brightness.dark, targetColor); | |
return ThemeData.dark().copyWith( | |
pageTransitionsTheme: pageTransitionsTheme, // Add this line | |
colorScheme: ColorScheme.fromSeed( | |
seedColor: source(targetColor), | |
brightness: Brightness.dark, | |
), | |
appBarTheme: appBarTheme(_colors), | |
cardTheme: cardTheme(), | |
listTileTheme: listTileTheme(), | |
tabBarTheme: tabBarTheme(_colors), | |
scaffoldBackgroundColor: _colors.background, | |
); | |
} |
Hasil :
Komentar
Posting Komentar