Skip to content

Commit 07daffa

Browse files
Add StickyHeader control
1 parent cffd778 commit 07daffa

File tree

4 files changed

+349
-192
lines changed

4 files changed

+349
-192
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
using System;
2+
using System.Runtime.CompilerServices;
3+
using Xamarin.Forms;
4+
5+
namespace SkeletonExample.Controls
6+
{
7+
public enum StickyHeaderAnimations
8+
{
9+
Translation, Resize
10+
}
11+
12+
public class StickyHeader : ContentView
13+
{
14+
#region Attributes
15+
16+
private RowDefinition rowDefinition;
17+
18+
private Grid externalGrid;
19+
20+
private Grid internalGrid;
21+
22+
private ScrollView scrollView;
23+
24+
private View currentHeader;
25+
26+
private View currentContent;
27+
28+
#endregion Attributes
29+
30+
#region Properties
31+
32+
public static readonly BindableProperty HeaderProperty = BindableProperty.Create(nameof(Header), typeof(View), typeof(StickyHeader), defaultValue: null);
33+
34+
public View Header
35+
{
36+
get => (View)GetValue(HeaderProperty);
37+
set => SetValue(HeaderProperty, value);
38+
}
39+
40+
public static new readonly BindableProperty ContentProperty = BindableProperty.Create(nameof(Content), typeof(View), typeof(StickyHeader), defaultValue: null);
41+
42+
public new View Content
43+
{
44+
get => (View)GetValue(ContentProperty);
45+
set => SetValue(ContentProperty, value);
46+
}
47+
48+
public static readonly BindableProperty HeaderHeightProperty = BindableProperty.Create(nameof(HeaderHeight), typeof(double), typeof(StickyHeader), defaultValue: 100.0);
49+
50+
public double HeaderHeight
51+
{
52+
get => (double)GetValue(HeaderHeightProperty);
53+
set => SetValue(HeaderHeightProperty, value);
54+
}
55+
56+
public static readonly BindableProperty MinimumHeaderHeightProperty = BindableProperty.Create(nameof(MinimumHeaderHeight), typeof(double), typeof(StickyHeader), defaultValue: 50.0);
57+
58+
public double MinimumHeaderHeight
59+
{
60+
get => (double)GetValue(MinimumHeaderHeightProperty);
61+
set => SetValue(MinimumHeaderHeightProperty, value);
62+
}
63+
64+
public static readonly BindableProperty AnimationProperty = BindableProperty.Create(nameof(Animation), typeof(StickyHeaderAnimations), typeof(StickyHeader), defaultValue: StickyHeaderAnimations.Translation);
65+
66+
public StickyHeaderAnimations Animation
67+
{
68+
get => (StickyHeaderAnimations)GetValue(AnimationProperty);
69+
set => SetValue(AnimationProperty, value);
70+
}
71+
72+
#endregion Properties
73+
74+
#region Constructors
75+
76+
public StickyHeader()
77+
{
78+
this.externalGrid = new Grid { ColumnSpacing = 0, RowSpacing = 0 };
79+
80+
this.scrollView = new ScrollView();
81+
this.scrollView.Scrolled += this.ScrollViewScrolled;
82+
this.externalGrid.Children.Add(this.scrollView, 0, 0);
83+
84+
this.internalGrid = new Grid { ColumnSpacing = 0, RowSpacing = 0 };
85+
this.scrollView.Content = this.internalGrid;
86+
87+
this.rowDefinition = new RowDefinition { Height = new GridLength(this.HeaderHeight, GridUnitType.Absolute) };
88+
this.internalGrid.RowDefinitions.Add(this.rowDefinition);
89+
90+
this.internalGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
91+
92+
base.Content = this.externalGrid;
93+
}
94+
95+
#endregion Constructors
96+
97+
#region Operations
98+
99+
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
100+
{
101+
switch (propertyName)
102+
{
103+
case nameof(this.Header):
104+
if (this.currentHeader != null)
105+
{
106+
this.externalGrid.Children.Remove(this.currentHeader);
107+
}
108+
109+
if (this.Header != null)
110+
{
111+
this.currentHeader = this.Header;
112+
this.currentHeader.HeightRequest = this.HeaderHeight;
113+
this.currentHeader.VerticalOptions = LayoutOptions.Start;
114+
this.externalGrid.Children.Add(this.currentHeader, 0, 0);
115+
}
116+
break;
117+
case nameof(this.Content):
118+
if (this.currentContent != null)
119+
{
120+
this.internalGrid.Children.Remove(this.currentContent);
121+
}
122+
123+
if (this.Content != null)
124+
{
125+
this.currentContent = this.Content;
126+
this.internalGrid.Children.Add(this.currentContent, 0, 1);
127+
}
128+
break;
129+
case nameof(this.HeaderHeight):
130+
if (this.currentHeader != null)
131+
{
132+
this.currentHeader.HeightRequest = this.HeaderHeight;
133+
}
134+
this.rowDefinition.Height = new GridLength(this.HeaderHeight, GridUnitType.Absolute);
135+
break;
136+
}
137+
}
138+
139+
private void ScrollViewScrolled(object sender, ScrolledEventArgs e)
140+
{
141+
var scrollY = ((ScrollView)sender).ScrollY;
142+
if (this.Animation == StickyHeaderAnimations.Translation)
143+
{
144+
if (scrollY < this.MinimumHeaderHeight)
145+
{
146+
this.currentHeader.TranslationY = 0 - scrollY;
147+
}
148+
}
149+
else
150+
{
151+
var height = this.HeaderHeight - scrollY;
152+
if (height > this.MinimumHeaderHeight)
153+
{
154+
this.currentHeader.HeightRequest = height;
155+
}
156+
}
157+
}
158+
159+
#endregion Operations
160+
}
161+
}

0 commit comments

Comments
 (0)