国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Flutter(九)Flutter動(dòng)畫(huà)和自定義組件

這篇具有很好參考價(jià)值的文章主要介紹了Flutter(九)Flutter動(dòng)畫(huà)和自定義組件。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

1.動(dòng)畫(huà)簡(jiǎn)介

Animation、Curve、Controller、Tween這四個(gè)角色,它們一起配合來(lái)完成一個(gè)完整動(dòng)畫(huà)

  • Animation
    Animation是抽象類,和UI渲染沒(méi)有關(guān)系,功能是保存動(dòng)畫(huà)的插值和狀態(tài);比較常用的是Animation
    addListener:幀監(jiān)聽(tīng)器中最常見(jiàn)的行為是改變狀態(tài)后調(diào)用setState()來(lái)觸發(fā)UI重建
    addStatusListener:動(dòng)畫(huà)開(kāi)始、結(jié)束、正向或反向(見(jiàn)AnimationStatus定義)時(shí)會(huì)調(diào)用狀態(tài)改變的監(jiān)聽(tīng)器。
  • Curve
    動(dòng)畫(huà)過(guò)程可以是勻速的、勻加速的或者先加速后減速等。Flutter中通過(guò)Curve(曲線)來(lái)描述動(dòng)畫(huà)過(guò)程,我們把勻速動(dòng)畫(huà)稱為線性的(Curves.linear),而非勻速動(dòng)畫(huà)稱為非線性的。
final CurvedAnimation curve =
    CurvedAnimation(parent: controller, curve: Curves.easeIn);

Curves曲線 動(dòng)畫(huà)過(guò)程
linear 勻速的
decelerate 勻減速
ease 開(kāi)始加速,后面減速
easeIn 開(kāi)始慢,后面快
easeOut 開(kāi)始快,后面慢
easeInOut 開(kāi)始慢,然后加速,最后再減速

也可以自定義一個(gè)正弦曲線:

class ShakeCurve extends Curve {
  @override
  double transform(double t) {
    return math.sin(t * math.PI * 2);
  }
}
  • AnimationController
    AnimationController用于控制動(dòng)畫(huà),它包含動(dòng)畫(huà)的啟動(dòng)forward()、停止stop() 、反向播放 reverse()等
final AnimationController controller = AnimationController( 
 duration: const Duration(milliseconds: 2000), 
 lowerBound: 10.0,
 upperBound: 20.0,
 vsync: this
);
  • Tween
    默認(rèn)AnimationController對(duì)象值的范圍是[0.0,1.0],但可以使用Tween來(lái)改變范圍
    例如,像下面示例,Tween生成[-200.0,0.0]的值
final Tween doubleTween = Tween<double>(begin: -200.0, end: 0.0);

完整示例:
以下示例構(gòu)建了一個(gè)控制器、一條曲線和一個(gè) Tween:

final AnimationController controller = AnimationController(
  duration: const Duration(milliseconds: 500), 
  vsync: this,
);
final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut);
Animation<int> alpha = IntTween(begin: 0, end: 255).animate(curve);

線性插值lerp函數(shù):

//a 為起始顏色,b為終止顏色,t為當(dāng)前動(dòng)畫(huà)的進(jìn)度[0,1]
Color.lerp(a, b, t);

2.動(dòng)畫(huà)實(shí)現(xiàn)和監(jiān)聽(tīng)

AnimatedBuilder可以封裝常見(jiàn)的過(guò)渡效果來(lái)復(fù)用動(dòng)畫(huà)

class GrowTransition extends StatelessWidget {
  const GrowTransition({Key? key,
    required this.animation,
    this.child,
  }) : super(key: key);

  final Widget? child;
  final Animation<double> animation;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: AnimatedBuilder(
        animation: animation,
        builder: (BuildContext context, child) {
          return SizedBox(
            height: animation.value,
            width: animation.value,
            child: child,
          );
        },
        child: child,
      ),
    );
  }
}
...
Widget build(BuildContext context) {
  return GrowTransition(
    child: Image.asset("images/avatar.png"), 
    animation: animation,
  );
}

Flutter中正是通過(guò)這種方式封裝了很多動(dòng)畫(huà),如:FadeTransition、ScaleTransition、SizeTransition等,很多時(shí)候都可以復(fù)用這些預(yù)置的過(guò)渡類

