[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'), title: const Text('Overlay Demo'),
), ),
body: ChangeNotifierProvider( body: ChangeNotifierProvider(
create: (context) => OverlayDemoAnchorDirection(AnchorDirection.topLeft), create: (context) => OverlayDemoAnchorDirection(AnchorDirection.rightWithTopAligned),
child: Builder(builder: (context) { child: Builder(builder: (providerContext) {
return Column( return Center(
children: [ child: ConstrainedBox(
DropdownButton<AnchorDirection>( constraints: const BoxConstraints.tightFor(width: 500),
value: context.watch<OverlayDemoAnchorDirection>().anchorDirection, child: Column(
onChanged: (AnchorDirection? newValue) { crossAxisAlignment: CrossAxisAlignment.center,
if (newValue != null) { children: [
context.read<OverlayDemoAnchorDirection>().anchorDirection = newValue; const SizedBox(height: 48.0),
} ElevatedButton(
}, onPressed: () {
items: AnchorDirection.values.map((AnchorDirection classType) { final windowSize = MediaQuery.of(context).size;
return DropdownMenuItem<AnchorDirection>(value: classType, child: Text(classType.toString())); FlowyOverlay.of(context).insertCustom(
}).toList(), widget: Positioned(
), left: windowSize.width / 2.0 - 100,
Flexible( top: 200,
child: Padding( child: SizedBox(
padding: const EdgeInsets.all(16.0), width: 200,
child: Container( height: 100,
height: 300.0, child: Card(
decoration: BoxDecoration( color: Colors.green[200],
borderRadius: BorderRadius.circular(15.0), child: GestureDetector(
color: Colors.grey[200], // ignore: avoid_print
), onTapDown: (_) => print('Hello Flutter'),
), child: const Center(child: FlutterLogo(size: 100)),
), ),
), ),
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)),
), ),
), ),
), identifier: 'overlay_flutter_logo',
identifier: 'overlay_card', delegate: null,
delegate: null, );
anchorContext: buttonContext, },
anchorDirection: context.read<OverlayDemoAnchorDirection>().anchorDirection, child: const Text('Show Overlay'),
); ),
}, const SizedBox(height: 24.0),
child: const Text('Show Anchored Overlay'), DropdownButton<AnchorDirection>(
); value: providerContext.watch<OverlayDemoAnchorDirection>().anchorDirection,
}), onChanged: (AnchorDirection? newValue) {
const SizedBox(height: 12.0), if (newValue != null) {
ElevatedButton( providerContext.read<OverlayDemoAnchorDirection>().anchorDirection = newValue;
onPressed: () { }
final windowSize = MediaQuery.of(context).size; },
FlowyOverlay.of(context).insertWithRect( items: AnchorDirection.values.map((AnchorDirection classType) {
widget: SizedBox( return DropdownMenuItem<AnchorDirection>(value: classType, child: Text(classType.toString()));
width: 200, }).toList(),
),
const SizedBox(height: 24.0),
Builder(builder: (buttonContext) {
return SizedBox(
height: 100, height: 100,
child: Card( child: ElevatedButton(
color: Colors.orange[200], onPressed: () {
child: GestureDetector( FlowyOverlay.of(context).insertWithAnchor(
onTapDown: (_) => print('Hello Flutter'), widget: SizedBox(
child: const Center(child: FlutterLogo(size: 100)), 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, const SizedBox(height: 24.0),
anchorPosition: Offset(0, windowSize.height - 200), ElevatedButton(
anchorSize: Size.zero, onPressed: () {
anchorDirection: context.read<OverlayDemoAnchorDirection>().anchorDirection, final windowSize = MediaQuery.of(context).size;
); FlowyOverlay.of(context).insertWithRect(
}, widget: SizedBox(
child: const Text('Show Positioned Overlay'), 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; Offset position;
switch (anchorDirection) { switch (anchorDirection) {
case AnchorDirection.topLeft: case AnchorDirection.topLeft:
position = Offset(anchorRect.left - childSize.width, anchorRect.top - childSize.height); position = Offset(
anchorRect.left - childSize.width,
anchorRect.top - childSize.height,
);
break; break;
case AnchorDirection.topRight: case AnchorDirection.topRight:
position = Offset(anchorRect.right, anchorRect.top - childSize.height); position = Offset(
anchorRect.right,
anchorRect.top - childSize.height,
);
break; break;
case AnchorDirection.bottomLeft: case AnchorDirection.bottomLeft:
position = Offset(anchorRect.left - childSize.width, anchorRect.bottom); position = Offset(
anchorRect.left - childSize.width,
anchorRect.bottom,
);
break; break;
case AnchorDirection.bottomRight: 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; break;
default: default:
throw UnimplementedError(); throw UnimplementedError();