Flutter旋转选择器插件flutter_spinning_wheel的使用
Flutter旋转选择器插件flutter_spinning_wheel的使用
A customizable widget to use as a spinning wheel in Flutter.
开始使用
安装
在你的 pubspec.yaml
文件中添加以下内容:
flutter_spinning_wheel : ^latest_version
然后在项目根目录运行以下命令来安装依赖:
flutter packages get
基本用法
创建一个新的 Flutter 项目:
flutter create myapp
编辑 lib/main.dart
文件如下:
import 'package:flutter/material.dart';
import 'package:flutter_spinning_wheel/flutter_spinning_wheel.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: Container(
child: SpinningWheel(
Image.asset('assets/images/wheel-6-300.png'), // 使用自定义图片作为轮盘
width: 310, // 轮盘宽度
height: 310, // 轮盘高度
dividers: 6, // 分割份数
onEnd: _dividerController.add, // 动画结束时触发回调
),
),
));
}
}
你可以将 wheel-6-300.png
替换为你自己的图片。
效果图:
基本轮盘 | 游戏轮盘 |
---|---|
![]() |
![]() |
构造函数参数
以下是 SpinningWheel
的构造函数参数及其描述:
参数名称 | 默认值 | 描述 |
---|---|---|
image | 无 | 用于轮盘的图片 |
dividers | 无 | 图片的分割份数,所有分割必须相等 |
height | 无 | 显示轮盘的容器高度 |
width | 无 | 显示轮盘的容器宽度 |
initialSpinAngle | 0.0 | 轮盘初始旋转角度 |
spinResistance | 0.5 | 从 >0.0 到 1.0 用于计算轮盘的速度和减速 |
canInteractWhileSpinning | true | 如果设置为 false,则动画开始后用户无法停止它 |
secondaryImage | 无 | 渲染在轮盘顶部的次级图片,不会受动画影响 |
secondaryImageHeight | 无 | 次级图片的高度 |
secondaryImageWidth | 无 | 次级图片的宽度 |
secondaryImageTop | 无 | 用于微调次级图片的位置 |
secondaryImageLeft | 无 | 用于微调次级图片的位置 |
onUpdate | void onUpdate(int value) | 在选中的分割变化时执行的回调函数 |
onEnd | void onEnd(int value) | 动画停止时执行的回调函数 |
shouldStartOrStop | 无 | 控制是否开始或停止动画的流 |
使用案例
游戏轮盘
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_spinning_wheel/flutter_spinning_wheel.dart';
void main() {
SystemChrome.setEnabledSystemUIOverlays([]);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
final StreamController _dividerController = StreamController<int>();
dispose() {
_dividerController.close();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: Color(0xffDDC3FF), elevation: 0.0),
backgroundColor: Color(0xffDDC3FF),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SpinningWheel(
Image.asset('assets/images/roulette-8-300.png'), // 轮盘图片
width: 310,
height: 310,
initialSpinAngle: _generateRandomAngle(), // 随机初始角度
spinResistance: 0.6,
canInteractWhileSpinning: false, // 动画期间不可交互
dividers: 8, // 分割份数
onUpdate: _dividerController.add, // 更新时的回调
onEnd: _dividerController.add, // 动画结束时的回调
secondaryImage: Image.asset('assets/images/roulette-center-300.png'), // 次级图片
secondaryImageHeight: 110,
secondaryImageWidth: 110,
),
SizedBox(height: 30),
StreamBuilder(
stream: _dividerController.stream,
builder: (context, snapshot) =>
snapshot.hasData ? RouletteScore(snapshot.data) : Container(),
)
],
),
),
);
}
double _generateRandomAngle() => Random().nextDouble() * pi * 2;
}
class RouletteScore extends StatelessWidget {
final int selected;
final Map<int, String> labels = {
1: '1000\$',
2: '400\$',
3: '800\$',
4: '7000\$',
5: '5000\$',
6: '300\$',
7: '2000\$',
8: '100\$',
};
RouletteScore(this.selected);
[@override](/user/override)
Widget build(BuildContext context) {
return Text('${labels[selected]}',
style: TextStyle(fontStyle: FontStyle.italic, fontSize: 24.0));
}
}
效果图:
示例代码
以下是完整的示例代码:
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_spinning_wheel/flutter_spinning_wheel.dart';
void main() {
SystemChrome.setEnabledSystemUIOverlays([]);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Container(
color: Color(0xffB0F9D2),
child: InkWell(
child: Center(child: Text('B A S I C')),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Basic()),
);
}),
),
),
Expanded(
child: Container(
color: Color(0xffDDC3FF),
child: InkWell(
child: Center(child: Text('R O U L E T T E')),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Roulette()),
);
}),
),
),
],
),
);
}
Widget buildNavigationButton({String text, Function onPressedFn}) {
return FlatButton(
color: Color.fromRGBO(255, 255, 255, 0.3),
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
onPressed: onPressedFn,
child: Text(
text,
style: TextStyle(color: Colors.white, fontSize: 18.0),
),
);
}
}
class Basic extends StatelessWidget {
final StreamController _dividerController = StreamController<int>();
dispose() {
_dividerController.close();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: Color(0xffB0F9D2), elevation: 0.0),
backgroundColor: Color(0xffB0F9D2),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SpinningWheel(
Image.asset('assets/images/wheel-6-300.png'),
width: 310,
height: 310,
initialSpinAngle: _generateRandomAngle(),
spinResistance: 0.2,
dividers: 6,
onUpdate: _dividerController.add,
onEnd: _dividerController.add,
),
StreamBuilder(
stream: _dividerController.stream,
builder: (context, snapshot) =>
snapshot.hasData ? BasicScore(snapshot.data) : Container(),
)
],
),
),
);
}
double _generateRandomAngle() => Random().nextDouble() * pi * 2;
}
class BasicScore extends StatelessWidget {
final int selected;
final Map<int, String> labels = {
1: 'Purple',
2: 'Magenta',
3: 'Red',
4: 'Dark Orange',
5: 'Light Orange',
6: 'Yellow',
};
BasicScore(this.selected);
[@override](/user/override)
Widget build(BuildContext context) {
return Text('${labels[selected]}',
style: TextStyle(fontStyle: FontStyle.italic));
}
}
class Roulette extends StatelessWidget {
final StreamController _dividerController = StreamController<int>();
final _wheelNotifier = StreamController<double>();
dispose() {
_dividerController.close();
_wheelNotifier.close();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: Color(0xffDDC3FF), elevation: 0.0),
backgroundColor: Color(0xffDDC3FF),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SpinningWheel(
Image.asset('assets/images/roulette-8-300.png'),
width: 310,
height: 310,
initialSpinAngle: _generateRandomAngle(),
spinResistance: 0.6,
canInteractWhileSpinning: false,
dividers: 8,
onUpdate: _dividerController.add,
onEnd: _dividerController.add,
secondaryImage: Image.asset('assets/images/roulette-center-300.png'),
secondaryImageHeight: 110,
secondaryImageWidth: 110,
shouldStartOrStop: _wheelNotifier.stream,
),
SizedBox(height: 30),
StreamBuilder(
stream: _dividerController.stream,
builder: (context, snapshot) =>
snapshot.hasData ? RouletteScore(snapshot.data) : Container(),
),
SizedBox(height: 30),
new RaisedButton(
child: new Text("Start"),
onPressed: () =>
_wheelNotifier.sink.add(_generateRandomVelocity()),
)
],
),
),
);
}
double _generateRandomVelocity() => (Random().nextDouble() * 6000) + 2000;
double _generateRandomAngle() => Random().nextDouble() * pi * 2;
}
class RouletteScore extends StatelessWidget {
final int selected;
final Map<int, String> labels = {
1: '1000\$',
2: '400\$',
3: '800\$',
4: '7000\$',
5: '5000\$',
6: '300\$',
7: '2000\$',
8: '100\$',
};
RouletteScore(this.selected);
[@override](/user/override)
Widget build(BuildContext context) {
return Text('${labels[selected]}',
style: TextStyle(fontStyle: FontStyle.italic, fontSize: 24.0));
}
}
更多关于Flutter旋转选择器插件flutter_spinning_wheel的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter旋转选择器插件flutter_spinning_wheel的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
flutter_spinning_wheel
是一个用于创建旋转选择器(类似于幸运大转盘)的 Flutter 插件。它允许你自定义旋转器的外观、旋转行为以及触发事件。以下是如何使用 flutter_spinning_wheel
的基本指南。
1. 添加依赖
首先,在你的 pubspec.yaml
文件中添加 flutter_spinning_wheel
依赖:
dependencies:
flutter:
sdk: flutter
flutter_spinning_wheel: ^1.0.0 # 请检查最新版本
然后运行 flutter pub get
来获取依赖。
2. 导入库
在你的 Dart 文件中导入 flutter_spinning_wheel
:
import 'package:flutter_spinning_wheel/flutter_spinning_wheel.dart';
3. 创建旋转选择器
你可以使用 SpinningWheel
小部件来创建一个旋转选择器。以下是一个简单的示例:
import 'package:flutter/material.dart';
import 'package:flutter_spinning_wheel/flutter_spinning_wheel.dart';
class SpinningWheelExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Spinning Wheel Example'),
),
body: Center(
child: SpinningWheel(
Image.asset('assets/wheel.png'), // 轮盘的图片
width: 300,
height: 300,
initialSpinAngle: 0,
spinResistance: 0.6,
canInteractWhileSpinning: false,
dividers: 8, // 轮盘的分割数量
onUpdate: (double angle) {
print('Current Angle: $angle');
},
onEnd: (double angle) {
print('Final Angle: $angle');
int selected = (angle / (360 / 8)).floor() % 8;
print('Selected: $selected');
},
),
),
);
}
}
4. 自定义旋转选择器
你可以通过以下参数来自定义旋转选择器:
- Image: 轮盘的图片。
- width 和 height: 轮盘的宽度和高度。
- initialSpinAngle: 初始旋转角度。
- spinResistance: 旋转阻力,值越大旋转越慢。
- canInteractWhileSpinning: 是否允许在旋转时进行交互。
- dividers: 轮盘的分割数量。
- onUpdate: 旋转时的回调,返回当前角度。
- onEnd: 旋转结束时的回调,返回最终角度。
5. 处理选择结果
在 onEnd
回调中,你可以根据最终角度计算出选择的选项。例如,如果轮盘有 8 个分割,每个分割的角度为 45 度,你可以通过以下方式计算选择的选项:
int selected = (angle / (360 / 8)).floor() % 8;