Animation的addStatusListener()方法來(lái)添加動(dòng)畫(huà)狀態(tài)改變監(jiān)聽(tīng)器。Flutter中,有四種動(dòng)畫(huà)狀態(tài),在AnimationStatus枚舉類中定義
dismissed 動(dòng)畫(huà)在起始點(diǎn)停止
forward 動(dòng)畫(huà)正在正向執(zhí)行
reverse 動(dòng)畫(huà)正在反向執(zhí)行
completed 動(dòng)畫(huà)在終點(diǎn)停止

3. 自定義路由切換動(dòng)畫(huà)

無(wú)論是MaterialPageRoute、CupertinoPageRoute,還是PageRouteBuilder,它們都繼承自PageRoute

MaterialPageRoute組件,它可以使用和平臺(tái)風(fēng)格一致的路由切換動(dòng)畫(huà),如在iOS上會(huì)左右滑動(dòng)切換,而在Android上會(huì)上下滑動(dòng)切換

CupertinoPageRoute是Cupertino組件庫(kù)提供的iOS風(fēng)格的路由切換組件,它實(shí)現(xiàn)的就是左右滑動(dòng)切換。

自定義切換動(dòng)畫(huà)優(yōu)先考慮使用PageRouteBuilder

Navigator.push(
  context,
  PageRouteBuilder(
    transitionDuration: Duration(milliseconds: 500), //動(dòng)畫(huà)時(shí)間為500毫秒
    pageBuilder: (BuildContext context, Animation animation,
        Animation secondaryAnimation) {
      return FadeTransition(
        //使用漸隱漸入過(guò)渡,
        opacity: animation,
        child: PageB(), //路由B
      );
    },
  ),
);

但是有些時(shí)候PageRouteBuilder是不能滿足需求的,例如在應(yīng)用過(guò)渡動(dòng)畫(huà)時(shí)我們需要讀取當(dāng)前路由的一些屬性,這時(shí)就只能通過(guò)繼承PageRoute的方式了

@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
    Animation<double> secondaryAnimation, Widget child) {
 //當(dāng)前路由被激活,是打開(kāi)新路由
 if(isActive) {
   return FadeTransition(
     opacity: animation,
     child: builder(context),
   );
 }else{
   //是返回,則不應(yīng)用過(guò)渡動(dòng)畫(huà)
   return Padding(padding: EdgeInsets.zero);
 }
}

4. Hero動(dòng)畫(huà)

在Flutter中將圖片從一個(gè)路由“飛”到另一個(gè)路由稱為hero動(dòng)畫(huà)

例如A路由有一個(gè)圓形用戶頭像,點(diǎn)擊后跳到B路由,可以查看大圖

class HeroAnimationRouteA extends StatelessWidget {
  const HeroAnimationRouteA({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.topCenter,
      child: Column(
        children: <Widget>[
          InkWell(
            child: Hero(
              tag: "avatar", //唯一標(biāo)記,前后兩個(gè)路由頁(yè)Hero的tag必須相同
              child: ClipOval(
                child: Image.asset(
                  "imgs/avatar.png",
                  width: 50.0,
                ),
              ),
            ),
            onTap: () {
              //打開(kāi)B路由
              Navigator.push(context, PageRouteBuilder(
                pageBuilder: (
                  BuildContext context,
                  animation,
                  secondaryAnimation,
                ) {
                  return FadeTransition(
                    opacity: animation,
                    child: Scaffold(
                      appBar: AppBar(
                        title: const Text("原圖"),
                      ),
                      body: const HeroAnimationRouteB(),
                    ),
                  );
                },
              ));
            },
          ),
          const Padding(
            padding: EdgeInsets.only(top: 8.0),
            child: Text("點(diǎn)擊頭像"),
          )
        ],
      ),
    );
  }
}
class HeroAnimationRouteB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Hero(
        tag: "avatar", //唯一標(biāo)記,前后兩個(gè)路由頁(yè)Hero的tag必須相同
        child: Image.asset("imgs/avatar.png"),
      ),
    );
  }
}

實(shí)現(xiàn) Hero 動(dòng)畫(huà)只需要用Hero組件將要共享的 widget 包裝起來(lái),并提供一個(gè)相同的 tag 即可

5.交織動(dòng)畫(huà)

