Home > OS >  How to make two text fields that show related content, and editable?
How to make two text fields that show related content, and editable?

Time:11-24

I'am trying to do a mobile app which is about crypto currencies.

I want to make two TextFields like USDT and BTC, And they are supposed to work like:

Let me say that BTC is equal to 15$,

And USDT is equal to 1$,

Now those text fields should be editable. so if I write 1 on BTC textfield, USDT textfield should me edited as 15.

Also, when I write 30 on USDT textfield, BTC field should become 2. Moreover, while in this position, if I delete 0 from the usdt field, BTC should updated with "0.something" directly.

How can I do that?

Thanks for the replies !

I managed to do something like USDT is input, and BTC is output. However, I want to make them both input and output. Below are my classes, widgets and codes.

import 'package:cryptx/Constants/app_colors.dart';
import 'package:cryptx/Providers/basic_providers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class USDTInput extends ConsumerWidget {
  const USDTInput({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 12.0),
      child: TextField(
        decoration: InputDecoration(
          icon: SizedBox(
              height: 30,
              child: Image.network(
                  "https://assets.coingecko.com/coins/images/325/small/Tether.png?1668148663")),
          hintText: "USDT",
          border: InputBorder.none,
        ),
        onChanged: (value) {
          ref
              .read(usdProvider.notifier)
              .update((state) => value != "" ? num.parse(value) : 0);
        },
        autocorrect: false,
        keyboardType: const TextInputType.numberWithOptions(decimal: true),
      ),
    );
  }
}
import 'package:cryptx/Objects/coin.dart';
import 'package:cryptx/Providers/basic_providers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class CoinOutput extends ConsumerWidget {
  const CoinOutput({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    Coin coin = ref.watch(coinDetailProvider) as Coin;
    num usd = ref.watch(usdProvider);
    num amount = usd != 0 ? usd / coin.current_price : 0;

    //return Text(amount.toString());
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 12.0),
      child: TextField(
        decoration: InputDecoration(
          icon: SizedBox(height: 30, child: Image.network(coin.image)),
          hintText: "Coin",
          border: InputBorder.none,
        ),
        controller:
            TextEditingController(text: "$amount ${coin.symbol.toUpperCase()}"),
        readOnly: true,
        autocorrect: false,
        keyboardType: const TextInputType.numberWithOptions(decimal: true),
        onChanged: (value) {
          ref.watch(coin_usdProvider.notifier).update((state) =>
              value != "" ? num.parse(value) / coin.current_price : 0);
        },
      ),
    );
  }
}

CodePudding user response:

I think the easiest solution would be to create an outside function which can relate/update these two values.

for example:

void updateValues(float BTC, var USDT)

And then use a FocusNode (see also stackoverflow_question) to detect which of the TextFields is/was selected. That was you know which value is the new one and which one to change.

In this solution you should call this function in an onChanged property of the widgets.

FocusNode can be used either to call something when its focus is changed or to check if something has a focus. So using this class you can solve it in a couple different ways.

CodePudding user response:

Try this example out:

import 'package:flutter/material.dart';

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

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

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final btcTextController = TextEditingController();
  final usdtTextController = TextEditingController();
  final btcFocusNode = FocusNode();
  final usdtFocusNode = FocusNode();
  double btcValue = 15; 
  double usdTValue = 1; 

  String curSelection = "";

  @override
  void initState() {
    btcTextController.addListener(calcBTC);
    usdtTextController.addListener(calcUSDT);
    super.initState();
  }

  void calcBTC() {
    if (btcFocusNode.hasFocus) {
      usdtTextController.clear();
      if (btcTextController.text.isNotEmpty &&
          double.tryParse(btcTextController.text) != null) {
        setState(() {
          usdtTextController.text =
              (double.parse(btcTextController.text) * (btcValue / usdTValue))
                  .toString();
        });
      }
    }
  }

  void calcUSDT() {
    if (usdtFocusNode.hasFocus) {
      btcTextController.clear();
      if (usdtTextController.text.isNotEmpty &&
          double.tryParse(usdtTextController.text) != null) {
        setState(() {
          btcTextController.text =
              (double.parse(usdtTextController.text) * (usdTValue / btcValue))
                  .toString();
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: Card(
            color: Colors.white,
            shape:
                RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
            elevation: 4,
            child: Container(
              margin: const EdgeInsets.all(10),
              width: 300,
              height: 300,
              child: Column(
                children: [
                  Expanded(
                    child: TextField(
                      style: const TextStyle(color: Colors.black),
                      controller: btcTextController,
                      focusNode: btcFocusNode,
                      decoration: InputDecoration(
                          filled: true,
                          fillColor: Colors.blue.shade100,
                          labelText: 'BTC',
                          labelStyle: const TextStyle(color: Colors.pink),
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(10),
                            borderSide: BorderSide.none,
                          )),
                    ),
                  ),
                  Expanded(
                      child: TextField(
                        style: const TextStyle(color: Colors.black),
                    controller: usdtTextController,
                    focusNode: usdtFocusNode,
                    decoration: InputDecoration(
                      
                        filled: true,
                        fillColor: Colors.blue.shade100,
                        labelText: 'USDT',
                        labelStyle: const TextStyle(color: Colors.pink),
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(10),
                          borderSide: BorderSide.none,
                        )),
                  )),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

You will deffo need to add more validation etc. Also you can possibly use one single function to do calculations and use the focusNodes to decide which side needs to be calculated against which.

  • Related