Стек с глобальным z-индексом?

У меня есть DataTable, в котором в некоторых ячейках есть ссылки. В идеале я хотел бы получить предварительный просмотр содержимого ссылки при наведении курсора на ссылку, чего я смог добиться с помощью виджета Stack. Однако, поскольку сложенный предварительный просмотр находится внутри DataCell, похоже, я не могу поднять его «z-index», чтобы он был поверх остальной части таблицы.

Стек с глобальным z-индексом?

Разве это невозможно с Flutter, или есть способ обойти это?

Единственный способ, которым я представляю, что это работает, без чего-либо, чтобы обновить глобальное z-index, было бы для ячейки, чтобы обновить глобальное состояние, а затем предварительный просмотр эскиза появился на Stack над уровнем DataTable. Но я бы хотел, чтобы был менее громоздкий способ сделать это...

3 виджета, которые я пробовал, но безрезультатно — они могут работать, я не знаю —:

  • Tooltip
  • Overlay
  • FloatingActionButton

Все мое приложение — здесь, а точная фиксация — 0303732. Соответствующий код — это виджет ClickableLink:

import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';

import 'package:url_launcher/url_launcher.dart';

import '../schema/links.dart';

@immutable
class ClickableLink extends StatefulWidget {
  const ClickableLink({
    Key? key,
    required this.link,
    this.linkText,
    this.color = Colors.blue,
  }) : super(key: key);

  final Link link;
  final String? linkText;
  final Color color;

  @override
  State<ClickableLink> createState() => _ClickableLinkState();
}

class _ClickableLinkState extends State<ClickableLink> {
  Widget hoverWidget = const SizedBox.shrink();

  void _fetchPreview(PointerEvent pointerEvent) {
    setState(() {
      if (widget.link.host == 'online-go.com' && widget.link.prePath == 'game') {
        hoverWidget = Positioned(
          top: 25,
          child: Image.network('https://online-go.com/api/v1/games/${widget.link.id}/png'),
        );
      }
    });
  }

  void _onExit(PointerEvent pointerEvent) {
    setState(() {
      hoverWidget = const SizedBox.shrink();
    });
  }

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      onHover: _fetchPreview,
      onExit: _onExit,
      child: Stack(
        clipBehavior: Clip.none,
        children: [
          SelectableText.rich(
            TextSpan(
              text: widget.linkText ?? widget.link.id,
              style: TextStyle(color: widget.color),
              recognizer: TapGestureRecognizer()
                ..onTap = () async => launch(widget.link.completeLink),
            ),
          ),
          hoverWidget,
        ],
      ),
    );
  }
}

Может быть, виджет Overlay в этом случае лучше, чем Stack?

Philippe Fanaro 17.03.2022 02:59
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема здесь связана с тем, что ваш виджет Stack, определенный внутри ClickableLink, будет находиться в «нижней» точке (внутри дерева виджетов вашего приложения), чем любой другой GameResultCell. Так что даже более высокие z-index все равно будут отставать от других GameResultCell.

Чтобы исправить это, я бы рекомендовал изменить вашу структуру и определить более высокую точку в вашей структуре, чтобы показать предварительный просмотр.

Другим способом может быть использование библиотеки для вложения предварительного просмотра во всплывающую подсказку. Взгляните, например, на этот: just_the_tooltip: ^0.0.11+2. С этим пакетом вы даже можете использовать StatelessWidget.

Результат здесь больше похож на то, что, я полагаю, вы ожидали.

class ClickableLink extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return JustTheTooltip(
      content: Image.network(
        'https://online-go.com/api/v1/games/${widget.link.id}/png',
      ),
      child: SelectableText.rich(
        TextSpan(
          text: widget.linkText ?? widget.link.id,
          style: TextStyle(
            color: widget.color ??
                (DogempTheme.currentThemeIsLight(context)
                    ? const Color(0xff1158c7)
                    : Colors.orange.withOpacity(0.85)),
          ),
          recognizer: TapGestureRecognizer()
            ..onTap = () async => launch(widget.link.completeLink),
        ),
      ),
    );
  }
}

Наконец, вы можете использовать Dialog, но результирующее поведение немного отличается. Взгляните на этот код, если хотите попробовать:

class _ClickableLinkState extends State<ClickableLink> {
  Widget hoverWidget = const SizedBox.shrink();

  void _fetchPreview(PointerEvent pointerEvent) {
    showDialog(
      context: context,
      builder: (context) {
        return Dialog(
          backgroundColor: Colors.transparent,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Image.network(
                  'https://online-go.com/api/v1/games/${widget.link.id}/png'),
              const SizedBox(
                height: 16.0,
              ),
              TextButton(
                  onPressed: () async => launch(widget.link.completeLink),
                  child: const Text('Go to complete link'))
            ],
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      onHover: _fetchPreview,
      child: Stack(
        clipBehavior: Clip.none,
        children: [
          SelectableText.rich(
            TextSpan(
              text: widget.linkText ?? widget.link.id,
              style: TextStyle(
                color: widget.color ??
                    (DogempTheme.currentThemeIsLight(context)
                        ? const Color(0xff1158c7)
                        : Colors.orange.withOpacity(0.85)),
              ),
              recognizer: TapGestureRecognizer()
                ..onTap = () async => launch(widget.link.completeLink),
            ),
          ),
        ],
      ),
    );
  }
}

Черт, этот пакет just_the_tooltip впечатляет, если посмотреть на его код. И, откровенно говоря, это то, что должно быть одним из родных виджетов Flutter. В любом случае, большое спасибо за ответ.

Philippe Fanaro 22.03.2022 15:44

В решении Dialog есть ли способ, чтобы оно появлялось только тогда, когда мышь непосредственно наводит на ссылку? Я думаю, что Flutter понимает, что это какой-то другой экран, поэтому он не будет знать, зависает ли что-то на предыдущем экране.

Philippe Fanaro 22.03.2022 15:50

На самом деле в коде, который я написал, диалоговое окно отображается при наведении мыши на ссылку. Дело в том, что диалоговое окно при отображении занимает весь экран. В этот момент вы фактически теряете наведение на ссылку. Вы можете использовать MouseRegion, чтобы лучше справляться с наведением, но было бы очень сложно воспроизвести результат всплывающей подсказки.

L. Gangemi 22.03.2022 16:43

Другие вопросы по теме