InkWell não mostra efeito de ondulação

104

Tocar no recipiente aciona o onTap()manipulador, mas não mostra nenhum efeito de respingo de tinta.

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new InkWell(
          onTap: (){print("tapped");},
          child: new Container(
            width: 100.0,
            height: 100.0,
            color: Colors.orange,
          ),
        ),
      ),
    );
  }
}

Tentei colocar InkWelldentro Containertambém, mas foi em vão.

J. Sarkar
fonte

Respostas:

162

Acho que adicionar cor ao contêiner está cobrindo o efeito de tinta

https://docs.flutter.io/flutter/material/InkWell/InkWell.html

Este código parece funcionar

  body: new Center(
    child: new Container(
      child: new Material(
        child: new InkWell(
          onTap: (){print("tapped");},
          child: new Container(
            width: 100.0,
            height: 100.0,
          ),
        ),
        color: Colors.transparent,
      ),
      color: Colors.orange,
    ),
  ),

apenas clique no quadrado do meio.

Edit: Encontrei o relatório do bug. https://github.com/flutter/flutter/issues/3782

Na verdade, isso é o esperado, embora devamos atualizar a documentação para torná-lo mais claro.

O que está acontecendo é que a especificação do material diz que os respingos são na verdade tinta no material. Então, quando salpicamos, o que fazemos é literalmente fazer com que o widget Material faça o splash. Se você tem algo em cima do Material, nós espirramos embaixo dele e você não consegue ver.

Eu queria adicionar um widget "MaterialImage" que conceitualmente imprime sua imagem no Material também para que os respingos fiquem sobre a imagem. Poderíamos ter um MaterialDecoration que faz algo semelhante para uma decoração. Ou podemos fazer com que o próprio Material receba uma decoração. No momento é preciso uma cor, mas poderíamos estendê-la para uma decoração inteira. Não está claro se é realmente compatível com as especificações do material ter um material com gradiente, então não tenho certeza se devemos fazer isso.

No curto prazo, se você só precisa de uma solução alternativa, pode colocar um Material no topo do recipiente, com o material configurado para usar o tipo "transparência", e então colocar a tinta bem dentro dele.

--hixie

