Home > front end >  Make some parts of TextField Editable
Make some parts of TextField Editable

Time:10-29

So I have this unique requirement as shown in the picture below, where the blue texts are user inputs. I have been doing my own research regarding this and have found a few viable solutions, out of which a custom TextEditingController seems most promising. I haven't started implementation but out of the top of my head, I think I might run into some problems with the touch and cursor controls later on.

Now my question is, Is there a better way that I might have overlooked? Is there a way to gracefully handle which areas are touchable, handle the cursor when deleting, and moving to the next focus?

enter image description here

CodePudding user response:

As suggested by @Andrey Gordeev, we can use a Wrap Widget with a children defined as follows:

Wrap(
  alignment: WrapAlignment.center,
  runAlignment: WrapAlignment.center,
  children: [
    const Text('Hala, we\'re '),
    SizedBox(
      width: 50,
      height: 20,
      child: TextField(
        controller: TextEditingController.fromValue(
          const TextEditingValue(text: 'aryab'),
        ),
      ),
    ),
    const Text(' You? I\'m '),
    SizedBox(
      width: 150,
      height: 20,
      child: TextField(
        controller: TextEditingController.fromValue(
          const TextEditingValue(text: 'Someone Awesome'),
        ),
      ),
    ),
  ],
)

This renders the result of the screenshot attached:

screenshot

A full example snippet can be found below:

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Demo',
      home: MyHomePage(),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: 
        Wrap(
          alignment: WrapAlignment.center,
          runAlignment: WrapAlignment.center,
          children: [
            const Text('Hala, we\'re '),
            SizedBox(
              width: 50,
              height: 20,
              child: TextField(
                controller: TextEditingController.fromValue(
                  const TextEditingValue(text: 'aryab'),
                ),
              ),
            ),
            const Text(' You? I\'m '),
            SizedBox(
              width: 150,
              height: 20,
              child: TextField(
                controller: TextEditingController.fromValue(
                  const TextEditingValue(text: 'Someone Awesome'),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

CodePudding user response:

While there are two types of widgets, <plainText,inputText> can be placed here, and we need to concern about retrieving full text from the form/text.

Creating a map for the widgets will be a good choice, I think.

  final Map<String, String?> _textsInForm = {
    "Hala, we're": null,
    "aryab": "groupName",
    ". You? I'm": null,
    "Someone Awysome": "myself",
    ",a": null,
    "Driver": "job",
  };

As you can see, I'm using key as main value and value as nullable string. If we find null-string, it will be simply Text widget, else TextFiled.

I'm using RichText to handle this situation.

We will create list List<InlineSpan> for RichText and List<TextEditingController> to handle input text.

I'm using StatelessWidget, while having stateFullWidget handle creation on initState.

There is one issue, it is taking minimum hint text width. You can try with passing text on TextEditingController instead.

enter image description here

import 'package:flutter/material.dart';

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

  final Map<String, String?> _textsInForm = {
    "Hala, we're": null,
    "aryab": "groupName",
    ". You? I'm": null,
    "Someone Awysome": "myself",
    ",a": null,
    "Driver": "job",
  };

  final TextStyle _hintTextStyle = const TextStyle(
    color: Colors.grey,
  );

  final TextStyle _textFiledStyle = const TextStyle(
    color: Colors.blue,
  );

  WidgetSpan _textFiled(TextEditingController controller, String hint) =>
      WidgetSpan(
        alignment: PlaceholderAlignment.middle, // set middle according to texts
        child: IntrinsicWidth(
          //flexiable size
          child: TextField(
            style: _textFiledStyle,
            controller: controller,
            decoration: InputDecoration(
              hintStyle: _hintTextStyle,
              hintText: hint,
              border: InputBorder.none,
            ),
          ),
        ),
      );

  @override
  Widget build(BuildContext context) {
    List<TextEditingController> controllers = [];

    List<InlineSpan> textSpans = [];

    _textsInForm.forEach((key, value) {
      if (value != null) {
        TextEditingController controller = TextEditingController();

        controllers.add(controller);
        textSpans.add(_textFiled(controller, key));
      } else {
        textSpans.add(TextSpan(text: "$key "));
      }
    });

    return Scaffold(
      body: Column(
        children: [
          RichText(
            text: TextSpan(children: textSpans),
          ),
          ElevatedButton(
            onPressed: () {
              String result = "";
              int i = 0;

              _textsInForm.forEach((key, value) {
                if (value != null) {
                  final textFromIcontroller = controllers[i  ].text;
                  result  = "$textFromIcontroller ";
                } else {
                  result  = "$key ";
                }
              });

              print(result);
            },
            child: Text("Get Text"),
          ),
        ],
      ),
    );
  }
}

  • Related