Skip to content

Commit a42ebe9

Browse files
committed
Added multiplatform support, adapted iOS implementation, implemented macOS and added macOS sample project
1 parent b5cd916 commit a42ebe9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2325
-116
lines changed
Lines changed: 42 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,44 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3-
<PropertyGroup>
4-
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5-
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6-
<ProjectGuid>{75D2DA9D-DFD4-49A1-98FB-FE0F0677EF0F}</ProjectGuid>
7-
<ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
8-
<OutputType>Library</OutputType>
9-
<RootNamespace>Cirrious.FluentLayouts.Touch</RootNamespace>
10-
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
11-
<AssemblyName>Cirrious.FluentLayouts.Touch</AssemblyName>
12-
<TargetFrameworkIdentifier>Xamarin.iOS</TargetFrameworkIdentifier>
13-
<TargetFrameworkVersion>v1.0</TargetFrameworkVersion>
14-
</PropertyGroup>
15-
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
16-
<DebugSymbols>true</DebugSymbols>
17-
<DebugType>full</DebugType>
18-
<Optimize>false</Optimize>
19-
<OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
20-
<DefineConstants>DEBUG</DefineConstants>
21-
<ErrorReport>prompt</ErrorReport>
22-
<WarningLevel>4</WarningLevel>
23-
<ConsolePause>false</ConsolePause>
24-
<MtouchLink>None</MtouchLink>
25-
<MtouchDebug>true</MtouchDebug>
26-
</PropertyGroup>
27-
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
28-
<DebugType>none</DebugType>
29-
<Optimize>true</Optimize>
30-
<OutputPath>bin\iPhoneSimulator\Release</OutputPath>
31-
<ErrorReport>prompt</ErrorReport>
32-
<WarningLevel>4</WarningLevel>
33-
<ConsolePause>false</ConsolePause>
34-
<MtouchLink>None</MtouchLink>
35-
</PropertyGroup>
36-
<ItemGroup>
37-
<Compile Include="AdvancedFluentLayoutExtensions.cs" />
38-
<Compile Include="FluentLayout.cs" />
39-
<Compile Include="FluentLayoutExtensions.cs" />
40-
<Compile Include="Margins.cs" />
41-
<Compile Include="Properties\AssemblyInfo.cs" />
42-
<Compile Include="RowSet-WorkInProgress\RowSet.cs" />
43-
<Compile Include="UIViewAndLayoutAttribute.cs" />
44-
<Compile Include="NfloatExtensions.cs" />
45-
<Compile Include="Extensions\ArrayExtensions.cs" />
46-
</ItemGroup>
47-
<ItemGroup>
48-
</ItemGroup>
49-
<ItemGroup>
50-
<Reference Include="System" />
51-
<Reference Include="System.Xml" />
52-
<Reference Include="System.Core" />
53-
<Reference Include="Xamarin.iOS" />
54-
</ItemGroup>
55-
<ItemGroup>
56-
<Folder Include="Extensions\" />
57-
</ItemGroup>
58-
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
2+
<Project Sdk="MSBuild.Sdk.Extras/2.0.41">
3+
<PropertyGroup>
4+
<TargetFrameworks>xamarin.ios10;xamarin.mac20</TargetFrameworks>
5+
<PackageProjectUrl>https://github.com/FluentLayout/Cirrious.FluentLayout</PackageProjectUrl>
6+
<Product>$(AssemblyName) ($(TargetFramework))</Product>
7+
<PackageTags>xamarin ios mac constraints</PackageTags>
8+
<PackageLicenseExpression>MS-PL</PackageLicenseExpression>
9+
<LangVersion>7.3</LangVersion>
10+
<NoWarn>$(NoWarn);1591;1701;1591;1702;1705;VSX1000;NU1603</NoWarn>
11+
<RepositoryUrl>https://github.com/FluentLayout/Cirrious.FluentLayout</RepositoryUrl>
12+
<RepositoryType>git</RepositoryType>
13+
<IncludeSymbols>True</IncludeSymbols>
14+
<IncludeSource>True</IncludeSource>
15+
<PublishRepositoryUrl>true</PublishRepositoryUrl>
16+
<EmbedUntrackedSources>true</EmbedUntrackedSources>
17+
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
18+
</PropertyGroup>
19+
20+
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
21+
<DebugType>full</DebugType>
22+
<DebugSymbols>true</DebugSymbols>
23+
</PropertyGroup>
24+
25+
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
26+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
27+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
28+
</PropertyGroup>
29+
30+
<ItemGroup>
31+
<Compile Remove="Platforms\**\*.*" />
32+
<None Include="Platforms\**\*.*" />
33+
</ItemGroup>
34+
35+
<ItemGroup Condition=" $(TargetFramework.StartsWith('xamarin.ios')) ">
36+
<Compile Include="Platforms\Shared\**\*.cs" />
37+
<Compile Include="Platforms\iOS\**\*.cs" />
38+
</ItemGroup>
39+
40+
<ItemGroup Condition=" $(TargetFramework.StartsWith('xamarin.mac')) ">
41+
<Compile Include="Platforms\Shared\**\*.cs" />
42+
<Compile Include="Platforms\Mac\**\*.cs" />
43+
</ItemGroup>
5944
</Project>
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
// AdvancedFluentLayoutExtensions.cs
2+
// (c) Copyright Cirrious Ltd. http://www.cirrious.com
3+
// MvvmCross is licensed using Microsoft Public License (Ms-PL)
4+
// Contributions and inspirations noted in readme.md and license.txt
5+
//
6+
// Project Lead - Stuart Lodge, @slodge, [email protected]
7+
8+
using System;
9+
using System.Collections.Generic;
10+
using System.Linq;
11+
using AppKit;
12+
using Cirrious.FluentLayouts.Touch.Extensions;
13+
14+
namespace Cirrious.FluentLayouts.Touch
15+
{
16+
public static class AdvancedFluentLayoutExtensions
17+
{
18+
const float DefaultMargin = 0;
19+
const float DefaultScale = 1;
20+
21+
public static FluentLayout AtTopOf(this NSView view, NSView parentView, nfloat? margin = null) =>
22+
view.Top().EqualTo().TopOf(parentView).Plus(margin.GetValueOrDefault(DefaultMargin));
23+
24+
public static FluentLayout AtLeftOf(this NSView view, NSView parentView, nfloat? margin = null) =>
25+
view.Left().EqualTo().LeftOf(parentView).Plus(margin.GetValueOrDefault(DefaultMargin));
26+
27+
public static FluentLayout AtRightOf(this NSView view, NSView parentView, nfloat? margin = null) =>
28+
view.Right().EqualTo().RightOf(parentView).Minus(margin.GetValueOrDefault(DefaultMargin));
29+
30+
public static FluentLayout AtBottomOf(this NSView view, NSView parentView, nfloat? margin = null) =>
31+
view.Bottom().EqualTo().BottomOf(parentView).Minus(margin.GetValueOrDefault(DefaultMargin));
32+
33+
public static FluentLayout AtLeadingOf(this NSView view, NSView parentView, nfloat? margin = null) =>
34+
view.Leading().EqualTo().LeadingOf(parentView).Plus(margin.GetValueOrDefault(DefaultMargin));
35+
36+
public static FluentLayout AtTrailingOf(this NSView view, NSView parentView, nfloat? margin = null) =>
37+
view.Trailing().EqualTo().TrailingOf(parentView).Minus(margin.GetValueOrDefault(DefaultMargin));
38+
39+
public static FluentLayout Below(this NSView view, NSView previous, nfloat? margin = null) =>
40+
view.Top().EqualTo().BottomOf(previous).Plus(margin.GetValueOrDefault(DefaultMargin));
41+
42+
public static FluentLayout Above(this NSView view, NSView previous, nfloat? margin = null) =>
43+
view.Bottom().EqualTo().TopOf(previous).Minus(margin.GetValueOrDefault(DefaultMargin));
44+
45+
public static FluentLayout WithSameLeft(this NSView view, NSView previous) => view.Left().EqualTo().LeftOf(previous);
46+
47+
public static FluentLayout WithSameTop(this NSView view, NSView previous) => view.Top().EqualTo().TopOf(previous);
48+
49+
public static FluentLayout WithSameCenterX(this NSView view, NSView previous) => view.CenterX().EqualTo().CenterXOf(previous);
50+
51+
public static FluentLayout WithSameCenterY(this NSView view, NSView previous) => view.CenterY().EqualTo().CenterYOf(previous);
52+
53+
public static FluentLayout WithSameRight(this NSView view, NSView previous) => view.Right().EqualTo().RightOf(previous);
54+
55+
public static FluentLayout WithSameWidth(this NSView view, NSView previous) => view.Width().EqualTo().WidthOf(previous);
56+
57+
public static FluentLayout WithSameBottom(this NSView view, NSView previous) => view.Bottom().EqualTo().BottomOf(previous);
58+
59+
public static FluentLayout WithSameLeading(this NSView view, NSView previous) => view.Leading().EqualTo().LeadingOf(previous);
60+
61+
public static FluentLayout WithSameTrailing(this NSView view, NSView previous) => view.Trailing().EqualTo().TrailingOf(previous);
62+
63+
public static FluentLayout WithRelativeWidth(this NSView view, NSView previous, nfloat? scale = null) =>
64+
view.Width().EqualTo().WidthOf(previous).WithMultiplier(scale.GetValueOrDefault(DefaultScale));
65+
66+
public static FluentLayout WithSameHeight(this NSView view, NSView previous) => view.Height().EqualTo().HeightOf(previous);
67+
68+
public static FluentLayout WithRelativeHeight(this NSView view, NSView previous, nfloat? scale = null) =>
69+
view.Height().EqualTo().HeightOf(previous).WithMultiplier(scale.GetValueOrDefault(DefaultScale));
70+
71+
public static FluentLayout ToRightOf(this NSView view, NSView previous, nfloat? margin = null) =>
72+
view.Left().EqualTo().RightOf(previous).Plus(margin.GetValueOrDefault(DefaultMargin));
73+
74+
public static FluentLayout ToLeftOf(this NSView view, NSView previous, nfloat? margin = null) =>
75+
view.Right().EqualTo().LeftOf(previous).Minus(margin.GetValueOrDefault(DefaultMargin));
76+
77+
public static FluentLayout ToTrailingOf(this NSView view, NSView previous, nfloat? margin = null) =>
78+
view.Leading().EqualTo().TrailingOf(previous).Plus(margin.GetValueOrDefault(DefaultMargin));
79+
80+
public static FluentLayout ToLeadingOf(this NSView view, NSView previous, nfloat? margin = null) =>
81+
view.Trailing().EqualTo().LeadingOf(previous).Minus(margin.GetValueOrDefault(DefaultMargin));
82+
83+
//public static FluentLayout ToLeftMargin(this NSView view, NSView previous) =>
84+
// view.Leading().EqualTo().LeadingMarginOf(previous);
85+
86+
//public static FluentLayout ToRightMargin(this NSView view, NSView previous) =>
87+
// view.Trailing().EqualTo().TrailingMarginOf(previous);
88+
89+
//public static FluentLayout ToTopMargin(this NSView view, NSView previous) =>
90+
// view.Top().EqualTo().TopMarginOf(previous);
91+
92+
//public static FluentLayout ToBottomMargin(this NSView view, NSView previous) =>
93+
// view.Bottom().EqualTo().BottomMarginOf(previous);
94+
95+
public static FluentLayout ToLeftOfCenterOf(this NSView view, NSView previous, nfloat? margin = null) =>
96+
view.Right().EqualTo().CenterXOf(previous).Minus(margin.GetValueOrDefault(0));
97+
98+
public static FluentLayout ToRightOfCenterOf(this NSView view, NSView previous, nfloat? margin = null) =>
99+
view.Left().EqualTo().CenterXOf(previous).Plus(margin.GetValueOrDefault(0));
100+
101+
public static FluentLayout AboveCenterOf(this NSView view, NSView previous, nfloat? margin = null) =>
102+
view.Bottom().EqualTo().CenterYOf(previous).Minus(margin.GetValueOrDefault(0));
103+
104+
public static FluentLayout BelowCenterOf(this NSView view, NSView previous, nfloat? margin = null) =>
105+
view.Top().EqualTo().CenterYOf(previous).Plus(margin.GetValueOrDefault(0));
106+
107+
public static IEnumerable<FluentLayout> FullWidthOf(this NSView view, NSView parent, nfloat? margin = null)
108+
{
109+
var marginValue = margin.GetValueOrDefault(DefaultMargin);
110+
111+
return new List<FluentLayout>
112+
{
113+
view.AtLeftOf(parent, marginValue).WithIdentifier("Left"),
114+
view.AtRightOf(parent, marginValue).WithIdentifier("Right")
115+
};
116+
}
117+
118+
public static IEnumerable<FluentLayout> FullHeightOf(this NSView view, NSView parent, nfloat? margin = null)
119+
{
120+
var marginValue = margin.GetValueOrDefault(DefaultMargin);
121+
122+
return new List<FluentLayout>
123+
{
124+
view.AtTopOf(parent, marginValue).WithIdentifier("Top"),
125+
view.AtBottomOf(parent, marginValue).WithIdentifier("Bottom")
126+
};
127+
}
128+
129+
public static IEnumerable<FluentLayout> FullSizeOf(this NSView view, NSView parent, nfloat? margin = null) =>
130+
FullSizeOf(view, parent, new Margins((float)margin.GetValueOrDefault(DefaultMargin)));
131+
132+
public static IEnumerable<FluentLayout> FullSizeOf(this NSView view, NSView parent, Margins margins)
133+
{
134+
margins = margins ?? new Margins();
135+
136+
return new List<FluentLayout>
137+
{
138+
view.AtTopOf(parent, margins.Top).WithIdentifier("Top"),
139+
view.AtBottomOf(parent, margins.Bottom).WithIdentifier("Bottom"),
140+
view.AtLeftOf(parent, margins.Left).WithIdentifier("Left"),
141+
view.AtRightOf(parent, margins.Right).WithIdentifier("Right")
142+
};
143+
}
144+
145+
public static FluentLayout GetLayoutById(this IEnumerable<FluentLayout> layouts, string identifier) =>
146+
layouts.FirstOrDefault(x => x.Identifier.Equals(identifier));
147+
148+
public static IEnumerable<FluentLayout> VerticalStackPanelConstraints(this NSView parentView, Margins margins, params NSView[] views) =>
149+
AdvancedVerticalStackPanelConstraints(parentView, margins, views: views);
150+
151+
/// <summary>
152+
/// Vertical stack panel constraints with support for children independent left, right and top margins
153+
/// and a multiplier factor for all margins applied. The multiplier can be useful when dealing with iPad screens.
154+
/// Example:
155+
///
156+
/// scrollView.AddConstraints(scrollView.AdvancedVerticalStackPanelConstraints(null,
157+
/// childrenLeftMargins: new float[] { 15, 0, 15, 0, 0, 15 },
158+
/// childrenTopMargins: new float[] { 15, 5, 15, 5, 8, 15, 22, 8, 8, 28, 28 },
159+
/// marginMultiplier: 2f,
160+
/// views: scrollView.Subviews)
161+
/// );
162+
/// </summary>
163+
public static IEnumerable<FluentLayout> AdvancedVerticalStackPanelConstraints(this NSView parentView,
164+
Margins margins,
165+
float[] childrenLeftMargins = null,
166+
float[] childrenTopMargins = null,
167+
float[] childrenRightMargins = null,
168+
float marginMultiplier = 1,
169+
params NSView[] views)
170+
{
171+
string previousIdentifierPrefix = null;
172+
margins = margins ?? new Margins();
173+
var layouts = new List<FluentLayout>();
174+
175+
var count = views.Length;
176+
for (var i = 0; i < count; i++)
177+
{
178+
var view = views[i];
179+
var viewIdentifierPrefix = $"{parentView.AccessibilityIdentifier ?? "VerticalStackPanel"}-{view.AccessibilityIdentifier ?? i.ToString()}-";
180+
181+
float childLeftMargin;
182+
childrenLeftMargins.TryGetElement(i, out childLeftMargin);
183+
var marginLeft = Math.Max(margins.Left, childLeftMargin) * marginMultiplier;
184+
layouts.Add(view.Left()
185+
.EqualTo()
186+
.LeftOf(parentView)
187+
.Plus(marginLeft)
188+
.WithIdentifier(viewIdentifierPrefix + "Left"));
189+
190+
float childRightMargin;
191+
childrenRightMargins.TryGetElement(i, out childRightMargin);
192+
var marginRight = Math.Max(margins.Right, childRightMargin) * marginMultiplier;
193+
layouts.Add(view.Width()
194+
.EqualTo()
195+
.WidthOf(parentView)
196+
.Minus(marginRight + marginLeft)
197+
.WithIdentifier(viewIdentifierPrefix + "Width"));
198+
199+
float childTopMargin;
200+
childrenTopMargins.TryGetElement(i, out childTopMargin);
201+
202+
layouts.Add(i == 0
203+
? view.Top()
204+
.EqualTo()
205+
.TopOf(parentView)
206+
.Plus(Math.Max(margins.Top, childTopMargin)*marginMultiplier)
207+
.WithIdentifier(viewIdentifierPrefix + "Top")
208+
: view.Top()
209+
.EqualTo()
210+
.BottomOf(views[i - 1])
211+
.Plus(Math.Max(margins.VSpacing, childTopMargin)*marginMultiplier)
212+
.WithIdentifier(viewIdentifierPrefix + "Top"));
213+
214+
previousIdentifierPrefix = viewIdentifierPrefix;
215+
}
216+
217+
if (parentView is NSScrollView)
218+
layouts.Add(views[views.Length - 1].Bottom()
219+
.EqualTo()
220+
.BottomOf(parentView)
221+
.Minus(margins.Bottom * marginMultiplier)
222+
.WithIdentifier(previousIdentifierPrefix + "Bottom"));
223+
224+
return layouts;
225+
}
226+
}
227+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using AppKit;
2+
3+
namespace Cirrious.FluentLayouts.Touch.Extensions
4+
{
5+
public static class NSViewExtensions
6+
{
7+
public static void AddSubviews(this NSView view, params NSView[] subviews)
8+
{
9+
foreach (var subview in subviews)
10+
view.AddSubview(subview);
11+
}
12+
}
13+
}

0 commit comments

Comments
 (0)