比如:有一個(gè)柱狀圖,需要在高度增長(zhǎng)的同時(shí)改變顏色,等到增長(zhǎng)到最大高度后,我們需要在X軸上平移一段距離??梢园l(fā)現(xiàn)上述場(chǎng)景在不同階段包含了多種動(dòng)畫(huà),要實(shí)現(xiàn)這種效果,使用交織動(dòng)畫(huà)(Stagger Animation)會(huì)非常簡(jiǎn)單
實(shí)現(xiàn)步驟:
1.要?jiǎng)?chuàng)建交織動(dòng)畫(huà),需要使用多個(gè)動(dòng)畫(huà)對(duì)象(Animation)。
2.一個(gè)AnimationController控制所有的動(dòng)畫(huà)對(duì)象。
3.給每一個(gè)動(dòng)畫(huà)對(duì)象指定時(shí)間間隔(Interval)

class StaggerAnimation extends StatelessWidget {
  StaggerAnimation({
    Key? key,
    required this.controller,
  }) : super(key: key) {
    //高度動(dòng)畫(huà)
    height = Tween<double>(
      begin: .0,
      end: 300.0,
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: const Interval(
          0.0, 0.6, //間隔,前60%的動(dòng)畫(huà)時(shí)間
          curve: Curves.ease,
        ),
      ),
    );

    color = ColorTween(
      begin: Colors.green,
      end: Colors.red,
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: const Interval(
          0.0, 0.6, //間隔,前60%的動(dòng)畫(huà)時(shí)間
          curve: Curves.ease,
        ),
      ),
    );

    padding = Tween<EdgeInsets>(
      begin: const EdgeInsets.only(left: .0),
      end: const EdgeInsets.only(left: 100.0),
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: const Interval(
          0.6, 1.0, //間隔,后40%的動(dòng)畫(huà)時(shí)間
          curve: Curves.ease,
        ),
      ),
    );
  }

  late final Animation<double> controller;
  late final Animation<double> height;
  late final Animation<EdgeInsets> padding;
  late final Animation<Color?> color;

  Widget _buildAnimation(BuildContext context, child) {
    return Container(
      alignment: Alignment.bottomCenter,
      padding: padding.value,
      child: Container(
        color: color.value,
        width: 50.0,
        height: height.value,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      builder: _buildAnimation,
      animation: controller,
    );
  }
}

StaggerAnimation中定義了三個(gè)動(dòng)畫(huà),分別是對(duì)Container的height、color、padding屬性設(shè)置的動(dòng)畫(huà),然后通過(guò)Interval來(lái)為每個(gè)動(dòng)畫(huà)指定在整個(gè)動(dòng)畫(huà)過(guò)程中的起始點(diǎn)和終點(diǎn)

使用:

class StaggerRoute extends StatefulWidget {
  @override
  _StaggerRouteState createState() => _StaggerRouteState();
}

class _StaggerRouteState extends State<StaggerRoute>
    with TickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(
      duration: const Duration(milliseconds: 2000),
      vsync: this,
    );
  }

  _playAnimation() async {
    try {
      //先正向執(zhí)行動(dòng)畫(huà)
      await _controller.forward().orCancel;
      //再反向執(zhí)行動(dòng)畫(huà)
      await _controller.reverse().orCancel;
    } on TickerCanceled {
      //捕獲異常??赡馨l(fā)生在組件銷毀時(shí),計(jì)時(shí)器會(huì)被取消。
    }
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: [
          ElevatedButton(
            onPressed: () => _playAnimation(),
            child: Text("start animation"),
          ),
          Container(
            width: 300.0,
            height: 300.0,
            decoration: BoxDecoration(
              color: Colors.black.withOpacity(0.1),
              border: Border.all(
                color: Colors.black.withOpacity(0.5),
              ),
            ),
            //調(diào)用我們定義的交錯(cuò)動(dòng)畫(huà)Widget
            child: StaggerAnimation(controller: _controller),
          ),
        ],
      ),
    );
  }
}

Flutter(九)Flutter動(dòng)畫(huà)和自定義組件,Flutter,flutter

6.動(dòng)畫(huà)切換

AnimatedSwitcher組件,它定義了一種通用的UI切換抽象

