Fala, Dev! Tudo bem?
Venho trazer para você um questionamento que bem provavelmente você se perguntou: "Por que preciso envolver o InkWell em um Material? E por que preciso usar um Ink dentro do InkWell ao invés de um Container?"
Este é um questionamento muito interessante e para que não tenhamos nenhuma dúvida segue abaixo um pouco sobre esse tema. Espero que goste! :D
O InkWell é muito interessante pois sua principal função é adicionar um clique ou ação de toque (onTap) a qualquer Widget. O mesmo lembra bastante o GestureDetector, que possui a mesma funcionalidade.
Podemos dizer que a principal diferença entre os dois é que no InkWell temos uma animação de onda quando tocamos ou clicamos no widget que ele envolve. Isso traz uma sensação muito legal para o nosso usuário, visto que há uma confirmação visual da ação na tela.
Mas por que usar o Ink dentro do InkWell e também por que usar o Material envolvendo tudo isso? Segue abaixo a explicação de forma mais detalhada:
O Inkwell quando envolve algum widget pode passar desapercebido quando tratamos da animação que citei acima, isso vai muito de como o Material Design funciona. Conforme indica a documentação oficial, nos muitos momentos em que não vemos a animação, tem a ver com o fundo opaco ao qual o InkWell está aplicado.
Segue um exemplo onde mal podemos enxergar a animação:
...
child: InkWell(
onTap: () {
// Alguma ação
},
child: const Text(
'Clique aqui',
style: TextStyle(
fontSize: 50,
),
),
),
...
Clicando no texto "Clique aqui" iremos realizar alguma ação que está presente no onTap, mas a animação mal é vista:

Por isso quando queremos ver bem claramente a onda (Ou os "Respingos de tinta", como citado na documentação) se formando, é preciso que envolvamos o InkWell em um widget Material, visto que sobre o Material que a tinta pode se dissipar.
Vai ficar assim:
...
child: Material( <=== AQUI
child: InkWell(
onTap: () {
// Alguma ação
},
child: const Text(
'Clique aqui',
style: TextStyle(
fontSize: 50,
),
),
),
),
...E nós teremos agora um resultado que nos possibilita ver bem a animação sendo feita:

Mas afinal para que serve então o Ink? Vamos à explicação! Pense no mesmo cenário acima, mas se ao invés de um Text nós usássemos um Container com uma cor Vermela, desta forma:
...
child: Material(
child: InkWell(
onTap: () {
// Alguma ação
},
child: Container(
color: Colors.red,
height: 100,
width: 100,
),
),
),
...Você vai perceber que a animação não mais acontecerá, mesmo utilizando do widget Material envolvendo tudo, e isso é um problema.

Isso acontece porque a animação de onda no Material está acontecendo por baixo da coloração do nosso Container, e pensando nisso, temos um widget especial que foi feito para resolver este problema, e seu nome é Ink.
O Ink tem quase todos os atributos que um Container tem, então podemos facilmente trocar o Container por um Ink, com os mesmos atributos e tudo funcionará como antes, mas com a diferença que a animação agora poderá ser vista! :D

Espero que tenha ajudado em seu entendido, sobre o InkWell, Material e Ink, mas caso tenha qualquer problema ou dúvida é só me falar aqui. Bons estudos.