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.
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"/>
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';
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,
),
),
);
}
}
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(),
],
),
),
);
}
}
- Wear OS devices with rotary input and round screens (Galaxy Watch 4, Pixel Watch, etc.)