InkWell не показывает эффект ряби


94

Нажатие на контейнер запускает onTap()обработчик, но не показывает никакого эффекта брызг чернил.

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,
          ),
        ),
      ),
    );
  }
}

Я тоже пытался вставить InkWellвнутрь, Containerно тщетно.

Ответы:


151

Я думаю, что добавление цвета к контейнеру перекрывает эффект чернил

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

Этот код вроде работает

  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,
    ),
  ),

просто щелкните средний квадрат.

Изменить: я нашел отчет об ошибке. https://github.com/flutter/flutter/issues/3782

На самом деле это соответствует ожиданиям, хотя нам следует обновить документацию, чтобы сделать ее более понятной.

Что происходит, так это то, что в спецификации материала говорится, что брызги на самом деле являются чернилами на материале. Итак, когда мы всплескиваем, мы буквально заставляем виджет материала делать всплеск. Если у вас что-то есть поверх Материала, мы плещемся под ним, и вы этого не видите.

Я хотел добавить виджет «MaterialImage», который концептуально также печатает свое изображение в материале, чтобы затем брызги были поверх изображения. У нас может быть MaterialDecoration, который делает что-то подобное для украшения. Или мы могли бы сделать так, чтобы сам Материал был украшением. Сейчас это требует цвета, но мы можем расширить это на все украшение. Неясно, действительно ли материал с градиентом совместим со спецификациями материала, поэтому я не уверен, стоит ли нам это делать.

В краткосрочной перспективе, если вам просто нужно обходное решение, вы можете поместить Материал поверх контейнера с материалом, настроенным на использование типа «прозрачность», а затем поместить чернила внутрь него.

--хикси

Обновление: в прошлом году Hixie объединила новое решение Ink. Чернила обеспечивают удобный способ заливки изображений.

  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)),
          ),
        )
      ),
    ),
  ),
)

Обратите внимание: я не тестировал новый виджет Ink. Я скопировал код из ink_paint_test.dart и документов класса 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


2
Вы можете просто нанести цвет на Materialсаму себя и оставить Container.
Herohtar

1
Я как бы подумал, когда CopsOnRoad опубликовал свой ответ.
user1462442 05

1
@KoenVanLooveren Попробуйте ответить CopsOnRoad. Я не редактировал свое решение, потому что решение CopsOnRoad довольно элегантно
user1462442

Это то, что я использовал после некоторого рефакторинга: D, спасибо
Koen Van Looveren

в моем случае это была форма Контейнера, спасибо за решение
Мохаммад Эрсан

106

Выход:

введите описание изображения здесь


Просто используйте Inkвиджет, завернутый в InkWell.

InkWell(
  onTap: () {}, // needed
  child: Ink( // use Ink
    width: 200,
    height: 200,
    color: Colors.blue,
  ),
)

Источник подтверждает шаг 3: github.com/flutter/flutter/blob/ ... В каждом обработчике проверяют, доступен ли обратный вызов, иначе ничего не происходит.
Nightking

@CopsOnRoad, могу я попросить вас задать здесь вопрос, связанный с флаттером: stackoverflow.com/questions/60539378/… ?
Istiaque Ahmed,

Если под полным кодом вы имеете в виду приведенный вами пример, тогда да. Я нашел, что это решение> stackoverflow.com/a/58556613/12140067
Крис

@Chris Я думаю, у вас может быть какое Theme-то Materialвмешательство, потому что этот код работает весь день.
CopsOnRoad,

1
это единственное решение,
сработавшее

24

InkWell () никогда не покажет эффект ряби, пока вы не добавите

onTap : () {} 

или любой из обратных вызовов, таких как onDoubleTap, onLongPress и т. д.

внутри InkWell, поскольку он начинает слушать ваши нажатия только тогда, когда вы указываете этот параметр.


Да, я сделал, и это правда. Проверьте источник: github.com/flutter/flutter/blob/… В каждом обработчике проверяют, доступен ли обратный вызов, иначе ничего не происходит.
Nightking

