как включить взаимодействие пользовательского интерфейса с видимыми компонентами за холстом?

#dart #flutter #overlay

#dart #флаттер #наложение

Вопрос:

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

итак, я расширил класс CustomPainter, получив контекст страницы (чтобы получить его размеры) и список GlobalKeys (для элементов, которые я хочу отображать и взаимодействовать с ними)

 Color colorBlack = Colors.black.withOpacity(0.4);

class CurvePainter extends CustomPainter{

  BuildContext context;
  List<GlobalKey> globalKeys;
  double padding;

  @override
  void paint(Canvas canvas, Size size) {
    final double screenWidth = MediaQuery.of(context).size.width;
    final double screenHeight = MediaQuery.of(context).size.height;
    Path path = Path()..addRect(Rect.fromLTWH(0, 0, screenWidth, screenHeight));

    Set<GlobalKey> keysSet = Set.from(globalKeys);
    keysSet.forEach((element){
      final List<double> vals = global_key_util.getArea(element);
      path = Path.combine(PathOperation.difference,
          path,
          Path()
            ..addOval(Rect.fromLTWH(vals[0]-(padding/2),vals[1]-padding/2,vals[2] padding,vals[3] padding)));
    });

    canvas.drawPath(path,
        Paint()..color = colorBlack);

  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return oldDelegate != this;
  }

  CurvePainter({this.context,this.globalKeys,this.padding=4});

}
  

пока все хорошо … кнопка, с которой я хочу взаимодействовать с пользователем, полностью видна, на initState() моей странице я создаю наложение и показываю его.

как приложение выглядит на данный момент

проблема в том, что я не могу взаимодействовать с этой кнопкой! как я могу это решить?

Спасибо

Комментарии:

1. Оберните свой widget с помощью gestureDetector и используйте onTap для выполнения желаемого действия.

2. @KeertiPurswani — иногда я хочу, чтобы элемент ввода был видимым .. поэтому ontap с этим не поможет

3. Не могли бы вы объяснить «видимый элемент ввода». Какой код вы пробовали?

4. @KeertiPurswani — Я хочу иметь возможность наложения на весь мой экран и при этом иметь возможность взаимодействовать с некоторыми виджетами за ним. в настоящее время я использую clipPath, чтобы виджеты за ним были полностью видны и могли взаимодействовать с ними. вопрос в том .. можно ли это сделать без clipPath, чтобы мое наложение все еще было видно в этих областях

Ответ №1:

итак .. ответ просто не использовать CustomPainter, использовать ClipPath с CustomClipper .

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

итак, я создал InvertedClipper класс, который расширяет CustomClipper :

 import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'HoleArea.dart';
import 'WidgetData.dart';

class InvertedClipper extends CustomClipper<Path> {

  final Animation<double> animation;
  final List<WidgetData> widgetsData;
  double padding;
  Function deepEq = const DeepCollectionEquality().equals;
  List<HoleArea> areas = [];

  InvertedClipper({@required this.padding, this.animation, Listenable reclip,
      this.widgetsData}) : super(reclip: reclip) {
    if (widgetsData.isNotEmpty) {
      widgetsData.forEach((WidgetData widgetData) {
        if (widgetData.isEnabled) {
          final GlobalKey key = widgetData.key;
          if (key == null) {
        //    throw new Exception("GlobalKey is null!");
          } else if (key.currentWidget == null) {
//            throw new Exception("GlobalKey is not assigned to a Widget!");
          } else {
            areas.add(getHoleArea(key: key,shape: widgetData.shape,padding: widgetData.padding));
          }
        }
      });
    }
  }

  @override
  Path getClip(Size size) {
    Path path = Path();
    double animationValue = animation != null ? animation.value : 0;
    areas.forEach((HoleArea area) {
      switch (area.shape) {
        case WidgetShape.Oval: {
          path.addOval(Rect.fromLTWH(area.x - (((area.padding   padding)   animationValue*15) / 2), area.y - ((area.padding   padding)   animationValue*15) / 2,
              area.width   ((area.padding   padding)   animationValue*15), area.height   ((area.padding   padding)   animationValue*15)));
        }
        break;
        case WidgetShape.Rect: {
          path.addRect(Rect.fromLTWH(area.x - (((area.padding   padding)   animationValue*15) / 2), area.y - ((area.padding   padding)   animationValue*15) / 2,
              area.width   ((area.padding   padding)   animationValue*15), area.height   ((area.padding   padding)   animationValue*15)));
        }
        break;
        case WidgetShape.RRect: {
          path.addRRect(RRect.fromRectAndCorners(Rect.fromLTWH(area.x - (((area.padding   padding)   animationValue*15) / 2), area.y - ((area.padding   padding)   animationValue*15) / 2,
              area.width   ((area.padding   padding)   animationValue*15), area.height   ((area.padding   padding)   animationValue*15)),
              topLeft: Radius.circular(5.0),
              topRight: Radius.circular(5.0),
              bottomLeft: Radius.circular(5.0),
              bottomRight: Radius.circular(5.0)));
        }
        break;
      }
    });
    return path
      ..addRect(Rect.fromLTWH(0.0, 0.0, size.width, size.height))
      ..fillType = PathFillType.evenOdd;
  }

  @override
  bool shouldReclip(InvertedClipper oldClipper) {
    return !deepEq(oldClipper.areas, areas);
  }
}
  

и перед этим я настраиваю GestureDetector , чтобы определять, когда пользователь нажимает на наложение:

 return GestureDetector(
                onTap: onTap,
                child: ClipPath(
                    clipper: InvertedClipper(
                      padding: defaultPadding,
                        animation: animation,
                        reclip: animationController,
                        widgetsData: widgetsData),
  ...