Skip to content

Commit 5d5ed19

Browse files
Episode 28: Fixing the iOS Frame Shadow
- Added the RecentActivity Page and PageModel - Added ExtendedFrame and iOS Renderer - Began RecentActivity Page Layout
1 parent ef6469e commit 5d5ed19

10 files changed

+190
-1
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System;
2+
using System.ComponentModel;
3+
using TimeTrackerTutorial.iOS.Renderers;
4+
using TimeTrackerTutorial.Views.Layouts;
5+
using Xamarin.Forms;
6+
using Xamarin.Forms.Platform.iOS;
7+
8+
[assembly: ExportRenderer(typeof(ExtendedFrame), typeof(ExtendedFrameRenderer))]
9+
namespace TimeTrackerTutorial.iOS.Renderers
10+
{
11+
public class ExtendedFrameRenderer : FrameRenderer
12+
{
13+
protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
14+
{
15+
base.OnElementChanged(e);
16+
if (e.NewElement != null)
17+
{
18+
// update frame's shadow
19+
UpdateShadow();
20+
}
21+
}
22+
23+
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
24+
{
25+
// check if property is the frame's shadow
26+
if (e.PropertyName == ExtendedFrame.ShadowOffsetProperty.PropertyName ||
27+
e.PropertyName == ExtendedFrame.ShadowOpacityProperty.PropertyName ||
28+
e.PropertyName == ExtendedFrame.ShadowRadiusProperty.PropertyName)
29+
{
30+
UpdateShadow();
31+
}
32+
else
33+
{
34+
base.OnElementPropertyChanged(sender, e);
35+
}
36+
}
37+
38+
private void UpdateShadow()
39+
{
40+
if (Element.HasShadow)
41+
{
42+
// update it
43+
var extendedFrame = Element as ExtendedFrame;
44+
Layer.ShadowOpacity = extendedFrame.ShadowOpacity;
45+
Layer.ShadowOffset = new CoreGraphics.CGSize(extendedFrame.ShadowOffset.X, extendedFrame.ShadowOffset.Y);
46+
Layer.ShadowRadius = extendedFrame.ShadowRadius;
47+
}
48+
else
49+
{
50+
Layer.ShadowOpacity = 0;
51+
}
52+
}
53+
}
54+
}

TimeTrackerTutorial.iOS/TimeTrackerTutorial.iOS.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
<Compile Include="Services\WorkItemRepository.cs" />
8383
<Compile Include="Extensions\IIdentifiableExtensions.cs" />
8484
<Compile Include="Renderers\PlainEntryRenderer.cs" />
85+
<Compile Include="Renderers\ExtendedFrameRenderer.cs" />
8586
</ItemGroup>
8687
<ItemGroup>
8788
<InterfaceDefinition Include="Resources\LaunchScreen.storyboard" />

TimeTrackerTutorial/App.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
<Color x:Key="PrimaryHeaderColor">#01A9DB</Color>
1010
<Color x:Key="GradientStartColor">#00BFFF</Color>
1111
<Color x:Key="GradientEndColor">#086A87</Color>
12+
<Color x:Key="BackgroundColorLight">#EFEFEF</Color>
1213
</Application.Resources>
1314
</Application>

TimeTrackerTutorial/PageModels/Base/PageModelLocator.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ static PageModelLocator()
3333
Register<SummaryPageModel, SummaryPage>();
3434
Register<TimeClockPageModel, TimeClockPage>();
3535

36+
Register<RecentActivityPageModel, RecentActivityPage>();
37+
3638
// Register Services (registered as Singletons by default)
3739
_container.Register<INavigationService, NavigationService>();
3840
_container.Register<IAccountService>(DependencyService.Get<IAccountService>());

