I'm trying to make an animation of sorting algorithms in flutter. So far I've coded the algorithm and managed to get some sort of animation by iterating once at a time instead of the whole sorting process but you have to keep tapping the button to sort, one item at a time. I've been trying to look for a way to animate this process. Here's my code:

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

List<double> rectHeights = new List<double>();
int n = 2;

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sorting',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

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

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  int _selectedIndex = 0;
  final _widgetOptions = [
    Text('Index 0: Sort'),
    Text('Index 1: Shuffle'),
  ];

  @override
  void initState() {
    super.initState();
    Random random = new Random();
    for (int i = 0; i < 35; i++) {
      double ranNum = random.nextDouble() * 600;
      rectHeights.add(ranNum);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.all(8.0),
        child: Center(
          child: Row(
            children: rectangles(),
          ),
        ),
      ),
      bottomNavigationBar: BottomNavigationBar(
        iconSize: 50.0,
          items: <BottomNavigationBarItem>[
            BottomNavigationBarItem(icon: Icon(Icons.sort), title: Text('Sort', style: TextStyle(fontSize: 20.0),)),
            BottomNavigationBarItem(icon: Icon(Icons.shuffle), title: Text('Shuffle', style: TextStyle(fontSize: 20.0),)),
          ],
        currentIndex: _selectedIndex,
        fixedColor: Colors.blue,
        onTap: _onItemTapped,
      ),
    );
  }

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
    switch(_selectedIndex) {
      case 0:
          setState(() {
            insertSortOnce(rectHeights, 1);
          });
          break;
      case 1:
        setState(() {
          shuffle(rectHeights);
          n = 2;
        });

    }
  }
}

List<Widget> rectangles() {
  List<Widget> rects = new List<Widget>();
  for (double height in rectHeights) {
    var rect = Padding(
      padding: EdgeInsets.symmetric(horizontal: 1.0),
      child: Container(
        width: 8.0,
        height: height,
        decoration: BoxDecoration(
            shape: BoxShape.rectangle,
            color: Colors.blue
        ),
      ),
    );
    rects.add(rect);
  }
  return rects;
}

void insertSort(values, choice) {
  int i, j;
  double key, temp;
  for (i = 1; i < values.length; i++) {
    key = values[i];
    j = i - 1;
    switch (choice) {
      case 1:
        while (j >= 0 && key < values[j]) {
          temp = values[j];
          values[j] = values[j + 1];
          values[j + 1] = temp;
          j--;
        }
        break;
      case 2:
        while (j >= 0 && key > values[j]) {
          temp = values[j];
          values[j] = values[j + 1];
          values[j + 1] = temp;
          j--;
        }
        break;
    }
  }
}

void insertSortOnce(values, choice) {
  int i, j;
  double key, temp;
  for (i = 1; i < n; i++) {
    key = values[i];
    j = i - 1;
    switch (choice) {
      case 1:
        while (j >= 0 && key < values[j]) {
          temp = values[j];
          values[j] = values[j + 1];
          values[j + 1] = temp;
          j--;
        }
        break;
      case 2:
        while (j >= 0 && key > values[j]) {
          temp = values[j];
          values[j] = values[j + 1];
          values[j + 1] = temp;
          j--;
        }
        break;
    }
  }
  n++;
}

List shuffle(List items) {
  var random = new Random();

  // Go through all elements.
  for (var i = items.length - 1; i > 0; i--) {

    // Pick a pseudorandom number according to the list length
    var n = random.nextInt(i + 1);

    var temp = items[i];
    items[i] = items[n];
    items[n] = temp;
  }

  return items;
}


Solution 1: Mazin Ibrahim

You can use a Future function with a short delay, for example (one second) to call the insertSort() after each second till the rectHeights are sorted:

  var _notSorted = true ;
  var _shiftNotPressed = true ;

  Future sortRectangles() async {
  while(_notSorted & _shiftPressed) { // You have to provide a condition to know when to stop
  await new Future.delayed(const Duration(seconds: 1), () {
      insertSortOnce(rectHeights, 1);
      }
    );
  }
} 

Then checking for shuffling:

    void _onItemTapped(int index) {
setState(() {
  _selectedIndex = index;
});
switch(_selectedIndex) {
  case 0:
      setState(() {
        insertSortOnce(rectHeights, 1);
      });
      break;
  case 1:
    _shiftNotPressed = false ; // This is what you should add
    setState(() {
      shuffle(rectHeights);
      n = 2;
    });

  }
}

Then Sorting completion:

   void insertSortOnce(values, choice) {
   _notSorted = false ; // if it didn't execute the loop it means sorted 
   int i, j;
   double key, temp;
   for (i = 1; i < n; i++) {
   key = values[i];
   j = i - 1;
   switch (choice) {
     case 1:
      while (j >= 0 && key < values[j]) {
       _notSorted = true ; //You should figure a more efficient way to do this
       temp = values[j];
       values[j] = values[j + 1];
       values[j + 1] = temp;
       j--;
      }
     break;
    case 2:
    while (j >= 0 && key > values[j]) {
      temp = values[j];
      values[j] = values[j + 1];
      values[j + 1] = temp;
      j--;
    }
    break;
   }
 }
 n++;
}

Also, You should include in your condition whether the shift button is pressed and to terminate accordingly.