'Multiline text fields on iOS with flutter_native_text_input

I want to use the flutter_native_text_input Flutter plugin to render multi-line native text fields in an iOS Flutter app, because autocorrect is not working with Cupertino text fields. I expect it to always show an integer number of lines. However, if the text field is at the maximum number of lines the padding no longer works well; sometimes lines are getting cut off at the top and the padding on the bottom is too small. You can see the issue in this video:

text padding issue

To reproduce, flutter create myapp && cd myapp && flutter pub add flutter_native_text_input. (The video uses flutter_native_text_input 2.2.0.) Then paste this code sample (copied from https://github.com/indjec/native-text-field) into lib/main.dart.

import 'package:flutter/material.dart';
import 'package:flutter_native_text_input/flutter_native_text_input.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: const MyChatScreen(),
    );
  }
}

class MyChatScreen extends StatefulWidget {
  const MyChatScreen({Key? key}) : super(key: key);

  @override
  State<MyChatScreen> createState() => _MyChatScreenState();
}

class _MyChatScreenState extends State<MyChatScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.green,
      body: SafeArea(
        child: Column(
          children: const [
            Expanded(
              child: Text(
                'DEMO',
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  color: Colors.white,
                ),
              ),
            ),
            BottomBar(),
          ],
        ),
      ),
    );
  }
}

class BottomBar extends StatefulWidget {
  const BottomBar({
    Key? key,
  }) : super(key: key);

  @override
  _BottomBarState createState() => _BottomBarState();
}

class _BottomBarState extends State<BottomBar> {
  //Controller for text message
  final TextEditingController _messageController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Container(
      constraints: const BoxConstraints(
        minHeight: 54,
      ),
      padding: const EdgeInsets.only(
        bottom: 6.0,
        top: 6.0,
        left: 15.0,
        right: 15.0,
      ),
      child: () {
        final textBar = ConstrainedBox(
          constraints: const BoxConstraints(
            minHeight: 36,
          ),
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.end,
            children: [
              Expanded(
                child: DecoratedBox(
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(19),
                    border: Border.all(
                      width: 0.5,
                      color: const Color(0xffCFCFCF),
                    ),
                  ),
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      const SizedBox(width: 12.0),
                      Expanded(
                        child: NativeTextInput(
                          controller: _messageController,
                          minLines: 1,
                          maxLines: 6,
                          keyboardType: KeyboardType.defaultType,
                          returnKeyType: ReturnKeyType.defaultAction,
                          iosOptions: IosOptions(
                            keyboardAppearance: Brightness.light,
                          ),
                          placeholder: "Message",
                          textCapitalization: TextCapitalization.sentences,
                          onChanged: (val) {},
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        );

        return Stack(
          children: [
            Visibility(
              maintainState: true,
              child: textBar,
            ),
          ],
        );
      }(),
    );
  }
}

Is there a solution (either a different approach to text input, or a code change for this plugin) that will:

  • support autocorrect properly; and
  • make the padding look like a native text field (default 8px content insets) and the padding doesn't disappear when lines wrap?

I'm only interested in iOS solutions since I'm planning to use a Flutter text field on Android.

Related GitHub issue



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source