纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

flutter进度条 flutter轮子计划之进度条

卡路里我的天敌   2021-10-09 我要评论
想了解flutter轮子计划之进度条的相关内容吗卡路里我的天敌在本文为您仔细讲解flutter进度条的相关知识和一些Code实例欢迎阅读和指正我们先划重点:flutter,进度条下面大家一起来学习吧

前言

本文的记录如何用CustomPaint、GestureDetector实现一个进度条控件首先需要说明的是 flutter Material 组件库中提供了两种进度指示器:LinearProgressIndicator和CircularProgressIndicator如果这两种进度指示器可以满足开发需求就不要尝试自己造轮子了本文实现的进度条控件功能如下:

  • 进度的范围为0到1的double类型数据
  • 支持拖动通过回调函数获取进度值
  • 支持跳转点击某个位置后进度跳转回调进度值
  • 样式为Material风格的样式可以根据需要修改

识别拖动手势

使用GestureDetector可以方便得对滑动点击事件进行监听如下是监听的四个事件重点关注onHorizontalDragUpdate即可,其回调函数将水平拖动事件的坐标等信息传递给_seekToRelativePosition函数_seekToRelativePosition函数的功能是计算滑动时进度条的值并更新界面代码如下:

GestureDetector(
        onHorizontalDragStart: (DragStartDetails details) {
          widget.onDragStart?.call();
        },
        onHorizontalDragUpdate: (DragUpdateDetails details) {
          widget.onDragUpdate?.call();
          _seekToRelativePosition(details.globalPosition);
        },
        onHorizontalDragEnd: (DragEndDetails details) {
          widget.onDragEnd?.call(progress);
        },
        onTapDown: (TapDownDetails details) {
          widget.onTapDown?.call(progress);
          _seekToRelativePosition(details.globalPosition);
        },
 
        // ....
 
)

_seekToRelativePosition 将全局坐标转换为进度条控件所在的举动坐标将点击处的横坐标即x与进度条控件的长度的比率作为进度条的值然后调用setState()更新界面上面

void _seekToRelativePosition(Offset globalPosition) {
    final box = context.findRenderObject()! as RenderBox;
    final Offset tapPos = box.globalToLocal(globalPosition);
    progress = tapPos.dx / box.size.width;
    if (progress < 0) progress = 0;
    if (progress > 1) progress = 1;
 
    setState(() {
        widget.controller.progressBarValue = progress;
    });
  } 

上面代码中有一个controller控件其定义如下:

class VideoProgressBarController extends ChangeNotifier
{
  double progressBarValue = .0;
 
   updateProgressValue(double value){
     progressBarValue = value;
    notifyListeners();
  }
}

其继承自ChangeNotifier 因为此进度条控件的状态由其他控件和控件本身混合管理状态当其他控件想改变进度条的值时可以通过VidoeProgressBarController通知进度条控件更新界面当然将进度条控件改用statelesswidget实现然后直接调用setState()更新界面实现起来会更简单一点读者有需要可以尝试

使用CustomPaint绘制进度条

绘制部分比较简单如下先绘制灰色背景然后绘制红色的进度再回事圆点

class _VideoProgressBarPainter extends CustomPainter {
  _VideoProgressBarPainter(
      {required this.barHeight,
      required this.handleHeight,
      required this.value,
      required this.colors});
 
  final double barHeight;
  final double handleHeight;
  final ProgressColors colors;
  final double value;
 
  @override
  bool shouldRepaint(CustomPainter painter) {
    return true;
  }
 
  @override
  void paint(Canvas canvas, Size size) {
    final baseOffset = size.height / 2 - barHeight / 2;
    final double radius = 4.0;
 
    canvas.drawRRect(
      RRect.fromRectAndRadius(
        Rect.fromPoints(
          Offset(0.0, baseOffset),
          Offset(size.width, baseOffset + barHeight),
        ),
        const Radius.circular(4.0),
      ),
      colors.backgroundPaint,
    );
 
    double playedPart =
        value > 1 ? size.width - radius : value * size.width - radius;
    if (playedPart < radius) {
      playedPart = radius;
    }
 
    canvas.drawRRect(
      RRect.fromRectAndRadius(
        Rect.fromPoints(
          Offset(0.0, baseOffset),
          Offset(playedPart, baseOffset + barHeight),
        ),
        Radius.circular(radius),
      ),
      colors.playedPaint,
    );
 
    canvas.drawCircle(
      Offset(playedPart, baseOffset + barHeight / 2),
      handleHeight,
      colors.playedPaint,
    );
  }
}

完整代码:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
 
void main() {
  runApp(MyApp());
}
 
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
 
class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);
 
  final String title;
 
  @override
  _MyHomePageState createState() => _MyHomePageState();
}
 
class _MyHomePageState extends State<MyHomePage> {
  double _progressValue = .5;
  late VideoProgressBarController controller;
 
  @override
  void initState() {
    controller = VideoProgressBarController();
    super.initState();
  }
 
  @override
  Widget build(BuildContext context) {
    print("build:$_progressValue");
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(title: Text("test")),
        body: Column(
            //aspectRatio: 16 / 9,
            children: [
              Container(
                width: 200,
                height: 26,
                //color: Colors.blue,
                child: VideoProgressBar(
                  controller: controller,
                  barHeight: 2,
                  onDragEnd: (double progress) {
                    print("$progress");
                  },
                ),
              ),
              Text("value:$_progressValue"),
              ElevatedButton(
                  onPressed: (){
                      _progressValue = 1;
                      controller.updateProgressValue(_progressValue);
                  },
                  child: Text("increase")
              )
            ]
        ),
      ),
    );
  }
}
 
