Flutter实战之封装一个LinearLayout

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 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 [],
    this.mainAxisAlignment = MainAxisAlignment.start,
    this.mainAxisSize = MainAxisSize.min,
    this.crossAxisAlignment = CrossAxisAlignment.center,
  }) : super(key: key);

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

class LinearLayoutState extends State {
  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 createState() {
    return LinearLayoutSampleState();
  }
}

class LinearLayoutSampleState extends State {
  GlobalKey _key = GlobalKey();

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

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


下面是我的个人公众号,欢迎关注交流

你可能感兴趣的:(Flutter)