9

As the Google stadia app is made with flutter I was wondering how they achieved the much more beautiful ripple animation on their BottomNavigationBar.

Example:

enter image description here

How did they achieve the custom ripple animation?

Edit: Simple custom BottomNavigationItem:

bottomNavigationBar: Container(
      height: 50,
      child: Row(
        children: <Widget>[
          Expanded(
            child: BottomItem(),
          ),
          Expanded(
            child: BottomItem(),
          ),
          Expanded(
            child: BottomItem(),
          ),
        ],
      )),
class BottomItem extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {},
      child: Center(child: Icon(Icons.shop)),
    );
  }
}
David Peters
  • 849
  • 1
  • 9
  • 12

4 Answers4

21

The Ink you're looking for is InkResponse and not InkWell. InkWell fills the entire available space with a highlight and then do the splash but, InkResponse does the splash with that circular effect you're looking for, you need to tweak it a bit, but this is the code example:


Material(
  child: Container(
    child: Center(
       child: InkResponse(
            focusColor: Colors.transparent,
            hoverColor: Colors.transparent,
            highlightColor: Colors.transparent,
            onTap: () {},
            child: Padding(
              padding: const EdgeInsets.all(30),
              child: Icon(Icons.home),
            ),
          ),
        ),
      ),
    )

| InkWell | InkResponse Default | InkResponse Custom |

Mariano Zorrilla
  • 7,165
  • 2
  • 34
  • 52
6

Google Stadia App Example: Image 1 Image 2

NB: Use Material Widget as parent of the Row so the effect can be expanded over all the row width and with a limit condition of "radius: 40"

Container(
      width: double.infinity,
      height: 300,
      child: Material(
        color: Colors.transparent,
        child: Row(
          children: [
            Expanded(
              flex: 20,
              child: InkResponse(
                onTap: () {},
                //containedInkWell: false,
                splashFactory: InkRipple.splashFactory,
                radius: 40,
                splashColor: Colors.black12,
                highlightColor: Colors.transparent,
                child: Container(height: double.infinity, alignment: Alignment.center, child: Icon(Icons.search_rounded)),
              ),
            ),
            Expanded(
              flex: 20,
              child: InkResponse(
                onTap: () {},
                //containedInkWell: false,
                splashFactory: InkRipple.splashFactory,
                radius: 40,
                splashColor: Colors.black12,
                highlightColor: Colors.transparent,
                child: Container(height: double.infinity, alignment: Alignment.center, child: Icon(Icons.search_rounded)),
              ),
            ),
            Expanded(
              flex: 20,
              child: InkResponse(
                onTap: () {},
                //containedInkWell: false,
                splashFactory: InkRipple.splashFactory,
                radius: 40,
                splashColor: Colors.black12,
                highlightColor: Colors.transparent,
                child: Container(height: double.infinity, alignment: Alignment.center, child: Icon(Icons.search_rounded)),
              ),
            ),
            Expanded(
              flex: 20,
              child: InkResponse(
                onTap: () {},
                //containedInkWell: false,
                splashFactory: InkRipple.splashFactory,
                radius: 40,
                splashColor: Colors.black12,
                highlightColor: Colors.transparent,
                child: Container(height: double.infinity, alignment: Alignment.center, child: Icon(Icons.search_rounded)),
              ),
            ),
            Expanded(
              flex: 20,
              child: InkResponse(
                onTap: () {},
                //containedInkWell: false,
                splashFactory: InkRipple.splashFactory,
                radius: 40,
                splashColor: Colors.black12,
                highlightColor: Colors.transparent,
                child: Container(height: double.infinity, alignment: Alignment.center, child: Icon(Icons.search_rounded)),
              ),
            ),
          ],
        ),
      ),
    )
Amine LAHRIM
  • 638
  • 6
  • 7
0

You might want to use the InkResponse Class in your BottomNavigationBar :)

Edited from InkWell to InkResponse.

Bilaal Abdel Hassan
  • 1,181
  • 2
  • 12
  • 20
  • Yes they're using InkWell in a way but how? The ripple animation gets clipped on the edges of my custom BottomNavigationItem. How did they implement a circular shaped ripple animation? – David Peters May 09 '20 at 21:08
  • Ah ok I get your point now. Can you upload your code? I might have an idea on how to achieve it. – Bilaal Abdel Hassan May 09 '20 at 21:10
  • I have to get some sleep but my idea is as follows, try it if you can else I will still try it tomorrow: In the bottomNavigationBar, use a stack and position the different buttons in their relevant places. This way the buttons won't be restricted with anything to their left or right thus allowing the ripple to be completed. – Bilaal Abdel Hassan May 09 '20 at 21:47
0
                                 FIRST WAY
    

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'BottomNavigationBar in style Material Design 2',
      theme: ThemeData(primarySwatch: Colors.indigo),
      home: BottomNavigationMaterial2(),
    );
  }
}

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

  @override
  State<BottomNavigationMaterial2> createState() =>
      _BottomNavigationMaterial2State();
}

class _BottomNavigationMaterial2State extends State<BottomNavigationMaterial3> {
  Widget _bottomNavItem() {
    return InkWell(
      onTap: () {},
      radius: 93,
      splashColor: Color.fromARGB(124, 108, 130, 255),
      highlightColor: Colors.white,
      splashFactory: InkRipple.splashFactory,
      child: Center(child: Icon(Icons.search, size: 25)),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      bottomNavigationBar: Container(
        height: 80,
        child: Row(
          children: <Widget>[
            Container(child: _bottomNavItem(), width: 196),
            Container(child: _bottomNavItem(), width: 196),
          ],
        ),
      ),
    );
  }
}
                                 SECOND WAY
    

theme: ThemeData(splashFactory: InkRipple.splashFactory),
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 25 '22 at 06:19