简体   繁体   中英

Flutter: Custom Multiple Choice Row from List of Widgets

I am trying to build a multiple choice Row from a list of Container widgets (wrapped in GestureDetector for onTap). When the user clicks on one of the Container widgets in the Row, that Container widget changes color (to blue) to reflect the user's selection. If the user then taps a different Container widget in the Row, THAT widget changes color to reflect the user's selection, and all others are reset to the initial color (white). Additionally, the user's choice (index?) must be retrievable.

All I have been able to do so far is create a Row of Container widgets that change color on tap, but function independently of one another. That is to say that the user may click on multiple selections, which is bad. I need some advice on how to break through to next level of functionality, where only one container may be selected and the selected value is passed-out.

Cheers, T

//choice button
class ChoiceButton extends StatefulWidget {
  final String label;
  final bool isPressed;

  const ChoiceButton({
    Key key,
    this.isPressed = false,
    this.label,
  }) : super(key: key);

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

class _ChoiceButtonState extends State<ChoiceButton> {
  bool _isPressed;

  @override
  void initState() {
    super.initState();
    _isPressed = widget.isPressed;
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        setState(() {
          _isPressed = !_isPressed;
        });
      },
      child: Container(
        height: 80,
        width: 80,
        decoration: BoxDecoration(
          color: _isPressed ? Colors.blue : Colors.transparent,
          border: Border.all(
            color: Colors.blue,
            width: 80 * 0.05,
          ),
        ),
        child: Center(
          child: Text(
            widget.label,
            style: TextStyle(
              fontSize: 12,
              fontWeight: FontWeight.bold,
              color: _isPressed ? Colors.white : Colors.blue,
            ),
            textAlign: TextAlign.center,
          ),
        ),
      ),
    );
  }
}

//choice row
class ChoiceRow extends StatefulWidget {
  @override
  _ChoiceRowState createState() => _ChoiceRowState();
}

class _ChoiceRowState extends State<ChoiceRow> {
  bool isPressed = false;
  String classChoice = '';

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.start,
      children: \[
        SizedBox(width: 30),
        ChoiceButton(
          isPressed: isPressed,
          label: 'A',
        ),
        SizedBox(width: 10),
        ChoiceButton(
          isPressed: isPressed,
          label: 'B',
        ),
        SizedBox(width: 10),
        ChoiceButton(
          isPressed: isPressed,
          label: 'C',
        ),
      \],
    );
  }
}

结果

I am providing two answers for this .... Use whichever one you prefer.

  1. The easy one :

So Flutter provides a widget named ToggleButton which will satisfy all the needs mentioned above. Follow this documentation for more information about this widget.

You can add your custom ChoiceButton design in the widget list of the toggle button and with some tweak you will also be able to achieve your ChioceRow design too.

  1. Now if you are someone who like to make everything from scratch (like me :P) then I have made some changes in the code you provided above which will satisfy all your needs. Below is the edited code.
class ChoiceRow extends StatefulWidget {
  @override
  _ChoiceRowState createState() => _ChoiceRowState();
}

class _ChoiceRowState extends State<ChoiceRow> {

  List<bool> isPressedList = [false,false,false];

  String classChoice = '';

  @override
  Widget build(BuildContext context) {

    print("Status L $isPressedList");

    return Row(
      mainAxisAlignment: MainAxisAlignment.start,
      children: [
        SizedBox(width: 30),
        GestureDetector(
          onTap: (){
            print("Hello");
            setState(() {
              isPressedList[0] = true;
              isPressedList[1] = false;
              isPressedList[2] = false;
            });
          },
          child: ChoiceButton(
            isPressed: isPressedList[0],
            label: 'A',
          ),
        ),
        SizedBox(width: 10),
        GestureDetector(
          onTap: (){
            setState(() {
              isPressedList[0] = false;
              isPressedList[1] = true;
              isPressedList[2] = false;
            });
          },
          child: ChoiceButton(
            isPressed: isPressedList[1],
            label: 'B',
          ),
        ),
        SizedBox(width: 10),
        GestureDetector(
          onTap: (){
            setState(() {
              isPressedList[0] = false;
              isPressedList[1] = false;
              isPressedList[2] = true;
            });
          },
          child: ChoiceButton(
            isPressed: isPressedList[2],
            label: 'C',
          ),
        ),
      ],
    );
  }
}







class ChoiceButton extends StatelessWidget {

  final String label;
  final bool isPressed;

  ChoiceButton({this.label,this.isPressed});


  @override
  Widget build(BuildContext context) {
    return Container(
      height: 80,
      width: 80,
      decoration: BoxDecoration(
        color: isPressed ? Colors.blue : Colors.transparent,
        border: Border.all(
          color: Colors.blue,
          width: 80 * 0.05,
        ),
      ),
      child: Center(
        child: Text(
          label,
          style: TextStyle(
            fontSize: 12,
            fontWeight: FontWeight.bold,
            color: isPressed ? Colors.white : Colors.blue,
          ),
          textAlign: TextAlign.center,
        ),
      ),
    );
  }
}

CHANGES :

  1. I made a list (onPressedList) which keeps track of the current status of the toggle buttons (Like which is on and which others are off).

  2. I moved the GestureDetector wrap on the button in the ChoiceRow class. This is because it will be difficult to pass the onTap result from ChoiceButton to ChoiceRow. (Now if you want the gesture detector in the Button class itself then you can make the list global or a static value in a completely different so that it can be properly accessed)

  3. I made the ChoiceButton class Stateless as there is no need to keep it Stateful now.

The two things I did were adding a list that tracks the current status of the toggle buttons and when one toggle button is active all the others will be deactivated.

Now it is working as you mentioned above and you will also be able to keep track of the current status of all the buttons through "isPressedList".

GLHF :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM