日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

flutter 图解_【Flutter 专题】83 图解自定义 ACEWave 波浪 Widget (一)

發(fā)布時(shí)間:2024/7/5 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 flutter 图解_【Flutter 专题】83 图解自定义 ACEWave 波浪 Widget (一) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

? ? ? 和尚今天嘗試一下繪制波浪的效果,雖然 pub 倉庫中已經(jīng)有成熟的插件,但和尚還是準(zhǔn)備用之前學(xué)習(xí)的 CanvasAnimation 嘗試自定義一個(gè) ACEWave

1. 繪制曲線

??????繪制波浪首先需要繪制曲線,采用 Canvas 繪制貝塞爾曲線;常用的是數(shù)學(xué)中通常用的 sin(x) / cos(y) 函數(shù)即可;

??????其中和尚通過 Canvas 繪制時(shí)使用了 path.quadraticBezierTo 來繪制從第一個(gè) Point 到另一個(gè) Point 的貝塞爾曲線;

class?_ACEWavePainter?extends?CustomPainter?{
??@override
??void?paint(Canvas?canvas,?Size?size)?{
????Paint?paint?=?Paint()
??????..color?=?Colors.red..strokeCap?=?StrokeCap.round
??????..strokeWidth?=?10..style?=?PaintingStyle.stroke;
????Path?path?=?Path()
??????..moveTo(0,?500)
??????..quadraticBezierTo(size.width?/?4,?300,?size.width?/?2,?500)
??????..quadraticBezierTo(size.width?/?4?*?3,?700,?size.width,?500);
????canvas.drawPath(path,?paint);
??}

??@override
??bool?shouldRepaint(CustomPainter?oldDelegate)?=>?false;
}

2. 循環(huán)動畫

