Flutter 128: 圖解 ColorTween 顏色補(bǔ)間動畫 & ButtonBar 按鈕容器

????小菜在嘗試做主題顏色切換時,希望背景色有一個自然的過渡過程,于是了解到 ColorTween 顏色補(bǔ)間差值器,配合 AnimationController 實(shí)現(xiàn)兩種顏色間的自然過渡;小菜簡單嘗試一下;

ColorTween

源碼分析

????ColorTween 的源碼很簡單,繼承自 Tween 補(bǔ)間動畫,與 Tween 相同,只是 beginendColor 替代;其中若需要透明狀態(tài),可以將 begin / end 設(shè)置為 nullColors.transparent 再此代表黑色透明,會淡入淡出黑色;

class ColorTween extends Tween<Color?> {
  ColorTween({ Color? begin, Color? end }) : super(begin: begin, end: end);

  @override
  Color? lerp(double t) => Color.lerp(begin, end, t);
}

案例源碼

????小菜預(yù)先設(shè)置好需要主題顏色切換的 UI Widget,之后通過混入 TickerProviderStateMixin,在 initState() 初始化時設(shè)置好 AnimationController,將顏色傳遞給背景色;

AnimationController _controller;
Animation<Color> _colors;
Color _currentColor = Colors.black;

@override
void initState() {
  super.initState();
  _controller = AnimationController(duration: Duration(seconds: 3), vsync: this);
  _colors = ColorTween(begin: _currentColor, end: Colors.amber).animate(_controller);
}

_bodyWid() => Material(
    child: AnimatedBuilder(
        animation: _colors,
        builder: (BuildContext _, Widget childWidget) {
          return Scaffold(backgroundColor: _colors.value, body: _itemListWid());
        }));

????通過 AnimationController 控制淡入淡出時機(jī);reset() 重置控制器,forward()beginend 顏色切換;reward()endbegin 顏色切換;repeat() 重復(fù)循環(huán)切換;

_changeColorWid() => Container(
    color: Colors.white,
    child: Column(children: [
      ListTile(title: Text('切換 ThemeColor:')),
      Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
        _itemColorWid(Colors.deepOrange), _itemColorWid(Colors.teal),
        _itemColorWid(Colors.blue), _itemColorWid(Colors.pink),
        _itemColorWid(Colors.indigoAccent)
      ])
    ]));

_itemColorWid(color) => GestureDetector(
    child: Container(width: 50.0, height: 50.0, color: color),
    onTap: () {
      _colors = ColorTween(begin: _currentColor, end: color).animate(_controller);
      setState(() {
        _controller.reset();
        _controller.forward();
      });
      _currentColor = color;
    });

ButtonBar

????小菜在很多場景中設(shè)置水平均分或右對齊,為此小菜了解到一個新的容器方式,ButtonBar 默認(rèn)水平方式放置子 Widget 當(dāng)水平寬度無法完全放置所有子 Widget 時會豎直方向放置,小菜簡單學(xué)習(xí)一下;

源碼分析

const ButtonBar({
    Key key,
    this.alignment,         // 對齊方式
    this.mainAxisSize,      // 主軸上占據(jù)空間范圍
    this.buttonTextTheme,   // 按鈕文本主題
    this.buttonMinWidth,    // 子按鈕最小寬度
    this.buttonHeight,      // 子按鈕最高度
    this.buttonPadding,     // 子按鈕內(nèi)邊距
    this.buttonAlignedDropdown, // 下拉菜單是否與子按鈕對齊
    this.layoutBehavior,
    this.overflowDirection, // 子按鈕排列順序
    this.overflowButtonSpacing, // 子按鈕之間間距
    this.children = const <Widget>[],
})

????簡單分析源碼,ButtonBar 作為一個無狀態(tài)的 StatelessWidgetRow 類似,作為一個存放子 Widget 的容器,其中包括了類似于對齊方式等屬性方便應(yīng)用;小菜簡單理解為變形的 Row,實(shí)際是繼承自 Flex_ButtonBarRow

案例嘗試

構(gòu)造方法

????ButtonBar 作為一個 Widget 容器,用于水平存放各 Widget,若子 Widget 占據(jù)空間范圍大于分配空間時,則豎直方向展示;

_buttonBarWid01() => ButtonBar(children: <Widget>[
      RaisedButton(child: Text('Button 01'), onPressed: null),
      RaisedButton(child: Text('Button 02'), onPressed: null) ]);
    
_buttonBarWid02() => ButtonBar(children: <Widget>[
      RaisedButton(child: Text('Button 01'), onPressed: null),
      RaisedButton(child: Text('Button 02'), onPressed: null),
      RaisedButton(child: Text('Button 03'), onPressed: null),
      RaisedButton(child: Text('Button 04'), onPressed: null) ]);
    
