Flutter圆形滚动视图插件circle_scroll的使用

Flutter圆形滚动视图插件circle_scroll的使用

环境

sdk: '>=2.17.0 <3.0.0'
flutter: '>=2.5.0'

简介

CircleScrollAreaExpansion 是一个用于构建圆形滚动视图的 Flutter 小部件。用户可以通过它来创建坐标。

开始使用

以下是一个完整的示例,展示如何在 Flutter 应用中使用 circle_scroll 插件。

示例代码

import 'package:circle_scroll/circle_scroll_area_expansion.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return const MaterialApp(home: MyHomePage());
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  var _tex = '';
  var _initial = 0.0;
  var _distance = 0.0;
  final double _addAngle = 0.05;
  List<double> angleAnimationList = [0.0, 0.0];
  final List<double> _valueList = [
    0.4,
    0.45,
    0.5,
    0.55,
    0.6,
  ];
  final List<double> _valueList2 = [
    0.9,
    0.95,
    0.0,
    0.05,
    0.1,
  ];
  List<Offset> offSetList = [];
  List<Offset> offSetList2 = [];
  late AnimationController c;

  late Animation<double> _animation;

  final _widgetSize = 30.0;
  final animationValue = 500;

  [@override](/user/override)
  void initState() {
    super.initState();
    c = AnimationController(vsync: this)
      ..duration = Duration(milliseconds: animationValue)
      ..addListener(() {
        setState(() {
          if (c.isCompleted) {
            c.stop();
          }
        });
      })
      ..forward();
    _animation = Tween(
      begin: 0.0,
      end: 0.0,
    ).animate(c);
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    var w = MediaQuery.of(context).size.width;
    var h = MediaQuery.of(context).size.height;
    var t = TransformationController();
    t.value = TransformationController().value = Matrix4.identity()
      ..translate(-((h - w) / 2), 0);

    var t2 = TransformationController();
    t2.value = TransformationController().value = Matrix4.identity()
      ..translate(-((h - w) / 2), -h / 3);

    Size size = Size(w, h);
    return Scaffold(
      backgroundColor: const Color(0xFF616161),
      appBar: AppBar(
        title: const Text('EverDaySoft'),
        backgroundColor: Colors.black,
        actions: [
          IconButton(
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) {
                    return const Example();
                  },
                ),
              );
            },
            icon: const Icon(Icons.arrow_forward_ios),
          )
        ],
      ),
      body: Stack(
        children: [
          Container(
            height: MediaQuery.of(context).size.height,
            alignment: Alignment.topCenter,
            width: size.width,
            child: Text(
              _tex,
              style: const TextStyle(color: Colors.white, fontSize: 30),
              textAlign: TextAlign.center,
            ),
          ),
          _def(
            true,
            t,
            EdgeInsets.only(
              top: MediaQuery.of(context).size.height * 0.1,
            ),
            size,
            2.1,
            _widgetSize / 2,
            _valueList2,
          ),
          _def(
            false,
            t2,
            EdgeInsets.only(
              top: MediaQuery.of(context).size.height * 0.5,
            ),
            size,
            1,
            _widgetSize / 2,
            _valueList,
          ),
        ],
      ),
    );
  }

  Widget _abc(List<Offset> offsetList) {
    return Container(
      margin: const EdgeInsets.only(right: 0),
      width: 30,
      height: 30,
      decoration: const BoxDecoration(
        shape: BoxShape.circle,
        color: Colors.red,
      ),
    );
  }

  Widget _def(
    bool flg,
    TransformationController t,
    EdgeInsetsGeometry edgeInset,
    Size size,
    double aliment,
    double margin,
    List<double> valueList,
  ) {
    return Container(
      color: Colors.black,
      width: size.width,
      height: MediaQuery.of(context).size.height / 4,
      margin: edgeInset,
      child: Stack(
        children: [
          InteractiveViewer(
            constrained: false,
            panEnabled: false,
            transformationController: t,
            child: GestureDetector(
              behavior: HitTestBehavior.opaque,
              onPanStart: (DragStartDetails details) {
                setState(() {
                  _initial = details.globalPosition.dx;
                });
              },
              onPanUpdate: (details) {
                setState(() {
                  _distance = details.globalPosition.dx - _initial;
                });
              },
              onPanEnd: (DragEndDetails details) {
                setState(() {
                  _initial = 0.0;
                  switch (_distance.isNegative) {
                    case false:
                      angleAnimationList = [
                        angleAnimationList.last,
                        angleAnimationList.last - _addAngle
                      ];
                      break;
                    case true:
                      angleAnimationList = [
                        angleAnimationList.last,
                        angleAnimationList.last + _addAngle
                      ];
                      break;
                  }
                  _animation = Tween(
                    begin: angleAnimationList.first,
                    end: angleAnimationList.last,
                  ).chain(CurveTween(curve: Curves.slowMiddle)).animate(c);
                  c
                    ..duration = Duration(milliseconds: animationValue)
                    ..reset()
                    ..forward();
                });
              },
              child: Stack(
                children: [
                  CircleScrollAreaExpansion(
                    w: flg ? _abc(offSetList) : _abc(offSetList2),
                    color: Colors.white,
                    height: size.height,
                    aliment: aliment,
                    marginList: flg
                        ? [-_widgetSize, _widgetSize, _widgetSize]
                        : [_widgetSize, _widgetSize, _widgetSize],
                    valueList: valueList,
                    offSetList: flg ? offSetList : offSetList2,
                    animation: _animation,
                    call: (offsetValue) async {
                      if (offsetValue.length == 1) {
                        if (flg) {
                          offSetList = offsetValue.first as List<Offset>;
                        } else {
                          offSetList2 = offsetValue.first as List<Offset>;
                        }
                      } else {
                        setState(() {
                          if (flg) {
                            offSetList = offsetValue.first as List<Offset>;
                          } else {
                            offSetList2 = offsetValue.first as List<Offset>;
                          }
                          _tex = offsetValue.last.toString();
                        });
                      }
                    },
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

更多关于Flutter圆形滚动视图插件circle_scroll的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter圆形滚动视图插件circle_scroll的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用circle_scroll插件来实现圆形滚动视图的示例代码。这个插件允许你创建一个可以水平滚动的圆形视图,非常适合用于展示图片、图标或任何其他小部件。

首先,你需要在你的pubspec.yaml文件中添加circle_scroll依赖:

dependencies:
  flutter:
    sdk: flutter
  circle_scroll: ^x.y.z  # 替换为最新版本号

然后运行flutter pub get来安装依赖。

接下来是一个完整的Flutter应用程序示例,展示了如何使用circle_scroll

import 'package:flutter/material.dart';
import 'package:circle_scroll/circle_scroll.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Circle Scroll Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CircleScrollDemo(),
    );
  }
}

class CircleScrollDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final List<String> imageUrls = [
      'https://via.placeholder.com/150',
      'https://via.placeholder.com/150/00FF00',
      'https://via.placeholder.com/150/FF0000',
      'https://via.placeholder.com/150/0000FF',
      'https://via.placeholder.com/150/FFFF00',
      'https://via.placeholder.com/150/FF00FF',
    ];

    return Scaffold(
      appBar: AppBar(
        title: Text('Circle Scroll Demo'),
      ),
      body: Center(
        child: CircleScroll(
          itemCount: imageUrls.length,
          itemBuilder: (context, index) {
            return Container(
              margin: EdgeInsets.all(8.0),
              child: ClipRRect(
                borderRadius: BorderRadius.circular(8.0),
                child: Image.network(
                  imageUrls[index],
                  fit: BoxFit.cover,
                  width: 100,
                  height: 100,
                ),
              ),
            );
          },
          scrollPhysics: BouncingScrollPhysics(),
          autoScrollDurationInSeconds: 5.0,
          autoScroll: true,
        ),
      ),
    );
  }
}

代码说明

  1. 依赖添加:在pubspec.yaml文件中添加circle_scroll依赖。

  2. 导入包:在代码文件中导入circle_scroll包。

  3. 创建主应用MyApp类作为应用的入口,定义了主题和首页。

  4. 创建示例页面CircleScrollDemo类作为示例页面,包含了一个CircleScroll组件。

  5. 图像URL列表:定义了一个包含图像URL的列表imageUrls

  6. CircleScroll组件

    • itemCount:子项的数量。
    • itemBuilder:构建每个子项的回调,这里用于显示网络图片。
    • scrollPhysics:滚动物理效果,这里使用BouncingScrollPhysics实现弹性效果。
    • autoScrollDurationInSeconds:自动滚动的时间间隔(秒)。
    • autoScroll:是否启用自动滚动。

这个示例代码展示了如何使用circle_scroll插件来创建一个自动滚动的圆形视图,显示网络图片。你可以根据需要调整itemBuilder中的逻辑来显示其他类型的内容。

回到顶部