Press ESC to close

Flutter App : Flutter scrollbar for wearOS devices with round screens

rotary_scrollbar

Flutter implementation of a native-looking Wear OS circular scrollbar.

It can be wrapped around a PageView, ListView or any other scrollable view.

And it is able to control the view’s ScrollController or PageController with rotary input, including haptic feedback for each rotary event.

Screenshot_1671591814

Setup

Wear OS (Android)

This package depends on wearable_rotary, which requires adding the following to MainActivity.kt:

import android.view.MotionEvent import com.samsung.wearable_rotary.WearableRotaryPlugin class MainActivity : FlutterActivity() { override fun onGenericMotionEvent(event: MotionEvent?): Boolean { return when { WearableRotaryPlugin.onGenericMotionEvent(event) -> true else -> super.onGenericMotionEvent(event) } } }

This package depends on vibration, which needs access to the VIBRATE permission, so make sure the following is added to AndroidManifest.xml

uses-permission android:name="android.permission.VIBRATE"/>

Usage

To use this plugin, add rotary_scrollbar as a dependency in your pubspec.yaml file.

dependencies:
  rotary_scrollbar: ^0.1.1

Then, import rotary_scrollbar in your Dart code.

// Import the package.
import 'package:rotary_scrollbar/rotary_scrollbar.dart';

ListView

class WatchScreen extends StatefulWidget { const WatchScreen({super.key}); @override State<WatchScreen> createState() => _WatchScreenState(); } class _WatchScreenState extends State<WatchScreen> { final scrollController = ScrollController(); @override void dispose() { scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: RotaryScrollWrapper( rotaryScrollbar: RotaryScrollbar( controller: scrollController, ), child: ListView.builder( controller: scrollController, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.only( bottom: 10, ), child: Container( color: Colors.blue.withRed(((255 / 29) * index).toInt()), width: 50, height: 50, child: Center(child: Text('box $index')), ), ); }, itemCount: 30, ), ), ); } }

PageView

class WatchScreen extends StatefulWidget { const WatchScreen({super.key}); @override State<WatchScreen> createState() => _WatchScreenState(); } class _WatchScreenState extends State<WatchScreen> { final pageController = PageController(); @override void dispose() { pageController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: RotaryScrollWrapper( rotaryScrollbar: RotaryScrollbar( controller: pageController, ), child: PageView( scrollDirection: Axis.vertical, controller: pageController, children: const [ Page1(), Page2(), Page3(), ], ), ), ); } }

Supported devices

GitHub

View Github

Footer Example