Davide Pulvirenti
Davide Pulvirenti

Reputation: 55

Display a text string and change it dynamically Flutter/Dart

Basically what i want to do is to display a name taken from a file that contains many others, and after a small delay, the given name changes into another word. The text that i wanna change is inside a Text() widget.

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

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

/*
 *  Retriving data from file, picking a random word and assign it to dataFromFile
 */

class _ReadTextFileState extends State<ReadTextFile> {

  String dataFromFile = "";
  static List<String> listOne = []; //contains all jobs.txt content, from top to bottom
  int randomIndex = Random().nextInt(1027); //quick fix to "RangeError" thrown by Random().nextInt(listOne.length)

  Future<void> readText() async {
    final String response = await rootBundle.loadString('assets/jobs.txt');
    listOne = response.split(',');
    setState(() {
      dataFromFile = listOne[randomIndex];
    });
  }

  @override
  Widget build(BuildContext context) {
    readText();
    // showRandomJob();
    return Container(child: Center(child: Text(dataFromFile)));
  }
} 

Widget tree:

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final appTitle = 'ListGenerator';

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          foregroundColor: Color.fromARGB(255, 32, 75, 132),
          title: Text(appTitle),
          centerTitle: true,
          backgroundColor: Color.fromARGB(255, 11, 161, 242),
        ),
        body: Column(
          children: const[
             Expanded(
                flex: 1,
                child: SingleChildScrollView(
                  scrollDirection: Axis.vertical,
                  child: ReadTextFile(),
                )),
          ],
        ),
      ),
    );
  }
 
}

As a plus, i'd like to know why passing listOne.length as a parameter to Random.nextInt() generates these 2 errors.

After running a hot restart:

RangeError (max): Must be positive and <= 2^32: Not in inclusive range 1..4294967296:
0
See also: https://flutter.dev/docs/testing/errors

Running a hot reload after a hot restart:

'package:flutter/src/widgets/framework.dart': Failed assertion: line 6205 pos 12: 'child == _child': is not true. See also: https//flutter.dev/docs/testing/errors

Upvotes: 2

Views: 3004

Answers (2)

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63569

readText() is a Future method, you need to await before using its data. Next thing is we can't tell what should be the response list. We need to act based on list items.

class _ReadTextFileState extends State<ReadTextFile> {
  String dataFromFile = "";
  static List<String> listOne = [];

  Future<void> readText() async {
    final String response = await rootBundle.loadString('assets/jobs.txt');
    listOne = response.split(',');

    int c = 0;
    if (listOne.isEmpty) return;
    Timer.periodic(Duration(seconds: 1), (timer) {
      if (c == listOne.length - 1) {
        timer.cancel();
        return;
      }
      if (c != 0) dataFromFile += ",";
      dataFromFile += listOne[c];
      c++;
      setState(() {});
    });
  }

  void initData() async {
    await readText();
  }

  @override
  void initState() {
    super.initState();
    initData();
  }

  @override
  Widget build(BuildContext context) {
    return Container(child: Center(child: Text(dataFromFile)));
  }
}

Upvotes: 1

Dulaj Nadawa
Dulaj Nadawa

Reputation: 603

Use Timer() inside the initState and move the randomIndex line inside the readText() function

import 'dart:async';
import 'dart:math';

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

class ReadTextFile extends StatefulWidget {
  @override
  _ReadTextFileState createState() => _ReadTextFileState();
}

class _ReadTextFileState extends State<ReadTextFile> {

  String dataFromFile = "";
  static List<String> listOne = [];

  Future<void> readText() async {
    final String response = await rootBundle.loadString('assets/jobs.txt');
    listOne = response.split(',');
    int randomIndex = Random().nextInt(listOne.length);
    setState(() {
      dataFromFile += listOne[randomIndex]+", ";
    });
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    Timer.periodic(Duration(seconds: 1), (val) async {
      await readText();
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Container(child: Center(child: Text(dataFromFile)));
  }
}

Upvotes: 0

Related Questions