1. 程式人生 > >Flutter佈局錦囊---塗鴉風格按鈕

Flutter佈局錦囊---塗鴉風格按鈕

設計給的效果如下:

UI佈局圖

拿到設計後,先把整體拆分成幾個部分:

  1. “可點選框”,使用堆疊(Stack)元件佈局的可點選區域。
  2. “底部矩形”,用來襯托“主要矩形”,以形成立體效果的矩形。
  3. “主要矩形”,按鈕主體部分,通過調整上下位置來模擬按壓效果。

然後就可以開始進行編碼了。

第1步:繪製元件樹

塗鴉風格按鈕的元件樹

第2步:實現“可點選框”

通過手勢探測器(GestureDetector)元件,你可以通過檢測多種手勢並設定對應的處理函式。通過大小框(SizedBox)元件為“按鈕”設定一個活動區域,並將堆疊(Stack)元件作為子元件置於其中。同時,通過activation

onTapCallback兩個變數來傳遞狀態和回撥函式。

import 'package:flutter/material.dart';

/// 自定義的塗鴉按鈕元件。
class DoodleButton extends StatefulWidget {
  // TODO: 第3步:實現“底部矩形”,成員變數。
  // TODO: 第4步:實現“主要矩形”,成員變數。
  /// 按鈕的啟用狀態,預設為`false`。
  final bool activation;
  /// 發生點選時的回撥函式。
  final Function onTapCallback;

  DoodleButton({
    // TODO: 第3步:實現“底部矩形”,預設構造。
// TODO: 第4步:實現“主要矩形”,預設構造。 this.activation: false, this.onTapCallback, }); @override _DoodleButtonState createState() => _DoodleButtonState(); } /// 與自定義的塗鴉按鈕元件關聯的狀態子類。 class _DoodleButtonState extends State<DoodleButton> { // TODO: 第4步:實現“主要矩形”,控制按壓。 @override Widget build
(BuildContext context) { // 手勢探測器(`GestureDetector`)元件,檢測手勢的元件。 // 嘗試識別與其非空回撥相對應的手勢。如果此元件具有子項, // 則它會根據其大小調整行為推遲該子項。 // 如果它沒有子元件,它會變得適合父元件。 return GestureDetector( // 在點選(`onTap`)屬性,發生了點選。 onTap: widget.activation ? () { setState(() { // TODO: 第4步:實現“主要矩形”,“按下”按鈕。 widget.onTapCallback(); // TODO: 第4步:實現“主要矩形”,“鬆開”按鈕。 }); } : null, child: SizedBox( height: 48.0, // 堆疊(`Stack`)元件,用於將其子級相對於其框的邊緣定位。 child: Stack( children: <Widget>[ // TODO: 第3步:實現“底部矩形”,實現容器。 // TODO: 第4步:實現“主要矩形”,實現容器。 ] ), ), ); } }

第3步:實現“底部矩形”

通過backgroundColorsilentBackgroundColor變數來傳遞“按鈕”可用、不可用時,“底部矩形”的顏色。

  // TODO: 第3步:實現“底部矩形”,成員變數。
  /// 按鈕的底部顏色,預設為`#D95636`。
  final Color backgroundColor;
  /// 不可用按鈕的底部顏色,預設為`#8A8A8A`。
  final Color silentBackgroundColor;

    // TODO: 第3步:實現“底部矩形”,預設構造。
    this.backgroundColor: const Color(0xFFD95636),
    this.silentBackgroundColor: const Color(0xFF8A8A8A),

使用對齊(Align)元件,並通過Alignment.bottomCenter將其設定為靠近下方對齊。再用邊界半徑(BorderRadius)類,將矩形的4個邊角設定為圓角。

            // TODO: 第3步:實現“底部矩形”,實現容器。
            // 對齊(`Align`)元件,用於將其子項與其自身對齊,並根據子級的大小自行調整大小。
            Align(
              // 對準屬性,如何調整子元件。
              alignment: Alignment.bottomCenter,
              child: Container(
                decoration: BoxDecoration(
                  color: widget.activation ? widget.backgroundColor : widget.silentBackgroundColor,
                  // 框裝飾(`BoxDecoration`)類的邊界(`border`)屬性,在背景顏色、漸變或影象上方繪製的邊框。
                  // 邊界(`Border`)類,框的邊框,由四個邊組成:頂部、右側、底部、左側。
                  border: Border.all(
                    // 寬度引數,邊框的寬度。
                    width: 2.0,
                    // 顏色引數,邊框的顏色。
                    color: const Color(0xFF282828),
                  ),
                  // 邊界半徑(`borderRadius`)屬性,如果為非空值,則此屬性將對此框的角進行舍入。
                  // 邊界半徑(`BorderRadius`)類,矩形每個角的一組不可變半徑。
                  // 邊界半徑.所有(`BorderRadius.all`)建構函式,建立一個邊界半徑,設定所有的半徑。
                  borderRadius: BorderRadius.all(
                    // 半徑(`Radius`)類,圓形或橢圓形的半徑。
                    // 半徑.圓(`Radius.circular`)建構函式,構造一個圓形半徑,x和y將具有相同的半徑值。
                    Radius.circular(2.0),
                  ),
                ),
                height: 42.0,
              ),
            ),

第4步:實現“主要矩形”

通過mainColorsilentMainColor變數來傳遞“按鈕”可用、不可用時,“底部矩形”的顏色,promptText變數傳遞“按鈕”的操作提示文字。

  // TODO: 第4步:實現“主要矩形”,成員變數。
  /// 按鈕的操作提示文字。
  final String promptText;
  /// 按鈕的主要顏色,預設為`#FF6B47`。
  final Color mainColor;
  /// 不可用按鈕的主要顏色,預設為`#B2B2B2`。
  final Color silentMainColor;

    // TODO: 第4步:實現“主要矩形”,預設構造。
    this.promptText,
    this.mainColor: const Color(0xFFFF6B47),
    this.silentMainColor: const Color(0xFFB2B2B2),

通過對準(Alignment)類來控制“主要矩形”的按壓效果:靠近上邊時是鬆開按鈕;靠近下邊時是按下按鈕。

  // TODO: 第4步:實現“主要矩形”,控制按壓。
  // 對準(`Alignment`)類,矩形內的一個點。
  // [0.0,0.0]表示矩形的中心,[-1.0到+1.0]的距離是從矩形的一邊到矩形的另一邊的距離。
  // 因此,水平(或垂直)[2.0]單位等於矩形的寬度(或高度)。
  /// 主要容器的對齊方式,控制按鈕的按壓狀態。
  Alignment mainContainerAlignment = Alignment.topCenter;

          // TODO: 第4步:實現“主要矩形”,“按下”按鈕。
          mainContainerAlignment = Alignment.bottomCenter;
          widget.onTapCallback();
          // TODO: 第4步:實現“主要矩形”,“鬆開”按鈕。
          mainContainerAlignment = Alignment.topCenter;

最後實現“主要矩形”的佈局程式碼。

            // TODO: 第4步:實現“主要矩形”,實現容器。
            Align(
              alignment: mainContainerAlignment,
              child: Container(
                child: Center(
                  child: Text(
                    widget.promptText,
                    style: TextStyle(
                      color: const Color(0xFF282828),
                      fontSize: 18.0,
                      // 字型重量(`FontWeight`)類,用於繪製文字的字形的粗細。
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
                decoration: BoxDecoration(
                  color: widget.activation ? widget.mainColor : widget.silentMainColor,
                  border: Border.all(
                    width: 2.0,
                    color: const Color(0xFF282828),
                  ),
                  borderRadius: BorderRadius.all(
                    Radius.circular(2.0),
                  ),
                ),
                height: 42.0,
              ),
            ),

第5步:還原效果

塗鴉風格按鈕的還原效果