FocusNode не выполняет автоматическую прокрутку до TextFormField, когда элемент уже выбран - дрожание - PullRequest
0 голосов
/ 13 июля 2020

Сценарий: это большая форма, пользователь выбирает TextFormField и затем вручную прокручивает вниз до кнопки сохранения. если _formKey.currentState.validate() обнаруживает проблемы проверки, мы можем вернуть фокус обратно на TextFormField с проблемами.

сначала мы вызываем _myFocusNode.unfocus(); // это работает, потому что ключевое слово автоматически закрывается. Затем мы вызываем FocusScope.of(context).requestFocus(_myFocusNode) // это тоже работает, потому что мы можем сразу же начать печатать. но FocusScope.of(context).requestFocus автоматически не возвращается к TextFormField.

Если мы попытаемся перейти к другому TextFormField (Tfield2), отличному от последнего выбранного, Tfield2 получит фокус, и прокрутка также сделает это видим.

ПРИМЕЧАНИЕ: если мы снова начнем печатать, прокрутка будет выполнена, и TextFormField станет видимым.

https://github.com/flutter/flutter/issues/58877

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Material App',
      theme: ThemeData.dark(),
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
  bool show = false;
  TextEditingController cnt1 = new TextEditingController();
  TextEditingController cnt2 = new TextEditingController();
  TextEditingController cnt3 = new TextEditingController();
  TextEditingController cnt4 = new TextEditingController();
  TextEditingController cnt5 = new TextEditingController();
  TextEditingController cnt6 = new TextEditingController();
  TextEditingController cnt7 = new TextEditingController();
  TextEditingController cnt8 = new TextEditingController();

  FocusNode _focuserr;
  FocusNode _focus1;
  FocusNode _focus2;
  FocusNode _focus3;
  FocusNode _focus4;
  FocusNode _focus5;
  FocusNode _focus6;
  FocusNode _focus7;
  FocusNode _focus8;

 @override
  void dispose() {
    // Clean up the focus node when the Form is disposed.
    _focuserr.dispose();
    _focus1.dispose();
    _focus2.dispose();
    _focus3.dispose();
    _focus4.dispose();
    _focus5.dispose();
    _focus6.dispose();
    _focus7.dispose();
    _focus8.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    _focus1 = new FocusNode();
    _focus2 = new FocusNode();
    _focus3 = new FocusNode();
    _focus4 = new FocusNode();
    _focus5 = new FocusNode();
    _focus6 = new FocusNode();
    _focus7 = new FocusNode();
    _focus8 = new FocusNode();

    return Scaffold(
      appBar: AppBar(
        title: Text('Material App Bar'),
      ),
      body: Center(
        child: Container(
          child: Text('Hello World'),
        ),
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: () {
          showModalBottomSheet(
            context: context,
            isScrollControlled: true,
            builder: (context) => StatefulBuilder(
              builder: (context, setState) {
                return Padding(
                  padding: EdgeInsets.only(left:10, right: 10, bottom: MediaQuery.of(context).viewInsets.bottom + 5),
                  child: Container(
                    height: 300,
                    child: SingleChildScrollView(
                      child: Form(
                        key: _formKey,
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            createTextField(cnt1, _focus1, 1),
                            createTextField(cnt2, _focus2, 2),
                            createTextField(cnt3, _focus3, 3),
                            createTextField(cnt4, _focus4, 4),
                            createTextField(cnt5, _focus5, 5),
                            createTextField(cnt6, _focus6, 6),
                            createTextField(cnt7, _focus7, 7),
                            createTextField(cnt8, _focus8, 8),
                            RaisedButton(
                                child: Text('Validate'),
                                onPressed: () {
                                  _validateInputs(context);
                                })
                          ],
                        ),
                      ),
                    ),
                  ),
                );
              },
            ),
          );
        },
        icon: Icon(Icons.add),
        label: Text('bottomsheet'),
      ),
    );
  }

  Widget createTextField(TextEditingController c, FocusNode f, int id){
  return Padding(
      padding: const EdgeInsets.only(
          top: 5, bottom: 5, left: 10, right: 10),
      child: Container(
        color: Colors.lightBlue.withOpacity(0.3),
        child:
        TextFormField(
          controller: c,
          focusNode: f,
          validator: (val) {
            var result = isNotNull(val);
            if(result != null && _focuserr == null)
              _focuserr = f;
              
            return result;
          },
          decoration: InputDecoration(
            counterText : "",
            hintStyle: TextStyle(fontSize: 17),
            hintText: 'TXT$id',
            border: InputBorder.none,
            focusedBorder: UnderlineInputBorder(
                borderSide: BorderSide(color: Colors.blue[300], width: 0.3)),
            enabledBorder: InputBorder.none,
            errorBorder: InputBorder.none,
            disabledBorder: InputBorder.none,
            contentPadding: const EdgeInsets.only(left: 10, top: 0),
          ),
        ),
      )
    );
  }

  void _validateInputs(BuildContext cnt) {
    final form = _formKey.currentState;
    _focuserr = null;
    
    if (form.validate()) {
      form.save();
    }
    else
    {
      setState(() {
        FocusManager.instance.primaryFocus.unfocus();
        FocusScope.of(cnt).requestFocus(_focuserr);
      });
    }
  }

  String isNotNull(String val) =>
      (val.length == 0) ? 'Cannot be empty' : null;
}

Демо:

1 Ответ

0 голосов
/ 22 июля 2020

оказалось подтвержденной проблемой в стабильной версии 17, а также в новом канале разработчиков

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...