const AnimatedSwitcher({
  Key? key,
  this.child,
  required this.duration, // 新child顯示動(dòng)畫(huà)時(shí)長(zhǎng)
  this.reverseDuration,// 舊child隱藏的動(dòng)畫(huà)時(shí)長(zhǎng)
  this.switchInCurve = Curves.linear, // 新child顯示的動(dòng)畫(huà)曲線
  this.switchOutCurve = Curves.linear,// 舊child隱藏的動(dòng)畫(huà)曲線
  this.transitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, // 動(dòng)畫(huà)構(gòu)建器
  this.layoutBuilder = AnimatedSwitcher.defaultLayoutBuilder, //布局構(gòu)建器
})

當(dāng)AnimatedSwitcher的 child 發(fā)生變化時(shí)(類型或 Key 不同),舊 child 會(huì)執(zhí)行隱藏動(dòng)畫(huà),新 child 會(huì)執(zhí)行執(zhí)行顯示動(dòng)畫(huà)。究竟執(zhí)行何種動(dòng)畫(huà)效果則由transitionBuilder參數(shù)決定,該參數(shù)接受一個(gè)AnimatedSwitcherTransitionBuilder類型的 builder

typedef AnimatedSwitcherTransitionBuilder =
  Widget Function(Widget child, Animation<double> animation);

defaultTransitionBuilder :默認(rèn)AnimatedSwitcher會(huì)對(duì)新舊child執(zhí)行“漸隱”和“漸顯”動(dòng)畫(huà)

現(xiàn)一個(gè)計(jì)數(shù)器,然后在每一次自增的過(guò)程中,舊數(shù)字執(zhí)行縮小動(dòng)畫(huà)隱藏,新數(shù)字執(zhí)行放大動(dòng)畫(huà)顯示

import 'package:flutter/material.dart';

class AnimatedSwitcherCounterRoute extends StatefulWidget {
   const AnimatedSwitcherCounterRoute({Key key}) : super(key: key);

   @override
   _AnimatedSwitcherCounterRouteState createState() => _AnimatedSwitcherCounterRouteState();
 }

 class _AnimatedSwitcherCounterRouteState extends State<AnimatedSwitcherCounterRoute> {
   int _count = 0;

   @override
   Widget build(BuildContext context) {
     return Center(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         children: <Widget>[
           AnimatedSwitcher(
             duration: const Duration(milliseconds: 500),
             transitionBuilder: (Widget child, Animation<double> animation) {
               //執(zhí)行縮放動(dòng)畫(huà)
               return ScaleTransition(child: child, scale: animation);
             },
             child: Text(
               '$_count',
               //顯示指定key,不同的key會(huì)被認(rèn)為是不同的Text,這樣才能執(zhí)行動(dòng)畫(huà)
               key: ValueKey<int>(_count),
               style: Theme.of(context).textTheme.headline4,
             ),
           ),
           ElevatedButton(
             child: const Text('+1',),
             onPressed: () {
               setState(() {
                 _count += 1;
               });
             },
           ),
         ],
       ),
     );
   }
 }

Flutter(九)Flutter動(dòng)畫(huà)和自定義組件,Flutter,flutter
Flutter SDK中還提供了一個(gè)AnimatedCrossFade組件,它也可以切換兩個(gè)子元素,切換過(guò)程執(zhí)行漸隱漸顯的動(dòng)畫(huà),和AnimatedSwitcher不同的是AnimatedCrossFade是針對(duì)兩個(gè)子元素,而AnimatedSwitcher是在一個(gè)子元素的新舊值之間切換

示例:實(shí)現(xiàn)各種“滑動(dòng)出入動(dòng)畫(huà)”便非常容易,只需給direction傳遞不同的方向值即可

class SlideTransitionX extends AnimatedWidget {
  SlideTransitionX({
    Key? key,
    required Animation<double> position,
    this.transformHitTests = true,
    this.direction = AxisDirection.down,
    required this.child,
  }) : super(key: key, listenable: position) {
    switch (direction) {
      case AxisDirection.up:
        _tween = Tween(begin: const Offset(0, 1), end: const Offset(0, 0));
        break;
      case AxisDirection.right:
        _tween = Tween(begin: const Offset(-1, 0), end: const Offset(0, 0));
        break;
      case AxisDirection.down:
        _tween = Tween(begin: const Offset(0, -1), end: const Offset(0, 0));
        break;
      case AxisDirection.left:
        _tween = Tween(begin: const Offset(1, 0), end: const Offset(0, 0));
        break;
    }
  }

  final bool transformHitTests;

  final Widget child;

  final AxisDirection direction;

  late final Tween<Offset> _tween;

