Home > Net >  Draggable text Portion inside Text Widget in Flutter
Draggable text Portion inside Text Widget in Flutter

Time:01-09

I am making a game where users can drag some portion - which is highligted with RED in the image - of String while not hurting rest of the String. To specify which text can be draggable, I encoded draggable portion in this format: x{String}x. And I decoded it in _constructGame function. I expected a well-organized String but it turns out it didn't happen. I encountered with a logical error, rather than a system error. But I can't just figure out. I tried making research but they are irrelevant with my issue.

To reach my goal, I also used a list of widget that goes like fixed text, draggable portion, fixed text, ...

import 'dart:math';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:schoolproject/GameTextList.dart';

class GameRoute extends StatefulWidget {

  @override
  State<StatefulWidget> createState() => _GameRouteState();
  
}

class _GameRouteState extends State<GameRoute>{

  // Random().nextInt(GameTextList.texts.length)
  String gameText = GameTextList.texts[0];

  Draggable _createDraggableText(String text) {
    return Draggable<String>(
      data: text,
      child: Text(
        text,
        style: TextStyle(fontWeight: FontWeight.bold, color: Colors.red),
      ),
      feedback: Text(
        text,
        style: TextStyle(fontSize: 16.0,fontWeight: FontWeight.bold, color: Colors.red),
      ),
      childWhenDragging: Text(
        text,
        style: TextStyle(color: Colors.grey),
      ),
    );
  }

  // Precondition: There must be at least one draggable
  List<Widget> _constructGame(String mes) {
    List<Widget> widgets = <Widget>[];

    // Decode the message
    int i = 0;
    int j = 0;
    while (i != mes.length - 1) {
      if (mes[i] == "x" && mes[i   1] == "{") {
        var last = mes.indexOf("}x", i);
        widgets.add(Text(mes.substring(j, i))); // Bugün hava çok
        widgets.add(_createDraggableText(mes.substring(i   2, last))); // soğuktu
        j = last   2;
      }
      i  ;
    }
    // add the remaining part of the text
    widgets.add(Text(mes.substring(j, mes.length)));
    return widgets;
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Egzersiz")),
      body: Wrap(
        children: _constructGame(gameText),
      )
      );
  }

}

class GameTextList {
    static List<String> texts = [
      "Bugün hava çok x{soğuktuuuuuuuuuuuuuuu}x. Fakat üstümüze mont giymeyi x{unuttuk}x. Şu an yağmur x{yağıyor}x. Son zamanlarda"
          " hava düzensiz olabileceğinden tedbirli olmak x{gerekecekmiş}x.",

      "Planktonların varlığı ekosistem için x{mühimdir}x hatta onlar x{olmasaydı}x  Dünyadaki canlıların bir çoğu yok "
          "x{olurdu}x. Nitekim bu canlılar atmosferdeki oksijenin P'sini x{oluştururlar}x. Yine de insanlar bilinçsizce"
          " denize atık bırakmaya devam x{ederse}x solunulacak bir x{kalmayacak}x.",

      "Uranyumun keşfedildiği tarih x{1789'dur}x.",

      """
Yapma x{ne olursun}x, bırak o yerimi x{doldursun}x. Bana ihtiyacın x{olursa}x sarıl ona, elbet x{unutursun}x.x{Girmişşe}x kalbine bambaşka biri...""",

    ];
}

abc

abc2

abc3

CodePudding user response:

after analyse your code, I made some changes in _constructGame in your method now its working. i simply debug and identify that you need add only one word at time in widgets list just like you do for extract x{Draggable Word}x.so i add code for normal string & commented old lines for the same.

Added code:

final noramlStringArray = normalString.split(" ");
    noramlStringArray.asMap().forEach((index, word) {
    if (index != (noramlStringArray.length - 1)) {
      widgets.add(Text("$word ")); // add word with trailing space 
    } else {
      widgets.add(Text(word)); // add last word without space 
    }
});

Added String extension for remove extra white spaces if string contains double or more spaces which replace with single white space.

extension on String {
  String removeExtraWhiteSpace() {
    return replaceAll(RegExp("[ \t\r\f]"), " ");
  }
}

used removeExtraWhiteSpace() extension in below line.

_constructGame(gameText.removeExtraWhiteSpace())

replace your _constructGame method with below code.

 // Precondition: There must be at least one draggable
List<Widget> _constructGame(String mes) {
    List<Widget> widgets = <Widget>[];
    
    try {
      // Decode the message
      int i = 0;
      int j = 0;
      while (i != mes.length - 1) {
        if (mes[i] == "x" && mes[i   1] == "{") {
          var last = mes.indexOf("}x", i);
    
          final normalString = mes.substring(j, i);
          final noramlStringArray = normalString.split(" ");
          noramlStringArray.asMap().forEach((index, word) {
            if (index != (noramlStringArray.length - 1)) {
              widgets.add(Text("$word ")); // add word with trailing space 
            } else {
              widgets.add(Text(word)); // add last word without space 
            }
          });
    
          //widgets.add(Text(mes.substring(j, i))); // Bugün hava çok
    
          widgets
              .add(_createDraggableText(mes.substring(i   2, last))); // soğuktu
          j = last   2;
        }
        i  ;
      }
      // add the remaining part of the text
      //widgets.add(Text(mes.substring(j, mes.length)));
      final normalString = mes.substring(j, mes.length);
    
      final noramlStringArray = normalString.split(" ");
      noramlStringArray.asMap().forEach((index, word) {
        if (index != (noramlStringArray.length - 1)) {
          widgets.add(Text("$word "));
        } else {
          widgets.add(Text(word));
        }
      });
      return widgets;
    } catch (ex) {
      debugPrint("Error: $ex");
      return widgets;
    }
}

if your word will not set in remain width then only it will set in newline automatically.

enter image description here

  • Related