Skip to content

Commit 97bd110

Browse files
committed
+Add sliver type functionality to sides
1 parent 4077477 commit 97bd110

File tree

9 files changed

+642
-158
lines changed

9 files changed

+642
-158
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![tag](https://img.shields.io/badge/Tag-v0.8.11-purple?logo=github)](https://github.com/dev-cetera/df_screen/tree/v0.8.11)
55
[![buymeacoffee](https://img.shields.io/badge/Buy%20Me%20A%20Coffee-FFDD00?logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/dev_cetera)
66
[![sponsor](https://img.shields.io/badge/Sponsor-grey?logo=github-sponsors&logoColor=pink)](https://github.com/sponsors/dev-cetera)
7-
[![patreon](https://img.shields.io/badge/Patreon-grey?logo=patreon)](https://www.patreon.com/t0mb3rr)
7+
[![patreon](https://img.shields.io/badge/Patreon-grey?logo=patreon)](https://www.patreon.com/robelator)
88
[![discord](https://img.shields.io/badge/Discord-5865F2?logo=discord&logoColor=white)](https://discord.gg/gEQ8y2nfyX)
99
[![instagram](https://img.shields.io/badge/Instagram-E4405F?logo=instagram&logoColor=white)](https://www.instagram.com/dev_cetera/)
1010
[![license](https://img.shields.io/badge/License-MIT-blue.svg)](https://raw.githubusercontent.com/dev-cetera/df_screen/main/LICENSE)

example/lib/example_2.dart

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
import 'package:df_screen/df_screen.dart';
2+
import 'package:flutter/material.dart';
3+
4+
void main() {
5+
runApp(const MyApp());
6+
}
7+
8+
class MyApp extends StatelessWidget {
9+
const MyApp({super.key});
10+
11+
@override
12+
Widget build(BuildContext context) {
13+
return const MaterialApp(
14+
debugShowCheckedModeBanner: false,
15+
title: 'Adaptive Screen Example',
16+
home: ExampleScreen(),
17+
);
18+
}
19+
}
20+
21+
base class ExampleScreen extends Screen {
22+
const ExampleScreen({super.key});
23+
24+
@override
25+
State createState() => ExampleScreenState();
26+
27+
@override
28+
ScreenController createController(Screen screen, ScreenState state) {
29+
return ExampleScreenController(screen, state);
30+
}
31+
}
32+
33+
final class ExampleScreenController extends ScreenController {
34+
ExampleScreenController(super.screen, super.state);
35+
}
36+
37+
final class ExampleScreenState
38+
extends AdaptiveScreenState<ExampleScreen, ExampleScreenController> {
39+
@override
40+
AdaptiveScreenSideMode get topSideMode => AdaptiveScreenSideMode.SLIVER;
41+
42+
@override
43+
AdaptiveScreenSideMode get leftSideMode =>
44+
AdaptiveScreenSideMode.OVERLAY_WITH_PADDING;
45+
46+
@override
47+
AdaptiveScreenSideMode get rightSideMode => AdaptiveScreenSideMode.OVERLAY;
48+
49+
@override
50+
AdaptiveScreenSideMode get bottomSideMode => AdaptiveScreenSideMode.STATIC;
51+
52+
@override
53+
double get minTopSideSize => 80.0;
54+
55+
@override
56+
Widget topSide(BuildContext context, double topInsets) {
57+
return AdaptiveScrollBuilder(
58+
controller: bodyScrollController,
59+
expandedSize: 250.0,
60+
collapsedSize: minTopSideSize,
61+
child: Container(
62+
decoration: BoxDecoration(
63+
gradient: LinearGradient(
64+
colors: [Colors.teal.shade800, Colors.teal.shade400],
65+
begin: Alignment.topLeft,
66+
end: Alignment.bottomRight,
67+
),
68+
boxShadow: const [
69+
BoxShadow(color: Colors.black26, blurRadius: 10.0),
70+
],
71+
),
72+
child: const Center(
73+
child: Opacity(
74+
opacity: 0.3,
75+
child: Icon(Icons.waves, size: 300.0, color: Colors.white),
76+
),
77+
),
78+
),
79+
builder: (context, percentage, staticChild) {
80+
return SizedBox(
81+
height: 250.0,
82+
child: Stack(
83+
children: [
84+
Positioned.fill(child: staticChild!),
85+
Positioned(
86+
bottom: 20.0 + (20.0 * (1.0 - percentage)),
87+
left: 20.0,
88+
child: Opacity(
89+
opacity: percentage,
90+
child: const Text(
91+
'Large Expanded Title',
92+
style: TextStyle(
93+
color: Colors.white,
94+
fontSize: 32.0,
95+
fontWeight: FontWeight.bold,
96+
),
97+
),
98+
),
99+
),
100+
Positioned(
101+
top: 40.0,
102+
left: 0.0,
103+
right: 0.0,
104+
child: Opacity(
105+
opacity: (1.0 - percentage),
106+
child: const Center(
107+
child: Text(
108+
'My App',
109+
style: TextStyle(
110+
color: Colors.white,
111+
fontWeight: FontWeight.bold,
112+
fontSize: 20.0,
113+
),
114+
),
115+
),
116+
),
117+
),
118+
],
119+
),
120+
);
121+
},
122+
);
123+
}
124+
125+
@override
126+
Widget leftSide(BuildContext context, double leftInsets) {
127+
return AdaptiveScrollBuilder(
128+
controller: bodyScrollController,
129+
expandedSize: 300.0,
130+
collapsedSize: 0.0,
131+
builder: (context, percentage, _) {
132+
return Container(
133+
width: 70.0,
134+
decoration: BoxDecoration(
135+
color: Color.lerp(
136+
Colors.white.withAlpha(200),
137+
Colors.teal.shade50.withAlpha(240),
138+
1.0 - percentage,
139+
),
140+
border: Border(right: BorderSide(color: Colors.grey.shade300)),
141+
),
142+
child: Column(
143+
mainAxisAlignment: MainAxisAlignment.center,
144+
children: [
145+
Transform.scale(
146+
scale: 0.8 + (0.4 * percentage),
147+
child: const Icon(Icons.dashboard, color: Colors.teal),
148+
),
149+
const SizedBox(height: 20.0),
150+
const Icon(Icons.person, color: Colors.grey),
151+
const SizedBox(height: 20.0),
152+
Opacity(
153+
opacity: percentage,
154+
child: const Icon(Icons.settings, color: Colors.grey),
155+
),
156+
],
157+
),
158+
);
159+
},
160+
);
161+
}
162+
163+
@override
164+
Widget rightSide(BuildContext context, double rightInsets) {
165+
return Align(
166+
alignment: Alignment.centerRight,
167+
child: Container(
168+
margin: const EdgeInsets.only(right: 10.0),
169+
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 8.0),
170+
decoration: BoxDecoration(
171+
color: Colors.black87,
172+
borderRadius: BorderRadius.circular(20.0),
173+
),
174+
child: const Icon(Icons.arrow_upward, color: Colors.white),
175+
),
176+
);
177+
}
178+
179+
@override
180+
Widget bottomSide(BuildContext context, double bottomInsets) {
181+
return Container(
182+
height: 60.0 + bottomInsets,
183+
color: Colors.white,
184+
padding: EdgeInsets.only(bottom: bottomInsets),
185+
child: const Center(child: Text('Static Bottom Footer')),
186+
);
187+
}
188+
189+
@override
190+
Widget body(BuildContext context) {
191+
return ListView.builder(
192+
controller: bodyScrollController,
193+
padding: EdgeInsets.only(top: topSideSize, bottom: 20.0),
194+
itemCount: 40,
195+
itemBuilder: (context, index) {
196+
return Card(
197+
margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
198+
elevation: 2.0,
199+
child: ListTile(
200+
title: Text('Item #$index'),
201+
subtitle: const Text('Scroll me!'),
202+
leading: CircleAvatar(child: Text('$index')),
203+
),
204+
);
205+
},
206+
);
207+
}
208+
209+
@override
210+
Widget align(BuildContext context, Widget body, EdgeInsets sideInsets) {
211+
return Padding(padding: sideInsets, child: body);
212+
}
213+
214+
@override
215+
EdgeInsets sideInsets(EdgeInsets preferredInsets) => preferredInsets;
216+
}

example/pubspec.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
name: adaptive_screen_example
22
homepage: https://dev-cetera.com/
3-
repository: https://github.com/robmllze/df_screen
43
funding:
5-
- https://www.patreon.com/c/t0mb3rr
6-
- https://github.com/sponsors/t0mb3rr
4+
- https://www.buymeacoffee.com/dev_cetera
5+
- https://www.patreon.com/c/robelator
6+
- https://github.com/sponsors/robelator
7+
- https://www.patreon.com/c/robelator
8+
- https://github.com/sponsors/robelator
79
- https://www.buymeacoffee.com/dev_cetera
810

911
publish_to: none

lib/src/_src.g.dart

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@
77
// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
88
//.title~
99

10-
export 'adaptive_layout_builder.dart';
10+
// ignore_for_file: directives_ordering
11+
12+
export './adaptive_layout_builder.dart';
13+
export './adaptive_scroll_builder.dart';
14+
export './app_layout.dart';
15+
export './measure_size.dart';
16+
export './screen.dart';
1117
export './screen_bread_crumb_bar.dart';
18+
export './screen_controller.dart';
19+
export './screen_state.dart';
20+
export './screen_states/adaptive_screen_state/adaptive_screen_state.dart';
21+
export './screen_states/adaptive_screen_state/mixins/default_no_scrollable_align_screen_mixin.dart';
1222
export './screen_states/adaptive_screen_state/mixins/default_padding_screen_mixin.dart';
1323
export './screen_states/adaptive_screen_state/mixins/default_scrollable_align_screen_mixin.dart';
14-
export './screen_states/adaptive_screen_state/mixins/never_scrollable_align_screen_mixin.dart';
15-
export './screen_states/adaptive_screen_state/mixins/default_no_scrollable_align_screen_mixin.dart';
16-
export './screen_states/adaptive_screen_state/mixins/rotate_icon_horizontal_mobile_layout_screen_mixin.dart';
1724
export './screen_states/adaptive_screen_state/mixins/mobile_frame_wide_layout_screen_mixin.dart';
18-
export './screen_states/adaptive_screen_state/adaptive_screen_state.dart';
19-
export './screen_controller.dart';
20-
export './screen_state.dart';
21-
export './app_layout.dart';
22-
export './screen.dart';
25+
export './screen_states/adaptive_screen_state/mixins/never_scrollable_align_screen_mixin.dart';
26+
export './screen_states/adaptive_screen_state/mixins/rotate_icon_horizontal_mobile_layout_screen_mixin.dart';
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//.title
2+
// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
3+
//
4+
// Copyright © dev-cetera.com & contributors.
5+
//
6+
// The use of this source code is governed by an MIT-style license described in
7+
// the LICENSE file located in this project's root directory.
8+
//
9+
// See: https://opensource.org/license/mit
10+
//
11+
// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
12+
//.title~
13+
14+
import 'package:flutter/widgets.dart';
15+
16+
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
17+
18+
class AdaptiveScrollBuilder extends StatelessWidget {
19+
final ScrollController controller;
20+
final double expandedSize;
21+
final double collapsedSize;
22+
final Widget Function(BuildContext context, double percentage, Widget? child)
23+
builder;
24+
final Widget? child;
25+
26+
const AdaptiveScrollBuilder({
27+
super.key,
28+
required this.controller,
29+
required this.expandedSize,
30+
required this.collapsedSize,
31+
required this.builder,
32+
this.child,
33+
});
34+
35+
@override
36+
Widget build(BuildContext context) {
37+
return AnimatedBuilder(
38+
animation: controller,
39+
builder: (context, child) {
40+
final offset = controller.hasClients ? controller.offset : 0.0;
41+
final range = expandedSize - collapsedSize;
42+
final t = range == 0 ? 1.0 : (1.0 - (offset / range)).clamp(0.0, 1.0);
43+
return builder(context, t, child);
44+
},
45+
child: child,
46+
);
47+
}
48+
}

lib/src/measure_size.dart

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//.title
2+
// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
3+
//
4+
// Copyright © dev-cetera.com & contributors.
5+
//
6+
// The use of this source code is governed by an MIT-style license described in
7+
// the LICENSE file located in this project's root directory.
8+
//
9+
// See: https://opensource.org/license/mit
10+
//
11+
// ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
12+
//.title~
13+
14+
import 'package:flutter/rendering.dart';
15+
import 'package:flutter/widgets.dart';
16+
17+
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
18+
19+
typedef OnWidgetSizeChange = void Function(Size size);
20+
21+
class MeasureSize extends SingleChildRenderObjectWidget {
22+
final OnWidgetSizeChange onChange;
23+
24+
const MeasureSize({
25+
super.key,
26+
required this.onChange,
27+
required Widget super.child,
28+
});
29+
30+
@override
31+
RenderObject createRenderObject(BuildContext context) {
32+
return _MeasureSizeRenderObject(onChange);
33+
}
34+
35+
@override
36+
void updateRenderObject(
37+
BuildContext context,
38+
_MeasureSizeRenderObject renderObject,
39+
) {
40+
renderObject.onChange = onChange;
41+
}
42+
}
43+
44+
class _MeasureSizeRenderObject extends RenderProxyBox {
45+
OnWidgetSizeChange onChange;
46+
Size? _oldSize;
47+
48+
_MeasureSizeRenderObject(this.onChange);
49+
50+
@override
51+
void performLayout() {
52+
super.performLayout();
53+
final newSize = child?.size ?? Size.zero;
54+
if (_oldSize == newSize) return;
55+
_oldSize = newSize;
56+
WidgetsBinding.instance.addPostFrameCallback((_) {
57+
onChange(newSize);
58+
});
59+
}
60+
}

0 commit comments

Comments
 (0)