Home > Blockchain >  How to have an onTap gesture multiple levels below effect a top level String Variable?
How to have an onTap gesture multiple levels below effect a top level String Variable?

Time:12-22

I've created a stateful Widget as my main page with a String variable, textToDisplay.

import 'package:flutter/material.dart';

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

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  String textToDisplay = 'Choose option';
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          children: [
            Text(
              '$textToDisplay',
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(
              height: 20,
            ),
            Choices(onTap: (){setState(() {
              textToDisplay =
            });},),
          ],
        ),
      ),
    );
  }
}

I have then created a stateless widget in another dart file called Choices().

class Choices extends StatelessWidget {
  Choices({required this.onTap});

  final VoidCallback? onTap;
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SizedBox(
          height: 20,
        ),
        Buttons(text: 'Option A', onTap: onTap),
        SizedBox(
          height: 10,
        ),
        Buttons(text: 'Option B', onTap: onTap),
      ],
    );
  }
}

and in this are 2 stateless widget buttons which have the ontap gesture.

class Buttons extends StatelessWidget {
  Buttons({required this.text, required this.onTap});

  final String text;
  final VoidCallback? onTap;

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: onTap,
      child: Container(
        color: Colors.green,
        width: 100,
        height: 40,
        child: Text(
          text,
        ),
      ),
    );
  }
}

I can pass the onTap gesture up the tree but what I need to do is when a button is pressed, it updates the variable, textToDisplay to display option A or Option B, depending on which button has been pressed.

I thought i could do this with a stateless widget (Choices()) because the data isn't chageing it is only being read

any help would be greatly appreciated.

CodePudding user response:

One way of updating the top-level string is the create your own Callback using ValueChanged.

Here is a complete working example:

import 'package:flutter/material.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MainPage(),
        ),
      ),
    );
  }
}

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

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  String textToDisplay = 'Choose option';
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          children: [
            Text(
              textToDisplay,
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(
              height: 20,
            ),
            Choices(
              onTap: (val) {
                setState(() {
                  textToDisplay = val;
                });
              },
            ),
          ],
        ),
      ),
    );
  }
}

class Choices extends StatelessWidget {
  Choices({required this.onTap});

  final ValueChanged? onTap;
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SizedBox(
          height: 20,
        ),
        Buttons(
          text: 'Option A',
          onTap: onTap,
        ),
        SizedBox(
          height: 10,
        ),
        Buttons(text: 'Option B', onTap: onTap),
      ],
    );
  }
}

class Buttons extends StatelessWidget {
  Buttons({required this.text, required this.onTap});

  final String text;
  final ValueChanged? onTap;

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {
        if (onTap != null) {
          onTap!(text);
        }
      },
      child: Container(
        color: Colors.green,
        width: 100,
        height: 40,
        child: Text(
          text,
        ),
      ),
    );
  }
}

CodePudding user response:

you can use function with parameter

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

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  String textToDisplay = 'Choose option';
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          children: [
            Text(
              textToDisplay,
              style: const TextStyle(fontSize: 20),
            ),
            const SizedBox(
              height: 20,
            ),
            Choices(
              onTap: (text) {
                _chageText(text);
              },
            ),
          ],
        ),
      ),
    );
  }

  void _chageText(String text) {
    setState(() {
      textToDisplay = text;
    });
  }
}

class Choices extends StatelessWidget {
  const Choices({super.key, required this.onTap});

  final Function(String text) onTap;
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        const SizedBox(
          height: 20,
        ),
        Buttons(text: 'Option A', onTap: () => onTap('Option A')),
        const SizedBox(
          height: 10,
        ),
        Buttons(text: 'Option B', onTap: () => onTap('Option B')),
      ],
    );
  }
}

class Buttons extends StatelessWidget {
  const Buttons({super.key, required this.text, required this.onTap});

  final String text;
  final VoidCallback? onTap;

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: onTap,
      child: Container(
        color: Colors.green,
        width: 100,
        height: 40,
        child: Text(
          text,
        ),
      ),
    );
  }
}
  • Related