欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Flutter实战之封装一个LinearLayout

程序员文章站 2022-05-25 19:06:32
...

APP开发过程中,经常遇到需要添加背景、设置边距、动态显示和隐藏某个组件。

但是在Flutter中,能同时具有添加背景、设置边距、阴影、边框、圆角的布局只有Container(参考我上一篇文章的介绍Flutter入门之Row、Column、Container布局),这个已经算是业务功能比较多的组件了,而要想实现组件的显示和隐藏则需要用到另外一个组件Offstage,水平的线性布局则需要用到组件Row,垂直的线性布局则需要用到组件Column,而RowColumn这两个布局都不具备直接设置背景、边距、显示和隐藏等功能。

在开发过程中这种需求又很常见,不可能每个地方都把这些代码重复一遍,所以对这几个组件封装一下,实现了一个类似AndroidLinearLayout布局的组件很有必要。

封装LinearLayout

封装成LinearLayout其实很简单,就是将RowColumnOffstageContainer四个组件合理的组合在一起就可以了。

  1. 首先要暴露一个参数确定是水平的线性布局还是垂直的线性布局
  2. Container经常用到的背景、边距参数暴露出来
  3. RowColumn中用到的主轴、交叉轴的对齐方式暴露出来
  4. RowColumn中主轴size的适配方式暴露出来
  5. 暴露出一个方法用来动态改变组件的显示和隐藏

代码如下:

import 'package:flutter/material.dart';
import 'package:flutter_library/common/util.dart';

enum LayoutOrientation { horizontal, vertical }

class LinearLayout extends StatefulWidget {
  final LayoutOrientation orientation;
  final bool isVisible;
  final Decoration background;
  final EdgeInsetsGeometry padding;
  final EdgeInsetsGeometry margin;
  final List<Widget> children;

  final MainAxisAlignment mainAxisAlignment;
  final MainAxisSize mainAxisSize;
  final CrossAxisAlignment crossAxisAlignment;

  LinearLayout({
    Key key,
    this.orientation,
    this.isVisible = true,
    this.background,
    this.padding,
    this.margin,
    this.children = const <Widget>[],
    this.mainAxisAlignment = MainAxisAlignment.start,
    this.mainAxisSize = MainAxisSize.min,
    this.crossAxisAlignment = CrossAxisAlignment.center,
  }) : super(key: key);

  @override
  LinearLayoutState createState() {
    return LinearLayoutState();
  }
}

class LinearLayoutState extends State<LinearLayout> {
  bool _isVisible = true;

  @override
  void initState() {
    _isVisible = widget.isVisible;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return isNotNull(_isVisible)
        ? Offstage(
            offstage: !_isVisible,
            child: _buildLayoutWidget(),
          )
        : _buildLayoutWidget();
  }

  Widget _buildLayoutWidget() {
    if (_isNeedContainerWidget()) {
      return _buildContainerWidget();
    } else {
      return _buildOrientationWidget();
    }
  }

  bool _isNeedContainerWidget() {
    return isNotNull(widget.background) ||
        isNotNull(widget.padding) ||
        isNotNull(widget.margin);
  }

  Widget _buildContainerWidget() {
    return Container(
      decoration: widget.background,
      padding: widget.padding,
      margin: widget.margin,
      child: _buildOrientationWidget(),
    );
  }

  Widget _buildOrientationWidget() {
    if (widget.orientation == LayoutOrientation.horizontal) {
      return _buildHorizontalWidget();
    } else {
      return _buildVerticalWidget();
    }
  }

  Widget _buildVerticalWidget() {
    return Column(
      mainAxisSize: widget.mainAxisSize,
      mainAxisAlignment: widget.mainAxisAlignment,
      crossAxisAlignment: widget.crossAxisAlignment,
      children: widget.children,
    );
  }

  Widget _buildHorizontalWidget() {
    return Row(
      mainAxisSize: widget.mainAxisSize,
      mainAxisAlignment: widget.mainAxisAlignment,
      crossAxisAlignment: widget.crossAxisAlignment,
      children: widget.children,
    );
  }

  bool isVisible() {
    return _isVisible;
  }

  void setVisible(bool isVisible) {
    setState(() {
      _isVisible = isVisible;
    });
  }
}

package:flutter_library/common/util.dart文件代码如下:

bool isNull(dynamic obj) {
  return obj == null;
}

bool isNotNull(dynamic obj) {
  return obj != null;
}

LinearLayout使用

class LinearLayoutSampleWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return LinearLayoutSampleState();
  }
}

class LinearLayoutSampleState extends State<LinearLayoutSampleWidget> {
  GlobalKey<LinearLayoutState> _key = GlobalKey<LinearLayoutState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('LinearLayout Sample'),
      ),
      body:
        LinearLayout(
          background: BoxDecoration(color: Colors.blue),
          orientation: LayoutOrientation.vertical,
          children: <Widget>[
            LinearLayout(
              key: _key,
              background: BoxDecoration(color: Colors.red),
              orientation: LayoutOrientation.horizontal,
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                Icon(Icons.list),
                Text('线性布局')
              ],
            ),
            FlatButton(
              onPressed: () {
                bool isVisible = _key.currentState.isVisible();
                _key.currentState.setVisible(!isVisible);
              },
              child: Text('切换显示'),
            )
          ],
        )  
    );
  }
}

这里重点说一下Demo中的GlobalKey<LinearLayoutState> _key = GlobalKey<LinearLayoutState>()这段代码,这个就是用来给LinearLayout设定一个唯一标识符,这样才能在后面点击按钮的时候调用setVisible方法来显示和隐藏。而泛型LinearLayoutState则是我封装的代码中的一个类,因为我的setVisible方法暴露在此State中。

相关标签: Flutter