  @override
  Widget build(BuildContext context) {
    final position = listenable as Animation<double>;
    Offset offset = _tween.evaluate(position);
    if (position.status == AnimationStatus.reverse) {
      switch (direction) {
        case AxisDirection.up:
          offset = Offset(offset.dx, -offset.dy);
          break;
        case AxisDirection.right:
          offset = Offset(-offset.dx, offset.dy);
          break;
        case AxisDirection.down:
          offset = Offset(offset.dx, -offset.dy);
          break;
        case AxisDirection.left:
          offset = Offset(-offset.dx, offset.dy);
          break;
      }
    }
    return FractionalTranslation(
      translation: offset,
      transformHitTests: transformHitTests,
      child: child,
    );
  }
}
AnimatedSwitcher(
  duration: Duration(milliseconds: 200),
  transitionBuilder: (Widget child, Animation<double> animation) {
    var tween=Tween<Offset>(begin: Offset(1, 0), end: Offset(0, 0))
     return SlideTransitionX(
       child: child,
       direction: AxisDirection.down, //上入下出
       position: animation,
     );
  },
  ...//省略其余代碼
)

Flutter(九)Flutter動(dòng)畫(huà)和自定義組件,Flutter,flutter

7.Flutter預(yù)置的動(dòng)畫(huà)過(guò)渡組件

AnimatedPadding 在padding發(fā)生變化時(shí)會(huì)執(zhí)行過(guò)渡動(dòng)畫(huà)到新?tīng)顟B(tài)
AnimatedPositioned 配合Stack一起使用,當(dāng)定位狀態(tài)發(fā)生變化時(shí)會(huì)執(zhí)行過(guò)渡動(dòng)畫(huà)到新的狀態(tài)。
AnimatedOpacity 在透明度opacity發(fā)生變化時(shí)執(zhí)行過(guò)渡動(dòng)畫(huà)到新?tīng)顟B(tài)
AnimatedAlign 當(dāng)alignment發(fā)生變化時(shí)會(huì)執(zhí)行過(guò)渡動(dòng)畫(huà)到新的狀態(tài)。
AnimatedContainer 當(dāng)Container屬性發(fā)生變化時(shí)會(huì)執(zhí)行過(guò)渡動(dòng)畫(huà)到新的狀態(tài)。
AnimatedDefaultTextStyle 當(dāng)字體樣式發(fā)生變化時(shí),子組件中繼承了該樣式的文本組件會(huì)動(dòng)態(tài)過(guò)渡到新樣式。

import 'package:flutter/material.dart';

class AnimatedWidgetsTest extends StatefulWidget {
  const AnimatedWidgetsTest({Key? key}) : super(key: key);

  @override
  _AnimatedWidgetsTestState createState() => _AnimatedWidgetsTestState();
}

class _AnimatedWidgetsTestState extends State<AnimatedWidgetsTest> {
  double _padding = 10;
  var _align = Alignment.topRight;
  double _height = 100;
  double _left = 0;
  Color _color = Colors.red;
  TextStyle _style = const TextStyle(color: Colors.black);
  Color _decorationColor = Colors.blue;
  double _opacity = 1;

