skip to Main Content

I have this design in flutter. I want it so that when the user scrolls down the exercise list, at the bottom of the exercise list (ALWAYS THERE – Liked fixed in place a certain height above the bottom of the container), is the start button with the expandableFAB. The container surrounding the start button with the FAB should be semi-transparent and also have a border radius. Thank you so much for your help in advance!

What it looks like right now

What I want it to look like

My code:

import 'package:flutter/material.dart';
import 'package:workout_app/Screens/Components/Widgets/footer.dart';

class workout_page extends StatefulWidget {
  @override
  _WorkoutPageState createState() => _WorkoutPageState();
}

class _WorkoutPageState extends State<workout_page>
    with TickerProviderStateMixin {
  late TabController _tabController;
  late PageController _pageController;

  List<Map<String, dynamic>> workoutMap = [
    {
      'name': 'My First Workout',
      'exercises': [
        {
          'name': 'Bicep Curl',
          'musclesworked': ['bicep', 'tricep']
        },
        {
          'name': 'Preacher Curl',
          'musclesworked': ['bicep', 'tricep']
        },
        {
          'name': 'Bicep Curl',
          'musclesworked': ['bicep', 'tricep']
        },
        {
          'name': 'Preacher Curl',
          'musclesworked': ['bicep', 'tricep']
        },
        {
          'name': 'Bicep Curl',
          'musclesworked': ['bicep', 'tricep']
        },
        {
          'name': 'Preacher Curl',
          'musclesworked': ['bicep', 'tricep']
        },
        {
          'name': 'Bicep Curl',
          'musclesworked': ['bicep', 'tricep']
        },
        {
          'name': 'Preacher Curl',
          'musclesworked': ['bicep', 'tricep']
        }
      ]
    },
  ];

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: workoutMap.length + 1, vsync: this);
    _pageController = PageController();
  }

  TextEditingController _newTabController = TextEditingController();

  void _addTab() {
    setState(() {
      String newTabName = _newTabController.text;
      Map<String, dynamic> newTab = {
        'name': newTabName,
        'exercises': [],
      };
      workoutMap.add(newTab);
      _newTabController.clear();
      _tabController = TabController(
        length: workoutMap.length + (workoutMap.length < 4 ? 1 : 0),
        vsync: this,
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    var size = MediaQuery.of(context).size;
    return Container(
      decoration: BoxDecoration(color: Color.fromARGB(255, 67, 67, 67)),
      child: DefaultTabController(
        length: workoutMap.length + (workoutMap.length < 4 ? 1 : 0),
        child: Scaffold(
          backgroundColor: Color.fromRGBO(79, 79, 79, 1),
          body: Stack(
            children: [
              CustomScrollView(
                physics: NeverScrollableScrollPhysics(),
                slivers: [
                  SliverAppBar(
                    expandedHeight: 30,
                    titleSpacing: 15,
                    pinned: true,
                    elevation: 0,
                    backgroundColor: Color.fromARGB(255, 19, 19, 19),
                    centerTitle: false,
                    bottom: PreferredSize(
                        preferredSize: const Size.fromHeight(0),
                        child: Column(children: [
                          TabBar(
                            controller: _tabController,
                            onTap: (index) {
                              if (index == _tabController.length - 1 &&
                                  workoutMap.length < 4) {
                                _tabController
                                    .animateTo(_tabController.previousIndex);
                              } else {
                                _tabController.animateTo(index);
                                _pageController.jumpToPage(index);
                              }
                            },
                            tabs: [
                              ...workoutMap.map(
                                  (tab) => Tab(text: tab['name'] as String)),
                              if (workoutMap.length < 4)
                                Container(
                                  width: 40,
                                  height: 40,
                                  alignment: Alignment.center,
                                  child: IconButton(
                                    icon: Icon(Icons.add),
                                    onPressed: () {
                                      showDialog(
                                        context: context,
                                        builder: (context) => AlertDialog(
                                          title: Text('Add Tab'),
                                          content: TextField(
                                            controller: _newTabController,
                                            decoration: InputDecoration(
                                              hintText: 'Enter tab name',
                                            ),
                                          ),
                                          actions: [
                                            TextButton(
                                              child: Text('Cancel'),
                                              onPressed: () {
                                                Navigator.pop(context);
                                              },
                                            ),
                                            TextButton(
                                              child: Text('Add'),
                                              onPressed: () {
                                                _addTab();
                                                Navigator.pop(context);
                                              },
                                            ),
                                          ],
                                        ),
                                      );
                                    },
                                  ),
                                ),
                            ],
                          ),
                        ])),
                  ),
                  SliverToBoxAdapter(
                      child: Container(
                    height: size.height * .6,
                    child: PageView(
                      controller: _pageController,
                      onPageChanged: (index) {
                        if (index == _tabController.length - 1 &&
                            workoutMap.length < 4) {
                          _pageController.jumpToPage(_tabController.index);
                        } else {
                          _tabController.animateTo(index);
                        }
                      },
                      children: [
                        ...workoutMap.map(
                          (tab) => Container(
                              width: size.width,
                              height: size.height * .6,
                              decoration: BoxDecoration(
                                  color: Color.fromARGB(255, 41, 41, 41)),
                              child: Column(
                                  mainAxisAlignment: MainAxisAlignment.center,
                                  children: [
                                    tab['exercises'].length == 0
                                        ? Column(
                                            mainAxisAlignment:
                                                MainAxisAlignment.center,
                                            children: <Widget>[
                                              Icon(
                                                Icons
                                                    .sentiment_very_dissatisfied,
                                                size: size.width *
                                                    .3, // You can adjust the size as per your need
                                                color: Colors
                                                    .white, // You can adjust the color as per your need
                                              ),
                                              SizedBox(height: 10),
                                              Text(
                                                'This folder is empty. Add some workouts',
                                                style: TextStyle(
                                                    color: Colors.white),
                                                textAlign: TextAlign.center,
                                              ),
                                            ],
                                          )
                                        : Expanded(
                                            child: ListView.builder(
                                              itemCount:
                                                  tab['exercises'].length,
                                              itemBuilder: (context, index) {
                                                return Container(
                                                    margin: EdgeInsets.only(
                                                        bottom: 10.0,
                                                        left: 10,
                                                        right: 10),
                                                    decoration: BoxDecoration(
                                                        color: Colors.black,
                                                        borderRadius:
                                                            BorderRadius
                                                                .circular(
                                                                    10.0)),
                                                    child: Column(children: [
                                                      Container(
                                                        height:
                                                            size.height * .15,
                                                        decoration:
                                                            BoxDecoration(
                                                          color: Color.fromARGB(
                                                              255, 94, 94, 94),
                                                          borderRadius:
                                                              BorderRadius
                                                                  .circular(
                                                                      10.0),
                                                        ),
                                                        child: Stack(
                                                          children: [
                                                            Positioned(
                                                              top: 10,
                                                              left: 10,
                                                              child: Container(
                                                                width:
                                                                    size.width *
                                                                        .4,
                                                                child:
                                                                    ClipRRect(
                                                                  borderRadius:
                                                                      BorderRadius
                                                                          .circular(
                                                                              10.0),
                                                                  child: Image
                                                                      .network(
                                                                    'https://i.giphy.com/media/14kdiJUblbWBXy/giphy.gif', // Replace with your GIF URL
                                                                  ),
                                                                ),
                                                              ),
                                                            ),
                                                            Positioned(
                                                              top: 10,
                                                              left: size.width *
                                                                      .4 +
                                                                  20,
                                                              child: Column(
                                                                  crossAxisAlignment:
                                                                      CrossAxisAlignment
                                                                          .start, // Add this line
                                                                  children: [
                                                                    Text(
                                                                      tab['exercises']
                                                                              [
                                                                              index]
                                                                          [
                                                                          'name'],
                                                                      style: TextStyle(
                                                                          color: Colors
                                                                              .black,
                                                                          fontSize:
                                                                              20,
                                                                          fontWeight:
                                                                              FontWeight.bold),
                                                                    ),
                                                                    Text(
                                                                      (tab['exercises'][index]['musclesworked']
                                                                              as List)
                                                                          .join(
                                                                              ', '), // join the list into a string
                                                                      style: TextStyle(
                                                                          fontSize:
                                                                              16), // adjust style as needed
                                                                    )
                                                                  ]),
                                                            ),
                                                          ],
                                                        ),
                                                      ),
                                                      SizedBox(height: 10),
                                                      Row(children: [
                                                        Spacer(),
                                                        Text(
                                                          '3 Sets', // Replace with your sets, reps, and weight data
                                                          style: TextStyle(
                                                              color:
                                                                  Colors.white),
                                                          textAlign:
                                                              TextAlign.center,
                                                        ),
                                                        Spacer(),
                                                        Text(
                                                          '4 reps', // Replace with your sets, reps, and weight data
                                                          style: TextStyle(
                                                              color:
                                                                  Colors.white),
                                                          textAlign:
                                                              TextAlign.center,
                                                        ),
                                                        Spacer(),
                                                        Text(
                                                          '30 kg', // Replace with your sets, reps, and weight data
                                                          style: TextStyle(
                                                              color:
                                                                  Colors.white),
                                                          textAlign:
                                                              TextAlign.center,
                                                        ),
                                                        Spacer()
                                                      ]),
                                                      SizedBox(height: 10),
                                                    ]));
                                              },
                                            ),
                                          ),
                                    SizedBox(height: 10),
                                    Row(
                                      mainAxisAlignment:
                                          MainAxisAlignment.center,
                                      children: [
                                        Spacer(),
                                        Container(
                                          decoration: BoxDecoration(
                                            color:
                                                Color.fromARGB(255, 0, 255, 8),
                                            borderRadius:
                                                BorderRadius.circular(10.0),
                                          ),
                                          height: size.height * .08,
                                          width: size.width * .5,
                                          child: Column(
                                            mainAxisAlignment:
                                                MainAxisAlignment.center,
                                            children: <Widget>[
                                              Text('Start',
                                                  style:
                                                      TextStyle(fontSize: 30)),
                                            ],
                                          ),
                                        ),
                                        SizedBox(width: 20),
                                        ExpandableFab(),
                                        Spacer(),
                                      ],
                                    ),
                                    SizedBox(height: 10),
                                  ])),
                        )
                      ],
                    ),
                  ))
                ],
              ),
              Footer(tab: 'Workout'),
            ],
          ),
        ),
      ),
    );
  }
}

class CustomScrollPhysics extends ScrollPhysics {
  final TabController tabController;

  CustomScrollPhysics({required this.tabController, ScrollPhysics? parent})
      : super(parent: parent);

  @override
  CustomScrollPhysics applyTo(ScrollPhysics? ancestor) {
    return CustomScrollPhysics(tabController: tabController, parent: ancestor);
  }

  @override
  double applyPhysicsToUserOffset(ScrollMetrics position, double offset) {
    if ((tabController.index == tabController.length - 2 && offset > 0)) {
      return 0.0;
    }
    return offset;
  }
}

class ExpandableFab extends StatefulWidget {
  @override
  _ExpandableFabState createState() => _ExpandableFabState();
}

class _ExpandableFabState extends State<ExpandableFab>
    with SingleTickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<double> _animation;
  bool _isExpanded = false;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 200),
    );
    _animation =
        Tween<double>(begin: 0.0, end: 1.0).animate(_animationController);
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  void _toggleExpanded() {
    setState(() {
      _isExpanded = !_isExpanded;
      if (_isExpanded) {
        _animationController.forward();
      } else {
        _animationController.reverse();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
        if (_isExpanded) _buildOptionButton(Icons.dangerous, 'Dangerous'),
        if (_isExpanded) _buildOptionButton(Icons.delete, 'Delete'),
        if (_isExpanded) _buildOptionButton(Icons.edit, 'Edit'),
        FloatingActionButton(
          heroTag: 'Blah',
          onPressed: _toggleExpanded,
          tooltip: _isExpanded ? 'Close' : 'Open',
          backgroundColor: Color.fromARGB(255, 100, 100, 100),
          child: AnimatedBuilder(
            animation: _animationController,
            builder: (context, child) {
              return Transform.rotate(
                angle: _animation.value * 0.5 * 3.1415,
                child: Icon(
                  _isExpanded ? Icons.close : Icons.add,
                ),
              );
            },
          ),
        ),
      ],
    );
  }

  Widget _buildOptionButton(IconData iconData, String tooltip) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 8.0),
      child: FloatingActionButton(
        backgroundColor: Color.fromARGB(255, 100, 100, 100),
        heroTag: tooltip,
        onPressed: () {},
        tooltip: tooltip,
        child: Icon(iconData),
      ),
    );
  }
}

2

Answers


  1. try

    Color.fromARGB(255, 67, 67, 67).withOpacity(0.5)
    

    customize withOpacity(xx) to your liking

    Login or Signup to reply.
  2. You can change opacity by change value of 255 from below.

    Color.fromARGB(255, x, x, x)
                                                      
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search