/// progress bar
class VideoProgressBar extends StatefulWidget {
  VideoProgressBar({
    ProgressColors? colors,
    Key? key,
    required this.controller,
    required this.barHeight,
    this.handleHeight = 6,
    this.onDragStart,
    this.onDragEnd,
    this.onDragUpdate,
    this.onTapDown,
  })  : colors = colors ?? ProgressColors(),
        super(key: key);
 
  final ProgressColors colors;
  final Function()? onDragStart;
  final Function(double progress)? onDragEnd;
  final Function()? onDragUpdate;
  final Function(double progress)? onTapDown;
 
  final double barHeight;
  final double handleHeight;
 
  final TVideoProgressBarController controller;
 
  //final bool drawShadow;
 
  @override
  _VideoProgressBarState createState() => _VideoProgressBarState();
}
 
class _VideoProgressBarState extends State<VideoProgressBar> {
  double progress = .0;
 
  @override
  void initState() {
    super.initState();
    progress = widget.controller.progressBarValue;
    widget.controller.addListener(_updateProgressValue);
  }
 
  @override
  void dispose() {
    widget.controller.removeListener(_updateProgressValue);
    super.dispose();
  }
 
  _updateProgressValue()
  {
    setState(() {
      progress = widget.controller.progressBarValue;
    });
  }
 
  void _seekToRelativePosition(Offset globalPosition) {
    final box = context.findRenderObject()! as RenderBox;
    final Offset tapPos = box.globalToLocal(globalPosition);
    progress = tapPos.dx / box.size.width;
    if (progress < 0) progress = 0;
    if (progress > 1) progress = 1;
 
    setState(() {
        widget.controller.progressBarValue = progress;
    });
  }
 
  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
 
    return GestureDetector(
        onHorizontalDragStart: (DragStartDetails details) {
          widget.onDragStart?.call();
        },
        onHorizontalDragUpdate: (DragUpdateDetails details) {
          widget.onDragUpdate?.call();
          _seekToRelativePosition(details.globalPosition);
        },
        onHorizontalDragEnd: (DragEndDetails details) {
          widget.onDragEnd?.call(progress);
        },
        onTapDown: (TapDownDetails details) {
          widget.onTapDown?.call(progress);
          _seekToRelativePosition(details.globalPosition);
        },
        child: Center(
          child: Container(
            height: MediaQuery.of(context).size.height,
            width: MediaQuery.of(context).size.width,
            child: CustomPaint(
                painter: _VideoProgressBarPainter(
                    barHeight: widget.barHeight,
                    handleHeight: widget.handleHeight,
                    colors: widget.colors,
                    value: progress)),
          ),
        ));
  }
}
 
class _VideoProgressBarPainter extends CustomPainter {
  _VideoProgressBarPainter(
      {required this.barHeight,
      required this.handleHeight,
      required this.value,
      required this.colors});
 
  final double barHeight;
  final double handleHeight;
  final ProgressColors colors;
  final double value;
 
  @override
  bool shouldRepaint(CustomPainter painter) {
    return true;
  }
 
  @override
  void paint(Canvas canvas, Size size) {
    final baseOffset = size.height / 2 - barHeight / 2;
    final double radius = 4.0;
 
    canvas.drawRRect(
      RRect.fromRectAndRadius(
        Rect.fromPoints(
          Offset(0.0, baseOffset),
          Offset(size.width, baseOffset + barHeight),
        ),
        const Radius.circular(4.0),
      ),
      colors.backgroundPaint,
    );
 
    double playedPart =
        value > 1 ? size.width - radius : value * size.width - radius;
    if (playedPart < radius) {
      playedPart = radius;
    }
 
    canvas.drawRRect(
      RRect.fromRectAndRadius(
        Rect.fromPoints(
          Offset(0.0, baseOffset),
          Offset(playedPart, baseOffset + barHeight),
        ),
        Radius.circular(radius),
      ),
      colors.playedPaint,
    );
 
    canvas.drawCircle(
      Offset(playedPart, baseOffset + barHeight / 2),
      handleHeight,
      colors.playedPaint,
    );
  }
}
 
class VideoProgressBarController extends ChangeNotifier
{
  double progressBarValue = .0;
 
   updateProgressValue(double value){
     progressBarValue = value;
    notifyListeners();
  }
}
 
class ProgressColors {
  ProgressColors({
    Color playedColor = const Color.fromRGBO(255, 0, 0, 0.7),
    Color bufferedColor = const Color.fromRGBO(30, 30, 200, 0.2),
    Color handleColor = const Color.fromRGBO(200, 200, 200, 1.0),
    Color backgroundColor = const Color.fromRGBO(200, 200, 200, 0.5),
  })  : playedPaint = Paint()..color = playedColor,
        bufferedPaint = Paint()..color = bufferedColor,
        handlePaint = Paint()..color = handleColor,
        backgroundPaint = Paint()..color = backgroundColor;
 
  final Paint playedPaint;
  final Paint bufferedPaint;
  final Paint handlePaint;
  final Paint backgroundPaint;
}

相关文章

猜您喜欢

网友评论

Copyright 2020 www.fresh-weather.com 【世纪下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式