TimeTrackerTutorial/PageModels/LoginPageModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ private async void OnLogin()
4646
if (loginAttempt)
4747
{
4848
// navigate to the Dashboard.
49-
await _navigationService.NavigateToAsync<DashboardPageModel>();
49+
await _navigationService.NavigateToAsync<RecentActivityPageModel>();
5050
}
5151
else
5252
{
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using TimeTrackerTutorial.PageModels.Base;
3+
using TimeTrackerTutorial.ViewModels.Buttons;
4+
5+
namespace TimeTrackerTutorial.PageModels
6+
{
7+
public class RecentActivityPageModel : PageModelBase
8+
{
9+
10+
private ButtonModel _viewAllModel;
11+
public ButtonModel ViewAllModel
12+
{
13+
get => _viewAllModel;
14+
set => SetProperty(ref _viewAllModel, value);
15+
}
16+
17+
private ButtonModel _clockInModel;
18+
public ButtonModel ClockInModel
19+
{
20+
get => _clockInModel;
21+
set => SetProperty(ref _clockInModel, value);
22+
}
23+
public RecentActivityPageModel()
24+
{
25+
26+
ViewAllModel = new ButtonModel("View All", OnViewAll);
27+
ClockInModel = new ButtonModel("CLOCK IN", OnClockIn);
28+
}
29+
30+
private void OnClockIn()
31+
{
32+
33+
}
34+
35+
private void OnViewAll()
36+
{
37+
38+
}
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<ContentPage
3+
xmlns="http://xamarin.com/schemas/2014/forms"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
5+
xmlns:skViews="clr-namespace:TimeTrackerTutorial.Views.SKViews"
6+
xmlns:buttons="clr-namespace:TimeTrackerTutorial.Views.Buttons"
7+
xmlns:layouts="clr-namespace:TimeTrackerTutorial.Views.Layouts"
8+
NavigationPage.HasNavigationBar="False"
9+
x:Class="TimeTrackerTutorial.Pages.RecentActivityPage">
10+
<ContentPage.Content>
11+
<Grid RowDefinitions="280,*" BackgroundColor="{StaticResource BackgroundColorLight}">
12+
<skViews:RectGradientView StartColor="{StaticResource GradientStartColor}"
13+
EndColor="{StaticResource GradientEndColor}"
14+
VerticalOptions="FillAndExpand" />
15+
<StackLayout>
16+
<!-- Header layout -->
17+
</StackLayout>
18+
19+
<StackLayout Grid.Row="1" Margin="20">
20+
<StackLayout Orientation="Horizontal">
21+
<Label Text="Recent Activity" VerticalOptions="Center" />
22+
<buttons:BindableButton BackgroundColor="Transparent"
23+
BindingContext="{Binding ViewAllModel}"
24+
FontAttributes="None" HorizontalOptions="EndAndExpand" />
25+
</StackLayout>
26+
<layouts:ExtendedFrame BackgroundColor="White" CornerRadius="20" HasShadow="True"
27+
Padding="10" VerticalOptions="FillAndExpand" ShadowOpacity="0.25"
28+
ShadowOffset="0,3" ShadowRadius="3">
29+
<StackLayout>
30+
<!-- recent activity list -->
31+
</StackLayout>
32+
</layouts:ExtendedFrame>
33+
</StackLayout>
34+
35+
<buttons:BindableButton BindingContext="{Binding ClockInModel}"
36+
Grid.Row="1" Margin="0,-30,0,0"
37+
VerticalOptions="Start" />
38+
</Grid>
39+
</ContentPage.Content>
40+
</ContentPage>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
using Xamarin.Forms;
5+
6+
namespace TimeTrackerTutorial.Pages
7+
{
8+
public partial class RecentActivityPage : ContentPage
9+
{
10+
public RecentActivityPage()
11+
{
12+
InitializeComponent();
13+
}
14+
}
15+
}

TimeTrackerTutorial/TimeTrackerTutorial.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<Folder Include="Views\SKViews\" />
2727
<Folder Include="Views\SKViews\Base\" />
2828
<Folder Include="Views\Entries\" />
29+
<Folder Include="Views\Layouts\" />
2930
</ItemGroup>
3031

3132
<ItemGroup>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using Xamarin.Forms;
3+
4+
namespace TimeTrackerTutorial.Views.Layouts
5+
{
6+
public class ExtendedFrame : Frame
7+
{
8+
public static readonly BindableProperty ShadowOffsetProperty = BindableProperty.Create(
9+
nameof(ShadowOffset), typeof(Point), typeof(ExtendedFrame), Point.Zero);
10+
11+
public static readonly BindableProperty ShadowRadiusProperty = BindableProperty.Create(
12+
nameof(ShadowRadius), typeof(float), typeof(ExtendedFrame), 5.0f);
13+
14+
public static readonly BindableProperty ShadowOpacityProperty = BindableProperty.Create(
15+
nameof(ShadowOpacity), typeof(float), typeof(ExtendedFrame), 0.8f);
16+
17+
public Point ShadowOffset
18+
{
19+
get => (Point)GetValue(ShadowOffsetProperty);
20+
set => SetValue(ShadowOffsetProperty, value);
21+
}
22+
23+
public float ShadowRadius
24+
{
25+
get => (float)GetValue(ShadowRadiusProperty);
26+
set => SetValue(ShadowRadiusProperty, value);
27+
}
28+
29+
public float ShadowOpacity
30+
{
31+
get => (float)GetValue(ShadowOpacityProperty);
32+
set => SetValue(ShadowOpacityProperty, value);
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)