_buttonBarWid03() => ButtonBar(children: <Widget>[
      RaisedButton(child: Text('Button 01'), onPressed: null),
      RaisedButton(child: Text('Button 02'), onPressed: null),
      RaisedButton(child: Text('Button 03'), onPressed: null),
      RaisedButton(child: Text('Button 04'), onPressed: null),
      RaisedButton(child: Text('Button 05'), onPressed: null) ]);

1. alignment

????alignment 為容器內(nèi)子 Widget 的對齊方式,不設(shè)置或?yàn)?null 時默認(rèn)為 end 方式對齊,此時與 ltr / rtl 相關(guān);

_buttonBarWid01(index) {
  MainAxisAlignment alignment;
  if (index == 0) {
    alignment = MainAxisAlignment.start;
  } else if (index == 1) {
    alignment = MainAxisAlignment.center;
  } else if (index == 2) {
    alignment = MainAxisAlignment.spaceAround;
  } else if (index == 3) {
    alignment = MainAxisAlignment.spaceBetween;
  } else if (index == 4) {
    alignment = MainAxisAlignment.spaceEvenly;
  } else {
    alignment = MainAxisAlignment.end;
  }
  return ButtonBar(alignment: alignment, children: <Widget>[
    RaisedButton(child: Text('Button'), onPressed: null),
    RaisedButton(child: Text('${alignment.toString()}'), onPressed: null) ]);
}

2. mainAxisSize

????mainAxisSize 為主軸上占據(jù)空間范圍,與 Row / Column 一致,分為 min / max 最小范圍和最大填充范圍兩種;

_buttonBarWid05(mainAxisSize) => Container(
    color: Colors.blue.withOpacity(0.3),
    child: ButtonBar(mainAxisSize: mainAxisSize, children: <Widget>[
      RaisedButton(child: Text('Button 01'), onPressed: null),
      RaisedButton(child: Text('Button 02'), onPressed: null),
      RaisedButton(child: Text('Button 03'), onPressed: null)
    ]));

3. buttonTextTheme

????buttonTextTheme 為子 Widget 按鈕主題,主要包括 normal / accent / primary 三種主題樣式,分別對應(yīng) ThemeData.brightness / accentColor / primaryColor

_buttonBarWid04(theme) =>
    ButtonBar(buttonTextTheme: theme, children: <Widget>[
      RaisedButton(child: Text('Button 01'), onPressed: null),
      RaisedButton(child: Text('Button 02', style: TextStyle(color: Colors.blue)), onPressed: null),
      RaisedButton(child: Text('${theme.toString()}'), onPressed: null),
    ]);

4. buttonMinWidth & buttonHeight

????buttonMinWidth & buttonHeight 分別對應(yīng)子 Widget 默認(rèn)的最小按鈕寬度和按鈕高度;

_buttonBarWid06(width, height, alignment) =>
    ButtonBar(buttonMinWidth: width, buttonHeight: height, children: <Widget>[
      RaisedButton(child: Text('Button 01'), onPressed: null),
      RaisedButton(child: Text('Button 02', style: TextStyle(color: Colors.blue)), onPressed: null),
      RaisedButton(child: Text('${alignment.toString()}'), onPressed: null),
    ]);

5. overflowButtonSpacing & buttonPadding

????overflowButtonSpacing 對應(yīng)子按鈕外間距,類似于 GridView 元素間間距;buttonPadding 對應(yīng)子按鈕內(nèi)邊距;

_buttonBarWid07(padding, spacing) => ButtonBar(
      overflowButtonSpacing: spacing,
      buttonPadding: EdgeInsets.all(padding),
      children: <Widget>[
        RaisedButton(child: Text('Button 01'), onPressed: null),
        RaisedButton(child: Text('Button 02', style: TextStyle(color: Colors.blue)), onPressed: null),
        RaisedButton(child: Text('Button 03'), onPressed: null)
      ]);

6. overflowDirection

????overflowDirection 為若容器內(nèi)子 Widget 所占范圍超過最大限制范圍時,垂直排列順序,小菜理解為順序和倒序兩種;

_buttonBarWid08(direction) =>
    ButtonBar(overflowDirection: direction, children: <Widget>[
      RaisedButton(child: Text('Button 01'), onPressed: null),
      RaisedButton(child: Text('Button 02', style: TextStyle(color: Colors.blue)), onPressed: null),
      RaisedButton(child: Text('Button 03'), onPressed: null),
      RaisedButton(child: Text('${direction.toString()}'), onPressed: null),
    ]);

????ColorTween 案例源碼 & ButtonBar 案例源碼


????ColorTweenButtonBar 的應(yīng)用非常簡單,這次小菜在實(shí)際場景中進(jìn)行嘗試學(xué)習(xí),如有錯誤,請多多指導(dǎo)!

來源: 阿策小和尚

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容