美文网首页
flutter中固定区域智能显示文本框

flutter中固定区域智能显示文本框

作者: afdjsajfdsl | 来源:发表于2019-04-27 21:01 被阅读0次

    1. 固定区域智能显示文本框

    需求:给定一个固定大小的区域,可以智能的显示文本(列排版):

    • 可以智能的调整字体大小的显示
    • 如果,小于或等于最小的字体,说明字体太多排不下,则增加滑动。
    • 如果超出或等于最大字体,说明可以排版下,这时候使header和content还有bottom都居中显示。

    2. 思路

    对于给定的区域,先用 Column 中的 Expand 排版,进行计算;待计算出结果后,进行状态的更新。

    • 获取可用的区域
    Expanded(
        child: Container(
            child: LayoutBuilder(builder: (context, constraints) {
                _calculateAndSetFontSize(Size(constraints.maxWidth, constraints.maxHeight));
                return Container(
                    child: Text('empty'),
                );
            }),
        ),
    )
    
    • 重新构建方法设置
    void _calculateAndSetFontSize(Size size) {
        print('size = $size');
        ......
        Future.delayed(Duration(milliseconds: 0), () {
          setState(() {});
        });
      }
    

    这里需要进行延迟 Future.delayed,否则就是正在 build中又设置markNeedsBuild = true,需要再次build`。会出现下面的异常:

    flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
    flutter: The following assertion was thrown building LayoutBuilder:
    flutter: setState() or markNeedsBuild() called during build.
    flutter: This _FitTextBox widget cannot be marked as needing to build because the framework is already in the
    flutter: process of building widgets. A widget can be marked as needing to be built during the build phase
    flutter: only if one of its ancestors is currently building. This exception is allowed because the framework
    flutter: builds parent widgets before children, which means a dirty descendant will always be built.
    flutter: Otherwise, the framework might not visit this widget during this build phase.
    flutter: The widget on which setState() or markNeedsBuild() was called was:
    flutter:   _FitTextBox(state: __FitTextBoxState#231de)
    flutter: The widget which was currently being built when the offending call was made was:
    flutter:   LayoutBuilder(renderObject: _RenderLayoutBuilder#e4bfa relayoutBoundary=up1 NEEDS-LAYOUT
    flutter:   NEEDS-PAINT)
    flutter:
    flutter: When the exception was thrown, this was the stack:
    flutter: #0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:3502:11)
    flutter: #1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:3528:6)
    flutter: #2      State.setState (package:flutter/src/widgets/framework.dart:1132:14)
    flutter: #3      __FitTextBoxState._calculateAndSetFontSize (package:hello/home/base/fitText/wisdom_fit_text.dart:93:5)
    
    

    3. 具体实现代码

    • 使用方法
    Container(
              width: double.infinity,
              height: 100.0 + 30.0 + 50.0,
              color: Colors.red[200],
              child: _FitTextBox(
                showText: textString,
                fixedHeightHeaderWidget: Container(
                  width: 100.0,
                  height: 30.0,
                  color: Colors.blue,
                ),
                fixedHeightBottomWidget: Container(
                  width: 100.0,
                  height: 50.0,
                  color: Colors.yellow[300],
                ),
              ),
            )
    
    • 实现代码
    class _FitTextBox extends StatefulWidget {
      final String showText;
      final Widget fixedHeightHeaderWidget;
      final Widget fixedHeightBottomWidget;
      _FitTextBox({this.showText, this.fixedHeightHeaderWidget, this.fixedHeightBottomWidget});
      @override
      __FitTextBoxState createState() => __FitTextBoxState();
    }
    
    class __FitTextBoxState extends State<_FitTextBox> {
      double _realFontSize;
      bool _layoutReady = false;
      bool _needCenter = false;
      bool _needScroll = false;
    
      void _calculateAndSetFontSize(Size size) {
        print('size = $size');
        double retFontSize = TextSize.calculateFontSizeSync(
          size,
          widget.showText,
        );
        _realFontSize = retFontSize;
        if (_realFontSize >= TextSize.maxFontSize) {
          _needCenter = true;
        } else {
          _needCenter = false;
        }
        if (_realFontSize <= TextSize.minFontSize) {
          _needScroll = true;
        } else {
          _needScroll = false;
        }
        print('needCenter = $_needCenter');
        _layoutReady = true;
    
        Future.delayed(Duration(milliseconds: 0), () {
          setState(() {});
        });
      }
    
      @override
      void didUpdateWidget(_FitTextBox oldWidget) {
        super.didUpdateWidget(oldWidget);
        print("didUpdateWidget");
        if (oldWidget.showText != widget.showText) {
          _layoutReady = false;
        }
      }
    
      @override
      Widget build(BuildContext context) {
        print('__FitTextBoxState build');
    
        var headerWidget = widget.fixedHeightHeaderWidget ?? Container();
        var bottomWidget = widget.fixedHeightBottomWidget ?? Container();
        if (!_layoutReady) {
          return Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              headerWidget,
              Expanded(
                child: Container(
                  child: LayoutBuilder(builder: (context, constraints) {
                    _calculateAndSetFontSize(Size(constraints.maxWidth, constraints.maxHeight));
                    return Container(
                      child: Text('empty'),
                    );
                  }),
                ),
              ),
              bottomWidget,
            ],
          );
        }
    
        Widget childWidget = Container(
          child: Center(
            child: Text(
              widget.showText,
              style: TextStyle(
                fontSize: _realFontSize,
              ),
            ),
          ),
        );
    
        if (_needScroll) {
          childWidget = SingleChildScrollView(
            child: childWidget,
          );
        }
    
        return Container(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              headerWidget,
              _needCenter
                  ? childWidget
                  : Expanded(
                      child: childWidget,
                    ),
              bottomWidget,
            ],
          ),
        );
      }
    }
    

    原文git代码地址

    相关文章

      网友评论

          本文标题:flutter中固定区域智能显示文本框

          本文链接:https://www.haomeiwen.com/subject/wtjlnqtx.html