Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[![pub package](https://img.shields.io/pub/v/getwidget.svg)](https://pub.dartlang.org/packages/getwidget) [![Build Status](https://travis-ci.org/ionicfirebaseapp/getwidget.svg?branch=master)](https://travis-ci.com/ionicfirebaseapp/getwidget) [![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=102)](https://opensource.org/licenses/MIT) [![License](https://img.shields.io/badge/license-MIT-orange.svg)](https://github.com/ionicfirebaseapp/getwidget/blob/master/LICENSE) [![Twitter Follow](https://img.shields.io/twitter/follow/getwidgetdev.svg?style=social)](https://twitter.com/getwidgetdev)


<p align="center">
<a href="https://docs.getwidget.dev/" target="_blank">
<img src="https://ik.imagekit.io/ionicfirebaseapp/logo.black_iOBoLWdj2I.png" alt="GetWidget">
Expand Down Expand Up @@ -28,6 +27,7 @@
</p>



## Quick start

Read the [Getting started page](https://docs.getwidget.dev)
Expand Down
63 changes: 63 additions & 0 deletions lib/components/sticky_header/gf_sticky_header.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'package:getwidget/getwidget.dart';

/// Place this widget inside a [ListView], [GridView], [CustomScrollView], [SingleChildScrollView] or similar.

class GFStickyHeader extends MultiChildRenderObjectWidget {
GFStickyHeader(
{Key key,
@required this.stickyContent,
@required this.content,
this.direction = Axis.vertical,
this.enableHeaderOverlap = false,
this.callback,
this.stickyContentPosition = GFPosition.start})
: assert(direction != null),
super(
key: key,
children: stickyContentPosition == GFPosition.start &&
direction == Axis.horizontal
? [stickyContent, content]
: stickyContentPosition == GFPosition.start &&
direction == Axis.vertical
? [content, stickyContent]
: [content, stickyContent]);

/// widget can be used to define [stickyContent].
final Widget stickyContent;

/// widget can be used to define [content].
final Widget content;

/// On state true, the [stickyContent] will overlap the [content].
/// Only works when direction is [Axis.vertical]. Default set to false.
final bool enableHeaderOverlap;

/// [GFPosition] allows to [stickyContentPosition] to stick at top in [Axis.vertical] and stick at start in [Axis.horizontal]
/// Defaults to [GFPosition.start]
final GFPosition stickyContentPosition;

/// Allows to add custom stickyHeader stuck offset value
final RenderGFStickyHeaderCallback callback;

/// [direction] allows children to align in vertical / horizontal way
/// Defaults to [Axis.vertical]
final Axis direction;

@override
RenderGFStickyHeader createRenderObject(BuildContext context) {
final scrollable = Scrollable.of(context);
assert(scrollable != null);
return RenderGFStickyHeader(
direction: direction,
scrollable: scrollable,
enableHeaderOverlap: enableHeaderOverlap,
callback: callback,
stickyContentPosition: stickyContentPosition,
);
}
}
71 changes: 71 additions & 0 deletions lib/components/sticky_header/gf_sticky_header_builder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import 'package:flutter/material.dart';
import 'package:getwidget/getwidget.dart';

typedef StickyHeaderWidgetBuilder = Widget Function(
BuildContext context, double stuckValue);

/// Place this widget inside a [ListView], [GridView], [CustomScrollView], [SingleChildScrollView] or similar.

class GFStickyHeaderBuilder extends StatefulWidget {
/// Constructs a new [GFStickyHeaderBuilder] widget.
const GFStickyHeaderBuilder({
Key key,
@required this.stickyContentBuilder,
@required this.content,
this.direction = Axis.vertical,
this.enableHeaderOverlap = false,
this.callback,
this.stickyContentPosition = GFPosition.start,
}) : assert(direction != null),
super(key: key);

/// widget can be used to define [stickyContentBuilder].
final StickyHeaderWidgetBuilder stickyContentBuilder;

/// widget can be used to define [content].
final Widget content;

/// On state true, the [stickyContentBuilder] will overlap the [content].
/// Only works when direction is [Axis.vertical]. Default set to false.
final bool enableHeaderOverlap;

/// [GFPosition] allows to [stickyContentPosition] to stick at top in [Axis.vertical] and stick at start in [Axis.horizontal]
/// Defaults to [GFPosition.start]
final GFPosition stickyContentPosition;

/// Allows to add custom stickyHeader stuck offset value
final RenderGFStickyHeaderCallback callback;

/// [direction] allows children to align in vertical / horizontal way
/// Defaults to [Axis.vertical]
final Axis direction;

@override
_GFStickyHeaderBuilderState createState() => _GFStickyHeaderBuilderState();
}

class _GFStickyHeaderBuilderState extends State<GFStickyHeaderBuilder> {
double _stuckValue;

@override
Widget build(BuildContext context) => GFStickyHeader(
enableHeaderOverlap: widget.enableHeaderOverlap,
direction: widget.direction,
stickyContentPosition: widget.stickyContentPosition,
stickyContent: LayoutBuilder(
builder: (context, _) =>
widget.stickyContentBuilder(context, _stuckValue ?? 0.0),
),
content: widget.content,
callback: (double stuckValue) {
if (_stuckValue != stuckValue) {
_stuckValue = stuckValue;
WidgetsBinding.instance.endOfFrame.then((_) {
if (mounted) {
setState(() {});
}
});
}
},
);
}
Loading