【问题标题】:Flutter Listview with Dynamic amount of Textfields covered by Keyboarrd具有键盘覆盖的动态文本字段数量的 Flutter Listview
【发布时间】:2020-09-28 04:24:51
【问题描述】:

我有一个 scoffold,它有一个列和 listview,它有一个文本字段列表,我们可以在搜索项目时将其添加到列表中,此时发生的事情是在列表超过 5 个时的某个点键盘覆盖列表中最新文本字段的项目,因此在键入值时不可见,

我尝试用 SingleChildScrollView 包裹正文并在列表视图上设置 NoScrollPhysics 但屏幕没有滚动

Widget pageFour() {
    return Builder(builder: (BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          backgroundColor: Colors.white,
          centerTitle: true,
          title: Text(
            'New Log',
            style: kTextStyleBold,
          ),
          actions: <Widget>[
            GestureDetector(
              onTap: () async {
                await _draftDialog().then((_) => Navigator.pop(context));
              },
              child: Center(
                child: Padding(
                  padding: const EdgeInsets.only(right: 15.0),
                  child: Text(
                    'Cancel',
                    style: kAppBarEdit,
                  ),
                ),
              ),
            ),
          ],
          leading: IconButton(
            icon: Icon(Icons.arrow_back_ios),
            color: Colors.black87,
            onPressed: () {
              setState(() {
                _currentStep--;
              });
            },
          ),
        ),
        resizeToAvoidBottomInset: false,
        bottomNavigationBar: SizedBox(
          height: 70,
          child: RawMaterialButton(
            onPressed: () {
              setState(() {
                if (_treatments.isNotEmpty) {
                  _subtotal = 0;
                  _treatments.forEach((tr) {
                    setState(() {
                      _subtotal += tr.total;
                    });
                  });
                  calcSummary();
                  _currentStep++;
                } else {
                  Flushbar(
                    flushbarPosition: FlushbarPosition.BOTTOM,
                    isDismissible: false,
                    shouldIconPulse: true,
                    duration: Duration(seconds: 2, milliseconds: 500),
                    borderRadius: 5,
                    animationDuration: Duration(milliseconds: 900),
                    margin: EdgeInsets.only(bottom: 75),
                    boxShadows: [
                      BoxShadow(
                          color: Colors.black26,
                          offset: Offset(0.0, 2.0),
                          blurRadius: 3.0)
                    ],
                    backgroundColor: Colors.white,
                    icon: Icon(Icons.error_outline, color: Colors.red.shade600),
                    maxWidth: MediaQuery.of(context).size.width * 0.6,
                    flushbarStyle: FlushbarStyle.FLOATING,
                    messageText: Text(
                      'Error please enter treatment data!',
                      style: TextStyle(
                        color: Colors.red.shade600,
                        fontWeight: FontWeight.w500,
                        fontFamily: 'NeueMontreal',
                      ),
                    ),
                  )..show(context);
                }
              });
            },
            fillColor: Color.fromRGBO(46, 54, 143, 1),
            child: Padding(
              padding: const EdgeInsets.only(bottom: 15),
              child: Text(
                'Next',
                style: kTextStyleButton,
              ),
            ),
          ),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            SizedBox(
              height: 20,
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                SizedBox(
                  height: 50,
                  width: MediaQuery.of(context).size.width,
                  child: _autoCompleteTextField =
                      AutoCompleteTextField<Treatments>(
                          key: key,
                          style: kTextStyleHint,
                          controller: _controller,
                          suggestionsAmount: 20,
                          focusNode: _autoComp,
                          decoration: InputDecoration(
                            contentPadding: EdgeInsets.all(15),
                            hintText: "Search Treatment Type",
                            suffixIcon: IconButton(
                              icon: Icon(Icons.clear),
                              iconSize: 18,
                              color: Colors.black87,
                              onPressed: () => _autoCompleteTextField.clear(),
                            ),
                            focusedBorder: kBorderStyleField,
                            disabledBorder: kBorderStyleField,
                            enabledBorder: kBorderStyleField,
                          ),
                          suggestions: suggestions,
                          itemSubmitted: (item) {
                            TreatmentData trData = TreatmentData(
                                code: int.parse(item.code),
                                description: item.name,
                                created: _date,
                                clinicId: _clinic.id,
                                cost: 0,
                                quantity: 1,
                                total: 0,
                                logId: id,
                                uid: uid,
                                focusNode: FocusNode());
                            setState(() {
                              _treatments.add(trData);
                            });
                            WidgetsBinding.instance.addPostFrameCallback((_) {
                              FocusScope.of(context).requestFocus(
                                  _treatments[_treatments.length - 1]
                                      .focusNode);
                            });
                          },
                          itemSorter: (a, b) {
                            return country == 'United Kingdom'
                                ? a.name.compareTo(b.name)
                                : a.code.compareTo(b.code);
                          },
                          itemBuilder: (context, item) {
                            return ListTile(
                              trailing: Text(
                                country == 'United Kingdom'
                                    ? ''
                                    : item.code == '000' ? '' : item.code,
                                style: kTextStyleBoldCode,
                              ),
                              title: Text(
                                item.description,
                                style: kTextStyleBoldCode,
                                overflow: TextOverflow.ellipsis,
                              ),
                              subtitle: Text(
                                item.name,
                                style: kTextStyle,
                              ),
                            );
                          },
                          itemFilter: (item, query) {
                            return _isNumeric(query)
                                ? item.code.startsWith(query)
                                : item.autocompleteTerm
                                    .toLowerCase()
                                    .contains(query.toLowerCase());
                          }),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.only(
                  top: 3, left: 10, right: 10, bottom: 10),
              child: Container(
                width: double.infinity,
                height: 1.0,
                color: kDividerColor,
              ),
            ),
            Expanded(
              child: ListView.separated(
                itemCount: _treatments.length,
                itemBuilder: (context, index) {
                  return Container(
                    height: 55,
                    child: Dismissible(
                      key: ValueKey(_treatments[index]),
                      direction: DismissDirection.endToStart,
                      background: Container(
                        alignment: AlignmentDirectional.centerEnd,
                        color: Colors.red[600],
                        child: Padding(
                          padding: const EdgeInsets.only(right: 15.0),
                          child: Icon(
                            Icons.delete_outline,
                            color: Colors.white,
                            size: 24,
                          ),
                        ),
                      ),
                      confirmDismiss: (direction) async {
                        setState(() {
                          _treatments.removeAt(index);
                        });
                        return true;
                      },
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceAround,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: <Widget>[
                          Column(
                            mainAxisSize: MainAxisSize.max,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                              Text(
                                _treatments[index].description,
                                style: _treatments[index].cost != 0
                                    ? kTextStylePink
                                    : kTextStyle,
                                textAlign: TextAlign.left,
                              ),
                              ConstrainedBox(
                                constraints: BoxConstraints(
                                  maxHeight: 20,
                                  maxWidth:
                                      MediaQuery.of(context).size.width * 0.6,
                                ),
                                child: TextFormField(
                                  keyboardType: TextInputType.numberWithOptions(
                                      signed: true, decimal: true),
                                  autofocus: false,
                                  focusNode: _treatments[index].focusNode,
                                  initialValue: _treatments[index].cost != 0
                                      ? _treatments[index].cost.toString()
                                      : "",
                                  style: _treatments[index].cost != 0
                                      ? kTextStyleFormLabelPink
                                      : kTextStyleFormLabelBlack,
                                  validator: validateNumber,
                                  decoration: InputDecoration(
                                      contentPadding:
                                          EdgeInsets.only(bottom: 0),
                                      prefix: Text(
                                        country == 'United Kingdom'
                                            ? '\u00A3'
                                            : '\$',
                                        style: _treatments[index].cost != 0
                                            ? kTextStyleFormLabelPink
                                            : kTextStyleFormLabelBlack,
                                      ),
                                      hintText: '0.00',
                                      hintStyle: kTextStyleFormLabelBlack,
                                      border: InputBorder.none),
                                  onFieldSubmitted: (String newValue) {
                                    setState(() {
                                      double cost = double.parse(newValue);
                                      _treatments[index].cost = cost;
                                      _treatments[index].total =
                                          (cost * _treatments[index].quantity);
                                    });
                                  },
                                ),
                              ),
                            ],
                          ),
                          Row(
                            crossAxisAlignment: CrossAxisAlignment.center,
                            children: <Widget>[
                              IconButton(
                                icon: Icon(
                                  Icons.remove,
                                  color: Color.fromRGBO(46, 54, 143, 1),
                                  size: 20,
                                ),
                                splashColor: Colors.black12,
                                highlightColor: Colors.black12,
                                onPressed: () {
                                  setState(() {
                                    if (_treatments[index].quantity > 1) {
                                      _treatments[index].quantity--;
                                      _treatments[index].total =
                                          (_treatments[index].quantity *
                                              _treatments[index].cost);
                                    }
                                  });
                                },
                              ),
                              Text(
                                _treatments[index].quantity.toString(),
                                style: kTextStyleBold,
                              ),
                              IconButton(
                                icon: Icon(
                                  Icons.add,
                                  color: Color.fromRGBO(46, 54, 143, 1),
                                  size: 20,
                                ),
                                splashColor: Colors.black12,
                                highlightColor: Colors.black12,
                                onPressed: () {
                                  setState(() {
                                    _treatments[index].quantity++;
                                    _treatments[index].total =
                                        (_treatments[index].quantity *
                                            _treatments[index].cost);
                                  });
                                },
                              ),
                            ],
                          ),
                        ],
                      ),
                    ),
                  );
                },
                separatorBuilder: (context, index) => Padding(
                  padding: const EdgeInsets.symmetric(vertical: 8.0),
                  child: Divider(
                    height: 1.0,
                    thickness: 1.0,
                    indent: 15.0,
                    endIndent: 15.0,
                    color: kDividerColor,
                  ),
                ),
              ),
            ),
          ],
        ),
      );
    });
  }

