[infra_ui][overlay] (WIP) Temp submit before refactor

This commit is contained in:
Jaylen Bian 2021-07-26 12:32:50 +08:00
parent ae45e64244
commit 7efbf03030
11 changed files with 192 additions and 52 deletions

View File

@ -1,4 +1,6 @@
import 'package:flutter/material.dart';
import '../overlay/overlay_screen.dart';
import '../keyboard/keyboard_screen.dart';
import 'demo_item.dart';
@ -8,6 +10,7 @@ class HomeScreen extends StatelessWidget {
static List<ListItem> items = [
SectionHeaderItem('Widget Demos'),
KeyboardItem(),
OverlayItem(),
];
@override

View File

@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
import '../home/demo_item.dart';
class OverlayItem extends DemoItem {
@override
String buildTitle() => 'Overlay';
@override
void handleTap(BuildContext context) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return const OverlayScreen();
},
),
);
}
}
class OverlayScreen extends StatelessWidget {
const OverlayScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Overlay Demo'),
),
body: Column(
children: [
Flexible(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
height: 300.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
color: Colors.grey[200],
),
),
),
),
ElevatedButton(
onPressed: () {},
child: const Text('Show Overlay'),
),
],
));
}
}

View File

@ -0,0 +1,5 @@
import 'package:flutter/material.dart';
// MARK: - Shared Builder
typedef WidgetBuilder = Widget Function();

View File

@ -1,2 +1,5 @@
// Basis
export 'basis.dart';
// Keyboard
export 'src/keyboard/keyboard_visibility_detector.dart';

View File

@ -1,2 +1,5 @@
// Basis
export 'basis.dart';
// Keyboard
export 'src/keyboard/keyboard_visibility_detector.dart';

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
/// Specifies how overlay are anchored to the SourceWidget
enum AnchorDirection {
// Corner aligned with a corner of the SourceWidget

View File

@ -0,0 +1,50 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'overlay_basis.dart';
class OverlayLayoutDelegate extends SingleChildLayoutDelegate {
OverlayLayoutDelegate({
required this.anchorRect,
required this.targetRect,
required this.anchorDirection,
required this.safeAreaEnabled,
required this.insets,
});
final AnchorDirection anchorDirection;
final bool safeAreaEnabled;
final EdgeInsets insets;
final Rect anchorRect;
final Rect targetRect;
@override
bool shouldRelayout(OverlayLayoutDelegate oldDelegate) {
return anchorRect != oldDelegate.anchorRect ||
insets != oldDelegate.insets ||
safeAreaEnabled != oldDelegate.safeAreaEnabled ||
anchorDirection != oldDelegate.anchorDirection;
}
@override
Offset getPositionForChild(Size size, Size childSize) {
// calculate the pannel maximum available rect
var pannelRect = Rect.fromLTWH(0, 0, size.width, size.height);
pannelRect = insets.deflateRect(pannelRect);
// apply safearea
if (safeAreaEnabled) {
final safeArea = MediaQueryData.fromWindow(window).padding;
pannelRect = safeArea.deflateRect(pannelRect);
}
// clip pannel rect
// TODO: junlin - calculate child position
return Offset.zero;
}
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return constraints.loosen();
}
}

View File

@ -0,0 +1,52 @@
import 'package:flutter/material.dart';
class OverlayManager extends StatefulWidget {
const OverlayManager({Key? key}) : super(key: key);
static OverlayManagerState of(
BuildContext context, {
bool rootOverlay = false,
}) {
OverlayManagerState? overlayManager;
if (rootOverlay) {
overlayManager = context.findRootAncestorStateOfType<OverlayManagerState>() ?? overlayManager;
} else {
overlayManager = overlayManager ?? context.findAncestorStateOfType<OverlayManagerState>();
}
assert(() {
if (overlayManager == null) {
throw FlutterError(
'Can\'t find overlay manager in current context, please check if already wrapped by overlay manager.',
);
}
return true;
}());
return overlayManager!;
}
static OverlayManagerState? maybeOf(
BuildContext context, {
bool rootOverlay = false,
}) {
OverlayManagerState? overlayManager;
if (rootOverlay) {
overlayManager = context.findRootAncestorStateOfType<OverlayManagerState>() ?? overlayManager;
} else {
overlayManager = overlayManager ?? context.findAncestorStateOfType<OverlayManagerState>();
}
return overlayManager;
}
@override
OverlayManagerState createState() => OverlayManagerState();
}
class OverlayManagerState extends State<OverlayManager> {
@override
Widget build(BuildContext context) {
Navigator.of(context, rootNavigator: true);
return Container();
}
}

View File

@ -1,43 +1,37 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'overlay_basis.dart';
class OverlayPannel extends SingleChildLayoutDelegate {
OverlayPannel({
import 'overlay_basis.dart';
import 'overlay_layout_delegate.dart';
class OverlayPannel extends StatelessWidget {
const OverlayPannel({
Key? key,
required this.child,
required this.targetRect,
required this.anchorRect,
this.safeAreaEnabled = true,
this.anchorDirection = AnchorDirection.topRight,
this.safeAreaEnabled = false,
this.insets = EdgeInsets.zero,
});
}) : super(key: key);
final AnchorDirection anchorDirection;
final bool safeAreaEnabled;
final EdgeInsets insets;
final Rect targetRect;
final Rect anchorRect;
final Widget child;
@override
bool shouldRelayout(OverlayPannel oldDelegate) {
return targetRect != oldDelegate.targetRect ||
insets != oldDelegate.insets ||
safeAreaEnabled != oldDelegate.safeAreaEnabled ||
anchorDirection != oldDelegate.anchorDirection;
}
@override
Offset getPositionForChild(Size size, Size childSize) {
var pannelRect = targetRect;
if (safeAreaEnabled) {
final safeArea = MediaQueryData.fromWindow(window).padding;
pannelRect = safeArea.deflateRect(pannelRect);
}
// TODO: junlin - calculate child position
return Offset.zero;
}
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return constraints.loosen();
Widget build(BuildContext context) {
return CustomSingleChildLayout(
delegate: OverlayLayoutDelegate(
targetRect: targetRect,
anchorRect: anchorRect,
safeAreaEnabled: safeAreaEnabled,
anchorDirection: anchorDirection,
insets: insets,
),
child: child,
);
}
}

View File

@ -1,15 +0,0 @@
import 'package:flutter/material.dart';
class Overlay extends StatelessWidget {
const Overlay({
Key? key,
this.safeAreaEnabled = true,
}) : super(key: key);
final bool safeAreaEnabled;
@override
Widget build(BuildContext context) {
return Container();
}
}

View File

@ -6,9 +6,7 @@ typedef HoverBuilder = Widget Function(BuildContext context, bool isHovering);
class MouseHoverBuilder extends StatefulWidget {
final bool isClickable;
const MouseHoverBuilder(
{Key? key, required this.builder, this.isClickable = false})
: super(key: key);
const MouseHoverBuilder({Key? key, required this.builder, this.isClickable = false}) : super(key: key);
final HoverBuilder builder;
@ -22,9 +20,7 @@ class _MouseHoverBuilderState extends State<MouseHoverBuilder> {
@override
Widget build(BuildContext context) {
return MouseRegion(
cursor: widget.isClickable
? SystemMouseCursors.click
: SystemMouseCursors.basic,
cursor: widget.isClickable ? SystemMouseCursors.click : SystemMouseCursors.basic,
onEnter: (p) => setOver(true),
onExit: (p) => setOver(false),
child: widget.builder(context, isOver),