Atualização: Hixie fundiu uma nova solução Ink no ano passado. O Ink oferece uma maneira conveniente de respingar nas imagens.

  testWidgets('Does the Ink widget render anything', (WidgetTester tester) async {
    await tester.pumpWidget(
      new Material(
        child: new Center(
          child: new Ink(
            color: Colors.blue,
            width: 200.0,
            height: 200.0,
            child: new InkWell(
              splashColor: Colors.green,
              onTap: () { },
            ),
          ),
        ),
      ),
    );


Material(
  color: Colors.grey[800],
  child: Center(
    child: Ink.image(
      image: AssetImage('cat.jpeg'),
      fit: BoxFit.cover,
      width: 300.0,
      height: 200.0,
      child: InkWell(
        onTap: () { /* ... */ },
        child: Align(
          alignment: Alignment.topLeft,
          child: Padding(
            padding: const EdgeInsets.all(10.0),
            child: Text('KITTEN', style: TextStyle(fontWeight: FontWeight.w900, color: Colors.white)),
          ),
        )
      ),
    ),
  ),
)

Observação: não testei o novo Ink Widget. Copiei o código de ink_paint_test.dart e os documentos da classe Ink

https://github.com/Hixie/flutter/blob/1f6531984984f52328e66c0cd500a8d517964564/packages/flutter/test/material/ink_paint_test.dart

https://github.com/flutter/flutter/pull/13900

https://api.flutter.dev/flutter/material/Ink-class.html

user1462442
fonte
2
Você pode simplesmente colocar a cor em Materialsi mesmo e deixar de fora o Container.
Herohtar
1
Eu meio que percebi quando CopsOnRoad postou sua resposta.
user1462442
1
@KoenVanLooveren Experimente a resposta do CopsOnRoad. Não editei minha solução porque a solução do CopsOnRoad é muito elegante
user1462442
Isso é o que eu usei depois de alguma refatoração: D obrigado
Koen Van Looveren
no meu caso era o formato Container, obrigado pela solução
Mohammad Ersan
115

Resultado:

insira a descrição da imagem aqui


Basta usar o Inkwidget envolvido em um InkWell.

InkWell(
  onTap: () {}, // needed
  child: Ink( // use Ink
    width: 200,
    height: 200,
    color: Colors.blue,
  ),
)
CopsOnRoad
fonte
A fonte confirma a etapa 3: github.com/flutter/flutter/blob/… Em cada manipulador, eles verificam se o retorno de chamada está disponível, caso contrário, nada acontece.
Nightking de
@CopsOnRoad, posso pedir-lhe para ter uma questão relacionada com flutter aqui: stackoverflow.com/questions/60539378/… ?
Istiaque Ahmed
Se por código completo você quer dizer o exemplo que deu, sim. Descobri que esta é a solução> stackoverflow.com/a/58556613/12140067
Chris
@Chris acho que você pode estar tendo alguma interferência do Themeor Material, porque esse código funciona o dia todo.
CopsOnRoad de
25

InkWell () nunca mostrará o efeito cascata até que você adicione o

onTap : () {} 

ou qualquer um dos retornos de chamada como onDoubleTap, onLongPress etc.

parâmetro dentro do InkWell quando ele começa a ouvir seus toques apenas quando você especifica este parâmetro.

Jaswant Singh
fonte
Sim, eu fiz, e é verdade. Verifique a fonte: github.com/flutter/flutter/blob/… Em cada manipulador eles verificam se o callback está disponível, caso contrário, nada acontece.
Nightking de
21
  1. O widget InkWell deve ter um widget de Material como ancestral, caso contrário, ele não pode mostrar efeitos. Por exemplo:

    Material(
      child : InkWell(
        child : .....
    
  2. você tem que adicionar onTapmétodo para ver os efeitos reais como

     Buttons {RaisedButton,FlatButton etc}.
     e.g -> Material(
                 child : InkWell(
                         onTap : (){}
                         child : .....
    

Vamos aos pontos principais, ver alguns exemplos abaixo e tentar entender os conceitos reais do InkWell.

  • No exemplo abaixo, o material é pai do InkWell com onTap, mas ainda não está funcionando. Por favor, tente entender o conceito disso. Você deve fornecer alguma margem para o contêiner ou outro widget para mostrar os efeitos. Na verdade, o código abaixo está funcionando bem, mas não podemos ver porque não fornecemos nenhuma margem ou alinhamento, então não há espaço para mostrar os efeitos.

    Widget build(BuildContext context) {
      return Center(
        child: Material(
          child: new InkWell(
            onTap: () {
              print("tapped");
            },
            child: new Container(
              width: 100.0,
              height: 100.0,
              color: Colors.orange,
            ),  
          ),
        ),
      );
    }
    
  • O exemplo abaixo mostra os efeitos do InkWell apenas para cima porque fornecemos espaço {margin}.

    Widget build(BuildContext context) {
      return Center(
        child: Material(
          child: new InkWell(
            onTap: () {
              print("tapped");
            },
            child: new Container(
              margin: EdgeInsets.only(top: 100.0),
              width: 100.0,
              height: 100.0,
              color: Colors.orange,
            ),
          ),
        ),
      );
    }
    
  • Abaixo exp. mostre os efeitos em toda a página porque o centro cria a margem de todos os lados. Alinhe ao centro o widget filho da parte superior, esquerda, direita e inferior.

    Widget build(BuildContext context) {
      return Center(
        child: Material(
          child: new InkWell(
            onTap: () {
              print("tapped");
            },
            child: Center(
              child: new Container(
                width: 100.0,
                height: 100.0,
                color: Colors.orange,
              ),
            ),
          ),
        ),
      );
     }
    
97loser
fonte
10

A melhor maneira é usar o Ink widget em vez de qualquer outro widget.

Em vez de definir colordentro do container, você pode defini-lo no Inkpróprio widget.

O código abaixo funcionará.

Ink(
  color: Colors.orange,
  child: InkWell(
    child: Container(
      width: 100,
      height: 100,
    ),
    onTap: () {},
  ),
)

Não se esqueça de adicionar um onTap: () {}no caso InkWellcontrário, ele também não mostrará o efeito cascata.

ibhavikmakwana
fonte
7

Eu encontrei essa solução para mim. Acho que pode te ajudar:

Material(
      color: Theme.of(context).primaryColor,
      child: InkWell(
        splashColor: Theme.of(context).primaryColorLight,
        child: Container(
          height: 100,
        ),
        onTap: () {},
      ),
    )

Coloré fornecido ao widget de Material. É a cor padrão do seu widget. Você pode ajustar a cor do efeito ondulante usando a splashColorpropriedade do Inkwell.

Kanan Yusubov
fonte
3

Esta é a melhor forma que encontrei e utilizo sempre. Você pode experimentá-lo.

  • Enrole seu WidgetcomInkWell
  • Embrulhar InkWellcomMaterial
  • Defina a opacidade para 0% de qualquer maneira. por exemplo:color: Colors.white.withOpacity(0.0),

    Material(
      color: Colors.white.withOpacity(0.0),
      child: InkWell(
        child: Container(width: 100, height: 100),
        onTap: (){print("Wow! Ripple");},
      ),
    )
    
Sa Sadik
fonte
3

Isso está funcionando para mim:

Material(
    color: Colors.white.withOpacity(0.0),
    child: InkWell(
      splashColor: Colors.orange,
      child: Text('Hello'), // actually here it's a Container wrapping an image
      onTap: () {
        print('Click');
      },
    ));

Depois de tentar muitas respostas aqui, foi uma combinação de:

  1. Configuração splashColor
  2. Embrulhar InkWellemMaterial(color: Colors.white.withOpacity(0.0), ..)

Graças às respostas aqui que fazem esses 2 pontos

Gene Bo
fonte
2

Corri para este mesmo problema tentando criar uma cor alternada de InkWell em um ListView. Nesse caso específico, há uma solução simples: embrulhe as alternativas em um Container que usa uma mudança de tonalidade / brilho principalmente transparente - a animação de toque InkWell ainda estará visível abaixo dela. Nenhum material necessário. Observe que há outros problemas ao tentar contornar isso com um Materal - por exemplo, ele substituirá um DefaultTextStyle que você está usando pelo padrão (instala um AnimatedDefaultTextStyle), o que é uma grande dor.

user3483238
fonte
1

Depois de adicionar o onTap:(){}ouvinte, o efeito cascata deve funcionar bem. Não funciona se você usar BoxShadow()com no InkWell()widget.

Aruna Warnasooriya
fonte
Esse é o truque. O Ripple não funcionará sem onTap (). Obrigado cara!
Hardik Joshi
1

Definir a cor do recipiente do InkWell

Todos os widgets filhos colocados dentro do Materialwidget têm a cor definida no Materialwidget. Portanto, devemos definir a cor da própria propriedade color do Material. Você não pode configurá-lo a partir de nenhum Containerwidget pai .

Outra coisa importante a observar ao criar InkWellcom o Materialwidget pai é que você deve definir a cor da própria propriedade do Material. Você não pode definir a partir do Container.

Portanto, nosso código que corrige o InkWellefeito e a cor do contêiner é assim:

Container(
    margin: EdgeInsets.all(12),
    height: 50.0,
    width: 100.0,
    decoration: BoxDecoration(boxShadow: [
      BoxShadow(
          color: Colors.grey, blurRadius: 4, offset: Offset(0, 2))
    ]),
    child: Material(
      color: Colors.blue,
      child: InkWell(
        child: Center(
            child: Text("My Chip",
                style: Theme.of(context).textTheme.body1)),
        onTap: () {},
      ),
    ),
  )
Paresh Mangukiya
fonte
0

Fui atingido por um problema semelhante ao adicionar um Inkwell a um widget complexo existente com um recipiente envolvendo um BoxDecoration com uma cor. Ao adicionar o Material e o Inkwell da maneira sugerida, o Inkwell ainda estava obscurecido pelo BoxDecoration, então apenas tornei a cor do BoxDecoration ligeiramente opaca, o que permitiu que o Inkwell fosse visto

Lee McLoughlin
fonte
0

A solução para widgets circulares, faça como abaixo:

Material(
    color: Colors.transparent,
    child: Container(
      alignment: Alignment.center,
      height: 100,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          IconButton(
              enableFeedback: true,
              iconSize: 40,
              icon: Icon(
                Icons.skip_previous,
                color: Colors.white,
                size: 40,
              ),
              onPressed: () {}),
          IconButton(
            iconSize: 100,
            enableFeedback: true,
            splashColor: Colors.grey,
            icon: Icon(Icons.play_circle_filled, color: Colors.white, size: 100),
            padding: EdgeInsets.all(0),
            onPressed: () {},
          ),
          IconButton(
              enableFeedback: true,
              iconSize: 40,
              icon: Icon(
                Icons.skip_next,
                color: Colors.white,
                size: 40,
              ),
              onPressed: () {}),
        ],
      ),
    ),
  )
Edeson Bizerril
fonte
0

Para mim foi outro problema. InkWell não estava mostrando efeito cascata quando eu tinha a função onTap como parâmetro do meu widget definido como abaixo.

Function(Result) onTapItem;
...
onTap: onTapItem(result),

Não sei qual é a diferença, mas o próximo código está funcionando bem.

onTap: (){ onTapItem(result); },
pateta
fonte
0

Se você deseja um efeito ondulação em qualquer widget, basta:

1- Envolva o widget com Material e Inkwell .

2- definir a cor do widget do Material .

3- Nunca defina a cor do widget que deseja ondular.

   Material (
   color: const Color(0xcffFF8906),
   child: InkWell(
   ontap:() { },
   child: Container(
   color: Colors.transparent,
   height: 80,
   width: 80,
 )
Mohammed_7aafar
fonte