当列表中的最后一项处于焦点时,我可以做些什么来使列表滚动以显示在键盘顶部的任何想法

谢谢

【问题讨论】:

  • 您是否尝试过仅使用 ListView 包裹 Expanded?通常,对我来说,由于Expanded,当我的键盘出现时,它会自动调整ListView 的大小,就好像屏幕变小了一样。我不确定在使用 ListView.separated 时是否适用相同的行为

标签: listview flutter textfield


【解决方案1】:

也许您可以尝试使用如下所示的 customScrollview。

您可以尝试将 textField 直接添加为 CustomScrollView 的子级或 sliverList 的子级,具体取决于您的要求。并将 NeverScrollableScrollPhysics() 添加到您的 ListView。

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: CustomScrollView(slivers: <Widget>[

        AutoCompleteTextField<Treatments>(
              key: key,
              style: kTextStyleHint,
              controller: _controller,
              . . .
              . . .
        ),

        SliverList(
          delegate: SliverChildListDelegate([
            Column(
              mainAxisSize: MainAxisSize.max,
            children: <Widget>[

            ListView.separated(
              physics: NeverScrollableScrollPhysics(),
              shrinkWrap: true,
              itemCount: _treatments.length,
              itemBuilder: (context, index) {
              return Container(
              height: 55,



              child: Dismissible(
              key: ValueKey(_treatments[index]),
              direction: DismissDirection.endToStart,
              . . .
              . . .
            )
          ),)
            ],
          )
        ]),
      ),
    ]),
  );
}

希望这会有所帮助!

【讨论】:

  • 嗨@anup sajaan,我已经尝试过了,但它仍然不起作用,我的 Texfields 构建在 ListView 内,一旦我到达一定数量的项目,它不会向上滚动或滚动列表中的项目全身上下。
  • 我认为使用 customScrollView 和使用 NeverScrollablePhysics 到你的 listView 就可以了。您是否也在 listView 中构建 TextFields 也没关系。再试一次?
猜你喜欢
  • 2020-10-13
  • 2022-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
  • 1970-01-01
  • 2020-06-22
相关资源
最近更新 更多