user1743703
user1743703

Reputation: 131

Is there a better way? Expandable rows

enter image description here

Hello. I was stuck for some time with this problem but I achieved what is shown in the gif with the following code:

class _EntitiesState extends State<Entities> {
  bool selected = false;
  bool selected2 = false;
  bool selected3 = false;

  var xwidth = 1;

  final activeColor = Colors.red;

  var flex1 = 1;
  var flex2 = 1;
  var flex3 = 1;

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Expanded(
          flex: flex1,
          child: GestureDetector(
            onTap: () => {
              setState(() {
                flex1 = 0;
                flex2 = 1;
                flex3 = 1;
                selected3 = !selected3;
              })
            },
            child: AnimatedContainer(
              color: selected3 ? activeColor : Colors.green,
              width: MediaQuery.of(context).size.width *
                  (selected3 ? xwidth : 0.33),
              duration: const Duration(seconds: 1),
              child: Container(),
            ),
          ),
        ),
        Expanded(
          flex: flex2,
          child: GestureDetector(
            onTap: () => {
              setState(() {
                flex1 = 1;
                flex2 = 0;
                flex3 = 1;
                selected2 = !selected2;
              })
            },
            child: AnimatedContainer(
              color: selected2 ? activeColor : Colors.yellow,
              width: MediaQuery.of(context).size.width *
                  (selected2 ? xwidth : 0.33),
              duration: const Duration(seconds: 1),
              child: Container(),
            ),
          ),
        ),
        Expanded(
          flex: flex3,
          child: GestureDetector(
            onTap: () => {
              setState(() {
                flex1 = 1;
                flex2 = 1;
                flex3 = 0;
                selected = !selected;
              })
            },
            child: AnimatedContainer(
              color: selected ? activeColor : Colors.blue,
              width: MediaQuery.of(context).size.width *
                  (selected ? xwidth : 0.33),
              duration: const Duration(seconds: 1),
              child: Container(),
            ),
          ),
        ),
      ],
    );
  }
} 

I have a question. Is there a better, more elegant way to do this? Maybe there is a suitable flutter element that does it? My solution is kinda primitive and doesn't work well with a lot of expandable rows.

Upvotes: 1

Views: 64

Answers (1)

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63829

It can be simplified using nullable selectedIndex, int? selectedIndex;.

Containers color and width logic will be

color: selectedIndex == null && selectedIndex == index
    ? Colors.red
    : colors[index],
width: selectedIndex == null
    ? constraints.maxWidth / totalItem
    : selectedIndex == index
        ? constraints.maxWidth
        : 0,

And index selection logic will be

onTap: () {
  selectedIndex == null
      ? selectedIndex = index
      : selectedIndex = null;
  setState(() {});
},

Run on dartPad

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

  @override
  State<Entities> createState() => _EntitiesState();
}

class _EntitiesState extends State<Entities> {
  int? selectedIndex;
  int totalItem = 3;
  late List<Color> colors;

  @override
  void initState() {
    colors = List.generate(
        totalItem,
        (index) =>
            Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0));
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) => Row(
        children: List.generate(
          totalItem,
          (index) => GestureDetector(
            onTap: () {
              selectedIndex == null
                  ? selectedIndex = index
                  : selectedIndex = null;
              setState(() {});
            },
            child: AnimatedContainer(
              key: ValueKey(index),
              height: constraints.maxHeight,
              color: selectedIndex == null && selectedIndex == index
                  ? Colors.red
                  : colors[index],
              width: selectedIndex == null
                  ? constraints.maxWidth / totalItem
                  : selectedIndex == index
                      ? constraints.maxWidth
                      : 0,
              duration: const Duration(seconds: 1),
              alignment: Alignment.center,
              child: Text("$index"),
            ),
          ),
        ),
      ),
    );
  }
}


Upvotes: 1

Related Questions