Flutter開發(fā)之自定義view,widget

為了滿足我們自身的開發(fā)需求,很多時候就需要我們自定動手制作東西,也就是所謂的自定義view,那么我們一起學(xué)習(xí)下flutter的自定義view吧

本人理解flutter的自定義view可以歸為兩類:
1,已有控件(widget)的繼承,組合
2,自定義繪制widget,也就是利用paint,cavans等進行繪制視圖。

1,先來示例第一種吧

我們做一個自定義的dialog,這個dialog是繼承原生自帶的Dialog,并且組合其他的控件一起的。

import 'dart:ui';
import 'package:flutter/material.dart';

 
class TestMessageDialog extends Dialog {
  BuildContext mContext;
  String title;
  String message;
  String negativeText;
  String positiveText;
  Function onCloseEvent;
  Function onPositivePressEvent;

  TestMessageDialog({
    Key key,
    @required this.title,
    @required this.message,
    this.negativeText,
    this.positiveText,
    this.onPositivePressEvent,
    @required this.onCloseEvent,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    mContext=context;
    return GestureDetector(
        onTap: () {
          Navigator.pop(context);
        },
        child: WillPopScope(
          onWillPop: () {
            _onNavigationClickEvent();
            return Future.value(false);
          },
          child: Material(
            color: Colors.transparent,

            child: Stack(
              fit: StackFit.expand,
              children: <Widget>[
                GestureDetector(onTap: _onNavigationClickEvent),
                _buildContentView(), //構(gòu)建具體的對話框布局內(nèi)容
              ],
            ),
          ),
        ));

  }

  void _onNavigationClickEvent(){

    Navigator.pop(mContext);
  }
  Widget _buildContentView(){
    return new Padding(
      padding: const EdgeInsets.all(15.0),
      child: new Material(
        type: MaterialType.transparency,
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Container(
              decoration: ShapeDecoration(
                color: Color(0xffffffff),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(8.0),
                  ),
                ),
              ),
              margin: const EdgeInsets.all(12.0),
              child: new Column(
                children: <Widget>[
                  new Padding(
                    padding: const EdgeInsets.all(10.0),
                    child: new Stack(
                      alignment: AlignmentDirectional.centerEnd,
                      children: <Widget>[
                        new Center(
                          child: new Text(
                            title,
                            style: new TextStyle(
                              fontSize: 19.0,
                            ),
                          ),
                        ),
                        new GestureDetector(
                          onTap: this.onCloseEvent,
                          child: new Padding(
                            padding: const EdgeInsets.all(5.0),
                            child: new Icon(
                              Icons.close,
                              color: Color(0xffe0e0e0),
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                  new Container(
                    color: Color(0xffe0e0e0),
                    height: 1.0,
                  ),
                  new Container(
                    constraints: BoxConstraints(minHeight: 180.0),
                    child: new Padding(
                      padding: const EdgeInsets.all(12.0),
                      child: new IntrinsicHeight(
                        child: new Text(
                          message,
                          style: TextStyle(fontSize: 16.0),
                        ),
                      ),
                    ),
                  ),
                  this._buildBottomButtonGroup(),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }


  Widget _buildBottomButtonGroup() {
    var widgets = <Widget>[];
    if (negativeText != null && negativeText.isNotEmpty) widgets.add(_buildBottomCancelButton());
    if (positiveText != null && positiveText.isNotEmpty) widgets.add(_buildBottomPositiveButton());
    return new Flex(
      direction: Axis.horizontal,
      children: widgets,
    );
  }

  Widget _buildBottomCancelButton() {
    return new Flexible(
      fit: FlexFit.tight,
      child: new FlatButton(
        onPressed: onCloseEvent,
        child: new Text(
          negativeText,
          style: TextStyle(
            fontSize: 16.0,
          ),
        ),
      ),
    );
  }

  Widget _buildBottomPositiveButton() {
    return new Flexible(
      fit: FlexFit.tight,
      child: new FlatButton(
        onPressed: onPositivePressEvent,
        child: new Text(
          positiveText,
          style: TextStyle(
            color: Color(Colors.teal.value),
            fontSize: 16.0,
          ),
        ),
      ),
    );
  }
} 

上面的自定義dialog就是繼承原生Dialog之后結(jié)合其他控件使用的一種典型例子,為了滿足需求你還可以加個回調(diào)函數(shù)final Function callback; 修改之后的回掉函數(shù),增加dialog操作之后回調(diào)給頁面。具體的一步步操作就好了。

2,下面介紹第二種,純手工制作的控件(自繪)

我們就來個簡單的例子。
最近看了別人博客跟著做了個小球下落的功能,那就看個自定義小球的例子吧

import 'dart:ui';

import 'package:flutter/material.dart';

///小球信息描述類
class Ball {
  double aX; //加速度
  double aY; //加速度Y
  double vX; //速度X
  double vY; //速度Y
  double x; //點位X
  double y; //點位Y
  Color color; //顏色
  double r;//小球半徑

  Ball({this.x=0, this.y=0, this.color, this.r=10,
    this.aX=0, this.aY=0, this.vX=0, this.vY=0});
}

///畫板Painter
class RunBallView extends CustomPainter {
  Ball _ball; //小球
  Rect _area;//運動區(qū)域
  Paint mPaint; //主畫筆
  Paint bgPaint; //背景畫筆

  RunBallView(this._ball,this._area) {
    mPaint = new Paint();
    bgPaint = new Paint()..color = Color.fromARGB(148, 198, 246, 248);
  }

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawRect(_area, bgPaint);
    _drawBall(canvas, _ball);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }

  ///使用[canvas] 繪制某個[ball]
  void _drawBall(Canvas canvas, Ball ball) {
    canvas.drawCircle(
        Offset(ball.x, ball.y), ball.r, mPaint..color = ball.color);
  }
}

var _area= Rect.fromLTRB(0+40.0,0+200.0,280+40.0,200+200.0);
var _ball = Ball(color: Colors.blueAccent, r: 10,x: 40.0+140,y:200.0+100);
 
var child = Scaffold(
  body: CustomPaint(
    painter: RunBallView(_ball,_area),
  ),
);

這個自身根據(jù)需要作出自定義的小球,然后再加上算法和函數(shù)就可以隨心地做你想要的東西了。

這一篇章寫得比較粗糙,本來打算做一個自定義的下雪動畫的,下次再上代碼介紹吧,先理解好先。
也可以參考下面文章理解:
https://book.flutterchina.club/chapter10/intro.html

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

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

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