[infra_ui][overlar] Implement edge aligned anchor mode and update example project

This commit is contained in:
Jaylen Bian 2021-08-01 21:34:45 +08:00
parent dffb56d1a9
commit 5c4df3c6f2
2 changed files with 185 additions and 89 deletions

View File

@ -43,96 +43,111 @@ class OverlayScreen extends StatelessWidget {
title: const Text('Overlay Demo'),
),
body: ChangeNotifierProvider(
create: (context) => OverlayDemoAnchorDirection(AnchorDirection.topLeft),
child: Builder(builder: (context) {
return Column(
children: [
DropdownButton<AnchorDirection>(
value: context.watch<OverlayDemoAnchorDirection>().anchorDirection,
onChanged: (AnchorDirection? newValue) {
if (newValue != null) {
context.read<OverlayDemoAnchorDirection>().anchorDirection = newValue;
}
},
items: AnchorDirection.values.map((AnchorDirection classType) {
return DropdownMenuItem<AnchorDirection>(value: classType, child: Text(classType.toString()));
}).toList(),
),
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: () {
FlowyOverlay.of(context).insertCustom(
widget: const FlutterLogo(
size: 200,
),
identifier: 'overlay_flutter_logo',
delegate: null,
);
},
child: const Text('Show Overlay'),
),
const SizedBox(height: 12.0),
Builder(builder: (buttonContext) {
return ElevatedButton(
onPressed: () {
FlowyOverlay.of(context).insertWithAnchor(
widget: SizedBox(
width: 200,
height: 100,
child: Card(
color: Colors.grey[200],
child: GestureDetector(
onTapDown: (_) => print('Hello Flutter'),
child: const Center(child: FlutterLogo(size: 100)),
create: (context) => OverlayDemoAnchorDirection(AnchorDirection.rightWithTopAligned),
child: Builder(builder: (providerContext) {
return Center(
child: ConstrainedBox(
constraints: const BoxConstraints.tightFor(width: 500),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 48.0),
ElevatedButton(
onPressed: () {
final windowSize = MediaQuery.of(context).size;
FlowyOverlay.of(context).insertCustom(
widget: Positioned(
left: windowSize.width / 2.0 - 100,
top: 200,
child: SizedBox(
width: 200,
height: 100,
child: Card(
color: Colors.green[200],
child: GestureDetector(
// ignore: avoid_print
onTapDown: (_) => print('Hello Flutter'),
child: const Center(child: FlutterLogo(size: 100)),
),
),
),
),
),
identifier: 'overlay_card',
delegate: null,
anchorContext: buttonContext,
anchorDirection: context.read<OverlayDemoAnchorDirection>().anchorDirection,
);
},
child: const Text('Show Anchored Overlay'),
);
}),
const SizedBox(height: 12.0),
ElevatedButton(
onPressed: () {
final windowSize = MediaQuery.of(context).size;
FlowyOverlay.of(context).insertWithRect(
widget: SizedBox(
width: 200,
identifier: 'overlay_flutter_logo',
delegate: null,
);
},
child: const Text('Show Overlay'),
),
const SizedBox(height: 24.0),
DropdownButton<AnchorDirection>(
value: providerContext.watch<OverlayDemoAnchorDirection>().anchorDirection,
onChanged: (AnchorDirection? newValue) {
if (newValue != null) {
providerContext.read<OverlayDemoAnchorDirection>().anchorDirection = newValue;
}
},
items: AnchorDirection.values.map((AnchorDirection classType) {
return DropdownMenuItem<AnchorDirection>(value: classType, child: Text(classType.toString()));
}).toList(),
),
const SizedBox(height: 24.0),
Builder(builder: (buttonContext) {
return SizedBox(
height: 100,
child: Card(
color: Colors.orange[200],
child: GestureDetector(
onTapDown: (_) => print('Hello Flutter'),
child: const Center(child: FlutterLogo(size: 100)),
),
child: ElevatedButton(
onPressed: () {
FlowyOverlay.of(context).insertWithAnchor(
widget: SizedBox(
width: 100,
height: 50,
child: Card(
color: Colors.grey[200],
child: GestureDetector(
// ignore: avoid_print
onTapDown: (_) => print('Hello Flutter'),
child: const Center(child: FlutterLogo(size: 50)),
),
),
),
identifier: 'overlay_anchored_card',
delegate: null,
anchorContext: buttonContext,
anchorDirection: providerContext.read<OverlayDemoAnchorDirection>().anchorDirection,
);
},
child: const Text('Show Anchored Overlay'),
),
),
identifier: 'overlay_card',
delegate: null,
anchorPosition: Offset(0, windowSize.height - 200),
anchorSize: Size.zero,
anchorDirection: context.read<OverlayDemoAnchorDirection>().anchorDirection,
);
},
child: const Text('Show Positioned Overlay'),
);
}),
const SizedBox(height: 24.0),
ElevatedButton(
onPressed: () {
final windowSize = MediaQuery.of(context).size;
FlowyOverlay.of(context).insertWithRect(
widget: SizedBox(
width: 200,
height: 100,
child: Card(
color: Colors.orange[200],
child: GestureDetector(
// ignore: avoid_print
onTapDown: (_) => print('Hello Flutter'),
child: const Center(child: FlutterLogo(size: 100)),
),
),
),
identifier: 'overlay_positioned_card',
delegate: null,
anchorPosition: Offset(0, windowSize.height - 200),
anchorSize: Size.zero,
anchorDirection: providerContext.read<OverlayDemoAnchorDirection>().anchorDirection,
);
},
child: const Text('Show Positioned Overlay'),
),
],
),
],
),
);
}),
));

View File

@ -39,16 +39,97 @@ class OverlayLayoutDelegate extends SingleChildLayoutDelegate {
Offset position;
switch (anchorDirection) {
case AnchorDirection.topLeft:
position = Offset(anchorRect.left - childSize.width, anchorRect.top - childSize.height);
position = Offset(
anchorRect.left - childSize.width,
anchorRect.top - childSize.height,
);
break;
case AnchorDirection.topRight:
position = Offset(anchorRect.right, anchorRect.top - childSize.height);
position = Offset(
anchorRect.right,
anchorRect.top - childSize.height,
);
break;
case AnchorDirection.bottomLeft:
position = Offset(anchorRect.left - childSize.width, anchorRect.bottom);
position = Offset(
anchorRect.left - childSize.width,
anchorRect.bottom,
);
break;
case AnchorDirection.bottomRight:
position = Offset(anchorRect.right, anchorRect.bottom);
position = Offset(
anchorRect.right,
anchorRect.bottom,
);
break;
case AnchorDirection.topWithLeftAligned:
position = Offset(
anchorRect.left,
anchorRect.top - childSize.height,
);
break;
case AnchorDirection.topWithCenterAligned:
position = Offset(
anchorRect.left + anchorRect.width / 2.0 - childSize.width / 2.0,
anchorRect.top - childSize.height,
);
break;
case AnchorDirection.topWithRightAligned:
position = Offset(
anchorRect.right - childSize.width,
anchorRect.top - childSize.height,
);
break;
case AnchorDirection.rightWithTopAligned:
position = Offset(anchorRect.right, anchorRect.top);
break;
case AnchorDirection.rightWithCenterAligned:
position = Offset(
anchorRect.right,
anchorRect.top + anchorRect.height / 2.0 - childSize.height / 2.0,
);
break;
case AnchorDirection.rightWithBottomAligned:
position = Offset(
anchorRect.right,
anchorRect.bottom - childSize.height,
);
break;
case AnchorDirection.bottomWithLeftAligned:
position = Offset(
anchorRect.left,
anchorRect.bottom,
);
break;
case AnchorDirection.bottomWithCenterAligned:
position = Offset(
anchorRect.left + anchorRect.width / 2.0 - childSize.width / 2.0,
anchorRect.bottom,
);
break;
case AnchorDirection.bottomWithRightAligned:
position = Offset(
anchorRect.right - childSize.width,
anchorRect.bottom,
);
break;
case AnchorDirection.leftWithTopAligned:
position = Offset(
anchorRect.left - childSize.width,
anchorRect.top,
);
break;
case AnchorDirection.leftWithCenterAligned:
position = Offset(
anchorRect.left - childSize.width,
anchorRect.top + anchorRect.height / 2.0 - childSize.height / 2.0,
);
break;
case AnchorDirection.leftWithBottomAligned:
position = Offset(
anchorRect.left - childSize.width,
anchorRect.bottom - childSize.height,
);
break;
default:
throw UnimplementedError();