??????和尚使用最常用的平移動畫來讓曲線動起來,其中注意的是:

  • 當(dāng)?shù)谝淮蝿赢嫿Y(jié)束時(shí),通過 controller.repeat() 來實(shí)現(xiàn)循環(huán)播放;

  • 動畫需要使用 Curves.linear 線性動畫,否則在循環(huán)播放過程中銜接不順暢;

  • 使用動畫時(shí)均需在生命周期結(jié)束時(shí) dispose() 銷毀動畫;

  • class?_ACEWaveState?extends?State<ACEWave>?with?TickerProviderStateMixin?{
    ??AnimationController?_waveController;
    ??Animation<double>?_waveAnimation;
    ??int?_duration?=?2000;
    ??CurvedAnimation?_curvedAnimation;

    ??@override
    ??Widget?build(BuildContext?context)?{
    ????return?Transform.translate(
    ????????offset:?Offset(MediaQuery.of(context).size.width?*?_curvedAnimation.value,?0.0),
    ????????child:?Container(width:?MediaQuery.of(context).size.width,
    ????????????child:?CustomPaint(painter:?_ACEWavePainter())));
    ??}

    ??_initAnimations()?{
    ????_waveController?=?AnimationController(duration:?Duration(milliseconds:?_duration),?vsync:?this);
    ????_curvedAnimation?=?CurvedAnimation(parent:?_waveController,?curve:?Curves.linear);
    ????_waveAnimation?=?Tween(begin:?0.0,?end:?1.0).animate(_waveController);
    ????_waveAnimation.addListener(()?=>?setState(()?{}));
    ????_waveController.forward();
    ????_waveAnimation.addStatusListener((status)?{
    ??????switch?(status)?{
    ????????case?AnimationStatus.completed:
    ??????????_waveController.repeat();
    ??????????break;
    ????????case?AnimationStatus.dismissed:
    ??????????_waveController.forward();
    ??????????break;
    ????????default:
    ??????????break;
    ??????}
    ????});
    ??}

    ??_disposeAnimations()?{
    ????_waveController.dispose();
    ??}

    ??@override
    ??void?initState()?{
    ????super.initState();
    ????_initAnimations();
    ??}

    ??@override
    ??void?dispose()?{
    ????_disposeAnimations();
    ????super.dispose();
    ??}
    }

    3. 增加波浪周期

    ??????在執(zhí)行循環(huán)動畫之后,發(fā)現(xiàn)動畫過程中,會有一半是空白的,此時(shí)我們增加波浪的周期即可,多繪制一個(gè)屏幕的波浪即可,和尚建議前后多繪制兩個(gè)屏幕的曲線,在循環(huán)過程中更流暢;

    Path?path?=?Path()
    ??..moveTo(0?-?size.width,?500)
    ??..quadraticBezierTo(size.width?/?4?-?size.width,?300,?size.width?/?2?-?size.width,?500)
    ??..quadraticBezierTo(size.width?/?4?*?3?-?size.width,?700,?size.width?-?size.width,?500)
    ??..quadraticBezierTo(size.width?/?4,?300,?size.width?/?2,?500)
    ??..quadraticBezierTo(size.width?/?4?*?3,?700,?size.width,?500);

    canvas.drawPath(path,?paint);

    4. 調(diào)整波浪起始位置

    ??????和尚嘗試的曲線是 sin(x) 方式的,起始位置都是 (0.0, 0.0),然而多條波浪時(shí)不會都從起點(diǎn)開始;于是和尚提供了一個(gè)初始位置,來錯(cuò)開各波浪展示位置;

    Path?path?=?Path()
    ??..moveTo(0?-?size.width?-?startOffset,?500)
    ??..quadraticBezierTo(size.width?/?4?-?size.width?-?startOffset,
    ??????500?-?waveHeight,?size.width?/?2?-?size.width?-?startOffset,?500)
    ??..quadraticBezierTo(size.width?/?4?*?3?-?size.width?-?startOffset,
    ??????500?+?waveHeight,?size.width?-?size.width?-?startOffset,?500)
    ??..quadraticBezierTo(size.width?/?4?-?startOffset,?500?-?waveHeight,
    ??????size.width?/?2?-?startOffset,?500)
    ??..quadraticBezierTo(size.width?/?4?*?3?-?startOffset,?500?+?waveHeight,
    ??????size.width?-?startOffset,?500)
    ??..quadraticBezierTo(size.width?/?4?+?size.width?-?startOffset,
    ??????500?-?waveHeight,?size.width?/?2?+?size.width?-?startOffset,?500)
    ??..quadraticBezierTo(size.width?/?4?*?3?+?size.width?-?startOffset,
    ??????500?+?waveHeight,?size.width?+?size.width?-?startOffset,?500);

    5. 調(diào)整波浪寬度和峰值

    ??????和尚調(diào)整完波浪起始位置之后對于波浪的寬度和峰值也要進(jìn)行調(diào)整,保證每條波浪效果略有不同;

    ??????和尚預(yù)先繪制了前中后三個(gè)屏幕曲線,在測試過程中,若屏幕并非是曲線周期倍數(shù)時(shí),銜接過程中會有空余,如圖;

    ??????于是和尚計(jì)算波浪完整周期倍數(shù)與屏幕寬的差值作為移動點(diǎn) moveTo 的附加寬度即可;

    for?(int?i?=?0;?i???path..moveTo(waveWidth?*?i?-?size.width?-?startOffset,?500.0)
    ????..quadraticBezierTo(
    ????????_quaterWidth?+?waveWidth?*?i?-?size.width?-?startOffset,
    ????????500?-?waveHeight,
    ????????_quaterWidth?*?2?+?waveWidth?*?i?-?size.width?-?startOffset,
    ????????500.0)
    ????..moveTo(
    ????????_quaterWidth?*?2?+?waveWidth?*?i?-?size.width?-?startOffset,?500.0)
    ????..quadraticBezierTo(
    ????????_quaterWidth?*?3?+?waveWidth?*?i?-?size.width?-?startOffset,
    ????????500?+?waveHeight,
    ????????_quaterWidth?*?4?+?waveWidth?*?i?-?size.width?-?startOffset,
    ????????500.0)
    ????..moveTo(waveWidth?*?i?+?startOffset?+?(plusWidth),?500.0)
    ????..quadraticBezierTo(
    ????????_quaterWidth?+?waveWidth?*?i?+?startOffset?+?plusWidth,
    ????????500?-?waveHeight,
    ????????_quaterWidth?*?2?+?waveWidth?*?i?+?startOffset?+?plusWidth,
    ????????500.0)
    ????..moveTo(
    ????????_quaterWidth?*?2?+?waveWidth?*?i?+?startOffset?+?plusWidth,?500.0)
    ????..quadraticBezierTo(
    ????????_quaterWidth?*?3?+?waveWidth?*?i?+?startOffset?+?plusWidth,
    ????????500?+?waveHeight,
    ????????_quaterWidth?*?4?+?waveWidth?*?i?+?startOffset?+?plusWidth,
    ????????500.0)
    ????..moveTo(waveWidth?*?i?-?size.width?+?startOffset,?500.0)
    ????..quadraticBezierTo(
    ????????_quaterWidth?+?waveWidth?*?i?-?size.width?+?startOffset,
    ????????500?-?waveHeight,
    ????????_quaterWidth?*?2?+?waveWidth?*?i?-?size.width?+?startOffset,
    ????????500.0)
    ????..moveTo(
    ????????_quaterWidth?*?2?+?waveWidth?*?i?-?size.width?+?startOffset,?500.0)
    ????..quadraticBezierTo(
    ????????_quaterWidth?*?3?+?waveWidth?*?i?-?size.width?+?startOffset,
    ????????500?+?waveHeight,
    ????????_quaterWidth?*?4?+?waveWidth?*?i?-?size.width?+?startOffset,
    ????????500.0);
    }


    ??????至此,一個(gè)基本的波浪模型基本完成,但還有很多優(yōu)化的方面,和尚在下篇中進(jìn)一步繪制波浪效果;如有錯(cuò)誤,請多多指導(dǎo)!

    來源:阿策小和尚

    總結(jié)

    以上是生活随笔為你收集整理的flutter 图解_【Flutter 专题】83 图解自定义 ACEWave 波浪 Widget (一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。