How to automatically add a list in the next line if the current line has one in a Flutter app: A Step by step tutorial

Flutter provides an extensive set of tools for creating beautiful and responsive user interfaces. One of the most commonly used widgets in Flutter is the TextFormField, which allows users to input text into an app.

Photo by Fahim Muntashir on Unsplash


In this tutorial, we'll show you how to use Flutter to automatically add list items to the next line in a text field if the current line has a hyphen at the beginning.

Prerequisite

Before we get started, make sure you have Flutter installed on your machine. You can download Flutter and follow the installation instructions from the official Flutter website.

Setting Up the Project 

Once Flutter is installed, create a new Flutter project by running the following command in your terminal:
flutter create flutter_autohyphenation

This line will create starter template for flutter which consist code for counter application using `stateful_widget` in `lib\main.dart` file . You need to copy this following code and paste it there.


import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Autohyphenation'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  TextEditingController descController = TextEditingController();
  String previousText = "", currentText = "";
  dynamic _hyphenate() {
    final value = descController.value;
    final cursorPosition = descController.selection.base.offset;
    final text = value.text;
    final selection = value.selection;
    final textList = text.substring(0, selection.extentOffset).split('\n');
    currentText =
        textList.length <= 1 ? textList[0] : textList[textList.length - 2];
    if (text.substring(0, selection.extentOffset).endsWith("\n")) {
      if (currentText.length > 0 &&
          currentText[0] == "-" &&
          text.length > previousText.length) {
        final newCursorPosition = cursorPosition + 1;
        descController.value = TextEditingValue(
          text: text.substring(0, selection.extentOffset) +
              "-" +
              text.substring(selection.extentOffset, text.length),
          selection: TextSelection.collapsed(offset: newCursorPosition),
        );
      }
    }
    previousText = text;
    return descController.value;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: SingleChildScrollView(
            child: TextFormField(
              controller: descController,
              style: TextStyle(color: Colors.grey[800], fontSize: 18),
              decoration: InputDecoration(
                border: InputBorder.none,
                hintText: 'Type something...',
                hintStyle: TextStyle(color: Colors.blue),
              ),
              maxLines: null,
              textInputAction: TextInputAction.newline,
              onChanged: (value) {
                descController.value = _hyphenate(descController);
              },
            ),
          ),
        ),
      ),
    );
  }
}

The MyHomePage widget contains a TextFormField widget that will allow us to type text and a _hyphenate() function will run whenever someone types in `textfield`, it's possible due to onChanged() function.

Code Explanation 

Breaking down this `_hyphenate` function into snippets which eventually adds hyphen to next line whenever anyone press enter. We will see it's step by step explanation:
  1. Get the current value of the text controller and cursor position:
  2. final value = descController.value;
    final cursorPosition = descController.selection.base.offset;
    
  3. Get the current text and text selection.Here the `text` variable holds the current text in the text controller. The selection variable holds the current text selection, which includes both the start and end indices of the selected text :
  4. final text = value.text;
    final selection = value.selection;
  5. Get the current line of text.Here, we split the text into lines using the newline character (\n) as the delimiter. We take the substring of the text up to the end index of the current text selection (selection.extentOffset). We then take the last line of the resulting list of lines (textList) as the current line of text (currentText). If the list of lines has only one line, we take that line as the current line of text.:
  6. final textList = text.substring(0, selection.extentOffset).split('\n');
    currentText = textList.length <= 1 ? textList[0] : textList[textList.length - 2];
  7. Check if the user pressed the Enter key & then also check if the current line starts with a hyphen.Here, we check if the current line of text has a length greater than zero and starts with a hyphen (-). We also check if the length of the text has increased since the last time this function was called, which indicates that the user has added new text & should not call this snippet when user press `backspace`:
  8. if (text.substring(0, selection.extentOffset).endsWith("\n")) {
    	if (currentText.length > 0 &&
        		currentText[0] == "-" &&
        		text.length > previousText.length) {
    	}
    }
  9. Add a hyphen to the next line of text.We add a hyphen to the next line of text by creating a new TextEditingValue with the modified text and cursor position. We insert the hyphen character (-) after the current text selection, and set the cursor position to the next index. :
  10. final newCursorPosition = cursorPosition + 1;
    descController.value = TextEditingValue(
      text: text.substring(0, selection.extentOffset) +
            "-" +
            text.substring(selection.extentOffset, text.length),
      selection: TextSelection.collapsed(offset: newCursorPosition),
    );
  11. Store the previous text & close both if statements. Finally,return a modified text controller value.:
  12. 
    previousText = text;
    }
    return descContoller.text;
    }
Here's how it looks after execution.




You can checkout github repo for the same as well.

Hope you got the idea for developing this feature using flutter, Thanx !!

Post a Comment

0 Comments