  @override
  Widget build(BuildContext context) {
    var duration = const Duration(milliseconds: 400);
    return SingleChildScrollView(
      child: Column(
        children: <Widget>[
          ElevatedButton(
            onPressed: () {
              setState(() {
                _padding = 20;
              });
            },
            child: AnimatedPadding(
              duration: duration,
              padding: EdgeInsets.all(_padding),
              child: const Text("AnimatedPadding"),
            ),
          ),
          SizedBox(
            height: 50,
            child: Stack(
              children: <Widget>[
                AnimatedPositioned(
                  duration: duration,
                  left: _left,
                  child: ElevatedButton(
                    onPressed: () {
                      setState(() {
                        _left = 100;
                      });
                    },
                    child: const Text("AnimatedPositioned"),
                  ),
                )
              ],
            ),
          ),
          Container(
            height: 100,
            color: Colors.grey,
            child: AnimatedAlign(
              duration: duration,
              alignment: _align,
              child: ElevatedButton(
                onPressed: () {
                  setState(() {
                    _align = Alignment.center;
                  });
                },
                child: const Text("AnimatedAlign"),
              ),
            ),
          ),
          AnimatedContainer(
            duration: duration,
            height: _height,
            color: _color,
            child: TextButton(
              onPressed: () {
                setState(() {
                  _height = 150;
                  _color = Colors.blue;
                });
              },
              child: const Text(
                "AnimatedContainer",
                style: TextStyle(color: Colors.white),
              ),
            ),
          ),
          AnimatedDefaultTextStyle(
            child: GestureDetector(
              child: const Text("hello world"),
              onTap: () {
                setState(() {
                  _style = const TextStyle(
                    color: Colors.blue,
                    decorationStyle: TextDecorationStyle.solid,
                    decorationColor: Colors.blue,
                  );
                });
              },
            ),
            style: _style,
            duration: duration,
          ),
          AnimatedOpacity(
            opacity: _opacity,
            duration: duration,
            child: TextButton(
              style: ButtonStyle(
                  backgroundColor: MaterialStateProperty.all(Colors.blue)),
              onPressed: () {
                setState(() {
                  _opacity = 0.2;
                });
              },
              child: const Text(
                "AnimatedOpacity",
                style: TextStyle(color: Colors.white),
              ),
            ),
          ),
          AnimatedDecoratedBox1(
            duration: Duration(
                milliseconds: _decorationColor == Colors.red ? 400 : 2000),
            decoration: BoxDecoration(color: _decorationColor),
            child: Builder(builder: (context) {
              return TextButton(
                onPressed: () {
                  setState(() {
                    _decorationColor = _decorationColor == Colors.blue
                        ? Colors.red
                        : Colors.blue;
                  });
                },
                child: const Text(
                  "AnimatedDecoratedBox toggle",
                  style: TextStyle(color: Colors.white),
                ),
              );
            }),
          )
        ].map((e) {
          return Padding(
            padding: const EdgeInsets.symmetric(vertical: 16),
            child: e,
          );
        }).toList(),
      ),
    );
  }
}

Flutter(九)Flutter動(dòng)畫(huà)和自定義組件,Flutter,flutter

自定義組件

1.簡(jiǎn)介

組合”是自定義組件最簡(jiǎn)單的方法,在任何需要自定義組件的場(chǎng)景下,都應(yīng)該優(yōu)先考慮是否能夠通過(guò)組合來(lái)實(shí)現(xiàn)。
而通過(guò)CustomPaint和RenderObject自繪的方式本質(zhì)上是一樣的,都需要開(kāi)發(fā)者調(diào)用Canvas API手動(dòng)去繪制UI

2.組合組件

  • 自定義漸變背景按鈕
    DecoratedBox可以支持背景色漸變和圓角,InkWell在手指按下有漣漪效果,所以我們可以通過(guò)組合DecoratedBox和InkWell來(lái)實(shí)現(xiàn)GradientButton
import 'package:flutter/material.dart';

class GradientButton extends StatelessWidget {
  const GradientButton({Key? key, 
    this.colors,
    this.width,
    this.height,
    this.onPressed,
    this.borderRadius,
    required this.child,
  }) : super(key: key);

  // 漸變色數(shù)組
  final List<Color>? colors;

  // 按鈕寬高
  final double? width;
  final double? height;
  final BorderRadius? borderRadius;

  //點(diǎn)擊回調(diào)
  final GestureTapCallback? onPressed;

  final Widget child;