17
  1. Виджет InkWell должен иметь виджет Material в качестве предка, иначе он не сможет отображать эффекты. Например:

    Material(
      child : InkWell(
        child : .....
    
  2. вам нужно добавить onTapметод, чтобы увидеть фактические эффекты, например

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

Давайте подойдем к основным моментам, рассмотрим несколько примеров ниже и попробуем понять фактические концепции InkWell.

  • В примере ниже Материал является родительским элементом InkWell с onTap, но он все еще не работает. Пожалуйста, попытайтесь понять суть этого. Вы должны предоставить некоторый запас для контейнера или другого виджета, чтобы показать эффекты. На самом деле код ниже работает нормально, но мы не можем видеть, потому что мы не предоставили никаких полей или выравнивания, поэтому у него нет места для отображения эффектов.

    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,
            ),  
          ),
        ),
      );
    }
    
  • В примере ниже показаны эффекты InkWell только вверх, потому что мы предоставляем пространство {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,
            ),
          ),
        ),
      );
    }
    
  • Ниже эксп. показать эффекты на всей странице, потому что центр создает поля со всех сторон. По центру выровняйте дочерний виджет сверху, слева, справа и снизу.

    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,
              ),
            ),
          ),
        ),
      );
     }
    

9

Лучше использовать Ink виджет вместо любого другого виджета.

Вместо определения colorвнутреннего контейнера вы можете определить его в Inkсамом виджете.

Код ниже будет работать.

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

Не забудьте добавить onTap: () {}в InkWellостальном он не будет показывать мультипликационный эффект тоже.


4

Я нашел для себя это решение. Думаю, это может вам помочь:

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

Colorдается виджету материала. Это цвет вашего виджета по умолчанию. Вы можете настроить цвет эффекта пульсации с помощью splashColorсвойства Inkwell.


3

Это лучший способ, который я нашел и использую всегда. Можешь попробовать.

  • Оберните WidgetсInkWell
  • Обруч InkWellсMaterial
  • В любом случае установите непрозрачность 0%. например: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");},
      ),
    )
    

2

Я столкнулся с той же проблемой, пытаясь создать чередующийся цвет InkWell в ListView. В этом конкретном случае есть простое решение: обернуть альтернативы в Контейнер, который использует в основном прозрачное изменение оттенка / яркости - анимация касания InkWell все еще будет видна под ним. Материал не требуется. Обратите внимание, есть и другие проблемы при попытке обойти это с помощью Materal - например, он переопределит используемый вами DefaultTextStyle по умолчанию (он устанавливает AnimatedDefaultTextStyle), что является огромной проблемой.


2

Это работает для меня:

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');
      },
    ));

Попробовав здесь много ответов, это была комбинация:

  1. Настройка splashColor
  2. Обертывание InkWellвMaterial(color: Colors.white.withOpacity(0.0), ..)

Благодаря ответам на эти 2 балла


1

После того, как вы добавили onTap:(){}слушателя, эффект пульсации должен работать нормально. Это не работает, если вы используете BoxShadow()в InkWell()виджете.


Это уловка. Ripple не будет работать без onTap (). Спасибо чувак!
Хардик Джоши,

0

У меня возникла аналогичная проблема с добавлением чернильницы к существующему сложному виджету с контейнером, обертывающим BoxDecoration с цветом. Добавив Материал и Чернильницу так, как предполагалось, Чернильница все еще была скрыта из-за BoxDecoration, поэтому я просто сделал цвет BoxDecoration слегка непрозрачным, что позволило видеть чернильницу.


0

Решение круглых виджетов, как показано ниже:

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: () {}),
        ],
      ),
    ),
  )

0

Для меня это была другая проблема. InkWell не показывал эффекта пульсации, когда у меня была функция onTap в качестве параметра моего виджета, определенного ниже.

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

Не знаю, в чем разница, но следующий код работает хорошо.

onTap: (){ onTapItem(result); },
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.