欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

flutter輪子計劃之進度條

 更新時間:2021年10月09日 17:09:27   作者:卡路里我的天敵  
這篇文章主要為大家詳細介紹了flutter輪子計劃之進度條,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

前言

本文的記錄如何用CustomPaint、GestureDetector實現(xiàn)一個進度條控件。首先需要說明的是 flutter Material 組件庫中提供了兩種進度指示器:LinearProgressIndicator和CircularProgressIndicator。如果這兩種進度指示器可以滿足開發(fā)需求,就不要嘗試自己造輪子了。本文實現(xiàn)的進度條控件,功能如下:

  • 進度的范圍為0到1的double類型數(shù)據(jù)
  • 支持拖動,通過回調(diào)函數(shù)獲取進度值
  • 支持跳轉(zhuǎn),點擊某個位置后進度跳轉(zhuǎn),回調(diào)進度值
  • 樣式為Material風格的樣式,可以根據(jù)需要修改

識別拖動手勢

使用GestureDetector可以方便得對滑動,點擊事件進行監(jiān)聽。如下是監(jiān)聽的四個事件,重點關(guān)注onHorizontalDragUpdate即可,其回調(diào)函數(shù)將水平拖動事件的坐標等信息傳遞給_seekToRelativePosition函數(shù)。_seekToRelativePosition函數(shù)的功能是計算滑動時進度條的值,并更新界面。代碼如下:

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 將全局坐標轉(zhuǎn)換為進度條控件所在的舉動坐標。將點擊處的橫坐標,即x與進度條控件的長度的比率作為進度條的值。然后調(diào)用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, 因為此進度條控件的狀態(tài)由其他控件和控件本身混合管理狀態(tài)。當其他控件想改變進度條的值時,可以通過VidoeProgressBarController通知進度條控件更新界面。當然,將進度條控件改用statelesswidget實現(xiàn),然后直接調(diào)用setState()更新界面實現(xiàn)起來會更簡單一點,讀者有需要可以嘗試。

使用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;
}

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論