Skip to main content

flutter_native_widget 0.1.1 copy "flutter_native_widget: ^0.1.1" to clipboard
flutter_native_widget: ^0.1.1 copied to clipboard

Write Android and iOS home screen widgets in Dart. The companion generator turns them into native RemoteViews and WidgetKit code.

example/example.md

Example #

A full app with 14 widgets (counter, weather, music player, prayer times, tasks, clocks, …) lives in the repository: example/. Screenshots and how each one was made: flutter-native-widget.vercel.app/examples.

The smallest widget, a counter:

// lib/widgets.dart
import 'package:flutter_native_widget/flutter_native_widget.dart';

part 'widgets.fnw.dart';

@HomeScreenWidget(
  displayName: 'Counter',
  fields: [NWField.integer('count')],
  layout: NWColumn(children: [
    NWText('{count}', style: NWTextStyle(size: 44, weight: NWFontWeight.bold)),
    NWRow(spacing: 12, children: [
      NWButton(action: NWAction.decrement('count', min: 0), child: NWText('−')),
      NWButton(action: NWAction.increment('count'), child: NWText('+')),
    ]),
  ]),
)
class Counter {}
// lib/main.dart
import 'package:flutter/material.dart';
import 'home_widgets.g.dart';
import 'widgets.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await initializeHomeWidgets();
  runApp(MaterialApp(
    home: Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () => CounterWidget.save(count: 5),
          child: const Text('Set the widget to 5'),
        ),
      ),
    ),
  ));
}

Run dart run build_runner build after editing widgets.dart.

The examples below are taken from the example app.

Tasks: repeated rows and toggles on the home screen #

repeat: 4 makes four fields (title0…title3); # in a key becomes the row index. Tapping a row flips done# natively, without opening the app.

@HomeScreenWidget(
  displayName: 'Tasks',
  sizes: [NWSize.medium, NWSize.large],
  fields: [
    NWField.string('title', repeat: 4),
    NWField.boolean('done', repeat: 4),
  ],
  layout: NWColumn(
    crossAxisAlignment: NWCrossAxisAlignment.stretch,
    spacing: 6,
    children: [
      NWText('Tasks', style: NWTextStyle(size: 15, weight: NWFontWeight.semibold)),
      NWRepeat(
        count: 4,
        spacing: 4,
        child: NWIf(
          condition: NWCondition.notEmpty('title#'),
          child: NWButton(
            action: NWAction.toggle('done#'),
            child: NWRow(spacing: 8, children: [
              NWIf(
                condition: NWCondition.isTrue('done#'),
                child: NWText('☑'),
                orElse: NWText('☐'),
              ),
              NWText('{title#}', maxLines: 1),
            ]),
          ),
        ),
      ),
    ],
  ),
  onTap: NWAction.openApp('/tasks'),
)
class Tasks {}
await TasksWidget.save(
  title: ['Buy bread', 'Call mom', 'Finish the widget package'],
  done: [false, true, false],
);

Music player: a Dart callback that runs in the background #

NWAction.callback('next') runs the function marked @WidgetCallback(widget: 'NowPlaying') in a background isolate (Android, and iOS 17+). It reads the widget's data, changes it and saves it.

NWButton(action: NWAction.callback('previous'), child: NWText('⏮')),
NWButton(action: NWAction.callback('next'), child: NWText('⏭')),
@WidgetCallback(widget: 'NowPlaying')
Future<void> onMusicButton(WidgetEvent event) async {
  const tracks = [('Bohemian Rhapsody', 'Queen'), ('Clair de Lune', 'Debussy')];
  final current = await NowPlayingWidget.read();
  var index = tracks.indexWhere((t) => t.$1 == current.title);
  index = event.name == 'next'
      ? (index + 1) % tracks.length
      : (index - 1 + tracks.length) % tracks.length;
  await NowPlayingWidget.save(title: tracks[index].$1, artist: tracks[index].$2);
}

Prayer times: a timeline the widget follows on its own #

The app saves the whole day once. At each entry's time the system switches the widget to the next prayer, and NWTimer counts down to it every second.

@HomeScreenWidget(
  displayName: 'Prayer times',
  sizes: [NWSize.small, NWSize.medium, NWSize.rectangular, NWSize.inline],
  fields: [
    NWField.string('next', initial: '—'),
    NWField.dateTime('nextAt'),
  ],
  layout: NWColumn(children: [
    NWText('{next}', style: NWTextStyle(size: 26, weight: NWFontWeight.bold)),
    NWTimer(field: 'nextAt', style: NWTextStyle(size: 20, monospacedDigits: true)),
  ]),
  inlineLayout: NWText('🕌 {next}'),
)
class PrayerTimes {}
// prayers: [(name, time), …] for the rest of today
await PrayerTimesWidget.save(next: prayers[0].$1, nextAt: prayers[0].$2);
await PrayerTimesWidget.saveTimeline([
  for (var i = 0; i < prayers.length - 1; i++)
    PrayerTimesTimelineEntry(
      prayers[i].$2,
      next: prayers[i + 1].$1,
      nextAt: prayers[i + 1].$2,
    ),
]);

More examples (clocks, weather, news, photo album, activity rings, water tracker, …) with screenshots: flutter-native-widget.vercel.app/examples.

0
likes
160
points
845
downloads
screenshot

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

Write Android and iOS home screen widgets in Dart. The companion generator turns them into native RemoteViews and WidgetKit code.

Homepage
Repository (GitHub)
View/report issues

Topics

#home-screen-widget #widgetkit #code-generation

License

MIT (license)

Dependencies

flutter, home_widget

More

Packages that depend on flutter_native_widget