  @override
  Widget build(BuildContext context) {
    ThemeData theme = Theme.of(context);

    //確保colors數(shù)組不空
    List<Color> _colors =
        colors ?? [theme.primaryColor, theme.primaryColorDark];

    return DecoratedBox(
      decoration: BoxDecoration(
        gradient: LinearGradient(colors: _colors),
        borderRadius: borderRadius,
        //border: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
      ),
      child: Material(
        type: MaterialType.transparency,
        child: InkWell(
          splashColor: _colors.last,
          highlightColor: Colors.transparent,
          borderRadius: borderRadius,
          onTap: onPressed,
          child: ConstrainedBox(
            constraints: BoxConstraints.tightFor(height: height, width: width),
            child: Center(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: DefaultTextStyle(
                  style: const TextStyle(fontWeight: FontWeight.bold),
                  child: child,
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

GradientButton是由DecoratedBox、Padding、Center、InkWell等組件組合而成,
flukit組件庫(kù)已收錄GradientButton
使用:

 children: <Widget>[
        GradientButton(
          colors: const [Colors.orange, Colors.red],
          height: 50.0,
          child: const Text("Submit"),
          onPressed: onTap,
        ),

3.CustomPaint 和 RenderObject

painter: 背景畫(huà)筆,會(huì)顯示在子節(jié)點(diǎn)后面;
foregroundPainter: 前景畫(huà)筆,會(huì)顯示在子節(jié)點(diǎn)前面
size:當(dāng)child為null時(shí),代表默認(rèn)繪制區(qū)域大小,如果有child則忽略此參數(shù),畫(huà)布尺寸則為child尺寸。如果有child但是想指定畫(huà)布為特定大小,可以使用SizeBox包裹CustomPaint實(shí)現(xiàn)。
isComplex:是否復(fù)雜的繪制,如果是,F(xiàn)lutter會(huì)應(yīng)用一些緩存策略來(lái)減少重復(fù)渲染的開(kāi)銷。
willChange:和isComplex配合使用,當(dāng)啟用緩存時(shí),該屬性代表在下一幀中繪制是否會(huì)改變

CustomPaint({
  Key key,
  this.painter, 
  this.foregroundPainter,
  this.size = Size.zero, 
  this.isComplex = false, 
  this.willChange = false, 
  Widget child, //子節(jié)點(diǎn),可以為空
})
//自定義
class MyPainter extends CustomPainter 

class CustomCheckbox extends LeafRenderObjectWidget 

Canvas常用:
drawLine 畫(huà)線
drawPoint 畫(huà)點(diǎn)
drawPath 畫(huà)路徑
drawImage 畫(huà)圖像
drawRect 畫(huà)矩形
drawCircle 畫(huà)圓
drawOval 畫(huà)橢圓
drawArc 畫(huà)圓弧文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-685950.html

到了這里,關(guān)于Flutter(九)Flutter動(dòng)畫(huà)和自定義組件的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Flutter自定義可拖動(dòng)組件

    Flutter自定義可拖動(dòng)組件

    2024年02月10日
    瀏覽(14)
  • flutter 自定義分層級(jí)樹(shù)形組件

    flutter 自定義分層級(jí)樹(shù)形組件

    前提條件,需在pubspec.yaml中依賴如下三方組件 1.調(diào)用入口 2.函數(shù)buildDepartTree()代碼 3.組件DepartGroupItemMouseRegionWidget代碼如下: 4.函數(shù)buildChildDepartList()代碼如下: 5.數(shù)據(jù)bean: 6.提供一個(gè)帶標(biāo)題、內(nèi)容、底部?jī)砂粹o的彈窗組件HLSimpleDialog,代碼如下: 具體效果如下: 可修改Depar

    2024年02月07日
    瀏覽(21)
  • Flutter:自定義組件的上下左右彈出層

    Flutter:自定義組件的上下左右彈出層

    最近要使用Flutter實(shí)現(xiàn)一個(gè)下拉菜單,需求就是,在當(dāng)前組件下點(diǎn)擊,其下方彈出一個(gè)菜單選項(xiàng),如下圖所示: 實(shí)現(xiàn)起來(lái),貌似沒(méi)什么障礙,在Flutter中本身就提供了彈出層PopupMenuButton組件和showMenu方法,于是開(kāi)搞,代碼如下: 直接使用showMenu也行,代碼如下: PopupMenuButton運(yùn)行

    2024年02月10日
    瀏覽(28)
  • Flutter 筆記 | Flutter 動(dòng)畫(huà)

    Flutter 筆記 | Flutter 動(dòng)畫(huà)

    為了方便開(kāi)發(fā)者創(chuàng)建動(dòng)畫(huà),不同的UI系統(tǒng)對(duì)動(dòng)畫(huà)都進(jìn)行了一些抽象, Flutter中也對(duì)動(dòng)畫(huà)進(jìn)行了抽象,主要涉及 Animation、Curve、Controller、Tween 這四個(gè)角色,它們一起配合來(lái)完成一個(gè)完整動(dòng)畫(huà),下面我們一一來(lái)介紹它們。 1. Animation Animation 是一個(gè)抽象類,它本身和UI渲染沒(méi)有任何關(guān)

    2024年02月07日
    瀏覽(24)
  • 組件庫(kù)的使用和自定義組件

    目錄 一、組件庫(kù)介紹 1、什么是組件 2、組件庫(kù)介紹 3、arco.design 二、組件庫(kù)的使用 1、快速上手 2、主題定制 3、暗黑模式 4、語(yǔ)言國(guó)際化 5、業(yè)務(wù)常見(jiàn)問(wèn)題 三、自定義組件 2、組件開(kāi)發(fā)規(guī)范 3、示例實(shí)踐guide-tip 4、業(yè)務(wù)組件快速托管 (1)工業(yè):具有標(biāo)準(zhǔn)接口和某種功能且可復(fù)

    2024年02月11日
    瀏覽(36)
  • Flutter:動(dòng)畫(huà)

    Flutter:動(dòng)畫(huà)

    學(xué)習(xí)參考:老孟 flutter動(dòng)畫(huà) 基本上開(kāi)發(fā)時(shí)使用的組件都有其動(dòng)畫(huà),關(guān)于動(dòng)畫(huà)方面的知識(shí),一般情況很少會(huì)用到。因此這里只學(xué)習(xí)關(guān)于動(dòng)畫(huà)的基本知識(shí)。 Flutter中的 AnimationController 是一個(gè)用于控制動(dòng)畫(huà)的類。它可以控制動(dòng)畫(huà)的開(kāi)始、停止、反轉(zhuǎn)、重置等操作,并且可以設(shè)置動(dòng)畫(huà)

    2024年02月08日
    瀏覽(19)
  • Flutter開(kāi)發(fā)進(jìn)階之動(dòng)畫(huà)

    Flutter開(kāi)發(fā)進(jìn)階之動(dòng)畫(huà)

    在Flutter中,動(dòng)畫(huà)是至關(guān)重要的一個(gè)部分,它能夠?yàn)閼?yīng)用程序提供更加豐富和生動(dòng)的用戶體驗(yàn),F(xiàn)lutter中的動(dòng)畫(huà)系統(tǒng)是UI框架的核心功能之一,也是開(kāi)發(fā)者學(xué)習(xí)Flutter框架的重要部分,由于動(dòng)畫(huà)原理在所有程序中都是相同的,即視覺(jué)暫留,因此理解這一原理對(duì)于更好地使用Flutter的

    2024年01月21日
    瀏覽(29)
  • Flutter Flar動(dòng)畫(huà)實(shí)戰(zhàn)

    Flutter Flar動(dòng)畫(huà)實(shí)戰(zhàn)

    在Flare動(dòng)面出現(xiàn)之前,F(xiàn)lare動(dòng)畫(huà)大體可以分為使用AnimationController控制的基礎(chǔ)動(dòng)畫(huà)以及使用Hero的轉(zhuǎn)場(chǎng)動(dòng)畫(huà),如果遇到一些復(fù)雜的場(chǎng)景,使用這些動(dòng)畫(huà)方案實(shí)現(xiàn)起來(lái)還是有難度的。不過(guò),隨著Flutter開(kāi)始支持Flare矢量動(dòng)面,F(xiàn)lutter的動(dòng)畫(huà)開(kāi)發(fā)也變得越來(lái)越簡(jiǎn)單。事實(shí)上,F(xiàn)lare動(dòng)畫(huà)是一

    2024年02月14日
    瀏覽(20)
  • Flutter中動(dòng)畫(huà)的實(shí)現(xiàn)

    ? ? ? ?動(dòng)畫(huà)三要素 ????????控制動(dòng)畫(huà)的三要素:Animation、Tween、和AnmaitionController ????????Animation:?產(chǎn)生的值的序列,有CurveAnimation等子 類,,?可以將值賦值給Widget的寬高或其他屬性,進(jìn)而控制widget發(fā)生變化 ????????Tween:可以定義值的變化范圍,??繼承自 An

    2024年03月10日
    瀏覽(23)
  • Flutter 06 動(dòng)畫(huà)

    Flutter 06 動(dòng)畫(huà)

    1、動(dòng)畫(huà)原理: 在任何系統(tǒng)的Ul框架中,動(dòng)畫(huà)實(shí)現(xiàn)的原理都是相同的,即:在一段時(shí)間內(nèi),快速地多次改變Ul外觀;由于人眼會(huì)產(chǎn)生視覺(jué)暫留,所以最終看到的就是一個(gè)“連續(xù)”的動(dòng)畫(huà),這和電影的原理是一樣的。 我們將UI的一次改變稱為一個(gè)動(dòng)畫(huà)幀,對(duì)應(yīng)一次屏幕刷新,而決

    2024年02月05日
    瀏覽(18)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包