Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
[Material] + [Android, iOS] Refactored and fixed lots of button layou…
Browse files Browse the repository at this point in the history
…t issues (#4967)

* [Android] Refactored and fixed lots of button layout issues
 - All text, image and content layout logic has been extracted into a separate manager
 - Fixed the issue buttons with just an image changing size
 - Fixed a few button padding issues (still needs another look)
 - Fixed the issue with the content layout changes not updating the actual button layout
 - Fixed image positioning for all (not legacy) buttons
 - Material button no longer uses material image layout as it overrides the custom positioning
 - Fixed a few other issues where properties don't change the native button, or layouts break the positioning of the image

* [Button] Fixed a whole bunch of issues
 - added a platform specific "BorderAdjustsPadding" to Android and iOS to prevent border overlap
 - added a new gallery with all sorts of buttons
 - improvements to the Android button layout manager
 - fixed to the Android button measure/layout process

* [Android] [Button] The preservation of default padding is now a flag

* [iOS] [Button] Extracted all the layout logic for the classic button
 - yet to update Material button to use this
 - fixed a few issues with the iOS layout
    - content layout changes were not updating the control
    - top/bottom did not respect spacing
    - the native control trimmed text in the getter, so use the value from the element

* Removing the platform specifics as they were the wrong property
 - the property is part of the renderer implementation
 - Material button on iOS still needs implementing

* Updated the material button to use the layout manager
 - the iOS layout logic needs some more investigation

* remove old comments

* A fix for when there is no text and some backwards compatibility

* Added a more realistic set of values

* Restrict the material button border to 1px. See #4951.

* Fixed that issue with the buttons and the padding...
 - Removed the inset so that layout is accurate
 - set the padding to 8dp to match that of iOS and Material
 - set the minimum height to 36 according to Material (it was 48dp, with 12dp total inset, and, 48-12=36)

* Update Xamarin.Forms.Core/Button.cs

Co-Authored-By: mattleibow <mattleibow@live.com>

* Don't add members to the public type

* [Material] Added a button to change text size in the demo page

* appcompat regression fixes

* move state checks around

* fix bad merge

* adding delay to ui tests
  • Loading branch information
mattleibow authored and PureWeen committed Jan 30, 2019
1 parent b4d12ab commit 0dd61b7
Show file tree
Hide file tree
Showing 27 changed files with 1,406 additions and 828 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ async Task Kinetic(BoxView box)
public void DoesNotCrash()
{
RunningApp.Tap(q => q.Marked("Animate"));
RunningApp.WaitForElement(q => q.Marked("Success"));
RunningApp.WaitForElement(q => q.Marked("Success"), timeout:TimeSpan.FromSeconds(25));
}
#endif
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ public void Bugzilla41415Test()
RunningApp.Tap(q => q.Marked(ButtonText));
RunningApp.WaitForElement(q => q.Marked("x: 100"));
RunningApp.WaitForElement(q => q.Marked("y: 100"));
RunningApp.WaitForElement(q => q.Marked("z: True"));
RunningApp.WaitForElement(q => q.Marked("z: True"), timeout: TimeSpan.FromSeconds(25));
RunningApp.WaitForElement(q => q.Marked("a: True"));
RunningApp.Tap(q => q.Marked(ButtonText));
RunningApp.WaitForElement(q => q.Marked("x: 200"));
RunningApp.WaitForElement(q => q.Marked("y: 100"));
RunningApp.WaitForElement(q => q.Marked("z: True"));
RunningApp.WaitForElement(q => q.Marked("z: True"), timeout: TimeSpan.FromSeconds(25));
RunningApp.WaitForElement(q => q.Marked("a: False"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public void AnimationCancel()
{
RunningApp.WaitForElement(ButtonId);
RunningApp.DoubleTap(ButtonId);
RunningApp.WaitForElement(Success);
RunningApp.WaitForElement(Success, timeout: TimeSpan.FromSeconds(25));
}
#endif
}
Expand Down
4 changes: 4 additions & 0 deletions Xamarin.Forms.Controls/CoreGallery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,10 @@ public override string ToString()
new GalleryPageFactory(() => new ContextActionsGallery (tableView: true), "ContextActions Table Gallery"),
new GalleryPageFactory(() => new CoreBoxViewGalleryPage(), "BoxView Gallery"),
new GalleryPageFactory(() => new ButtonCoreGalleryPage(), "Button Gallery"),
new GalleryPageFactory(() => new ButtonLayoutGalleryPage(), "Button Layout Gallery"),
new GalleryPageFactory(() => new ButtonLayoutGalleryPage(VisualMarker.Material), "Button Layout Gallery (Material)"),
new GalleryPageFactory(() => new ButtonBorderBackgroundGalleryPage(), "Button Border & Background Gallery"),
new GalleryPageFactory(() => new ButtonBorderBackgroundGalleryPage(VisualMarker.Material), "Button Border & Background Gallery (Material)"),
new GalleryPageFactory(() => new DatePickerCoreGalleryPage(), "DatePicker Gallery"),
new GalleryPageFactory(() => new EditorCoreGalleryPage(), "Editor Gallery"),
new GalleryPageFactory(() => new FrameCoreGalleryPage(), "Frame Gallery"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Xamarin.Forms.Controls"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
x:Class="Xamarin.Forms.Controls.ButtonBorderBackgroundGalleryPage"
Title="Button Border &amp; Background">

<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="FontSize" Value="12" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<ScrollView>
<StackLayout Padding="20" Spacing="10">

<Label Text="Base:" Margin="0,5,0,0" FontAttributes="Bold" />

<Label Text="Defaults:" Margin="0,0,0,-5" />
<StackLayout Padding="0" Spacing="5">
<Button Text="Button Text" />
</StackLayout>

<Label Text="Modified:" Margin="0,5,0,0" FontAttributes="Bold" />

<Label Text="Backgrounds: (various background colors)" Margin="0,0,0,-5" />
<StackLayout Padding="0" Spacing="5">
<Button Text="Transparent" BackgroundColor="Transparent" />
<Button Text="Red" BackgroundColor="Red" />
<Button Text="Black" BackgroundColor="Black" />
<Button Text="Red, Image" BackgroundColor="Red" Image="bank.png" />
</StackLayout>

<Label Text="Corners: (various corner radii)" Margin="0,0,0,-5" />
<StackLayout Padding="0" Spacing="5">
<Button Text="Radius: 0" CornerRadius="0" />
<Button Text="Radius: 5" CornerRadius="5" />
<Button Text="Radius: 15" CornerRadius="15" />
<Button Text="Radius: 15, Image" CornerRadius="15" Image="bank.png" />
<Button Text="Radius: 15, Width: 5" CornerRadius="15" BorderWidth="5" BorderColor="Red" />
</StackLayout>

<Label Text="Border Widths: (various border widths, red color)" Margin="0,0,0,-5" />
<StackLayout Padding="0" Spacing="5">
<Button Text="Width: 5, Color: &lt;none&gt;" BorderWidth="5" />
<Button Text="Width: 0" BorderWidth="0" BorderColor="Red" />
<Button Text="Width: 1" BorderWidth="1" BorderColor="Red" />
<Button Text="Width: 15" BorderWidth="15" BorderColor="Red" />
<Button Text="Width: 15, Image" BorderWidth="15" BorderColor="Red" Image="bank.png" />
</StackLayout>

<Label Text="Border Colors: (various border colors, width 5)" Margin="0,0,0,-5" />
<StackLayout Padding="0" Spacing="5">
<Button Text="Red, Width: &lt;none&gt;" BorderColor="Red" />
<Button Text="Transparent" BorderColor="Transparent" BorderWidth="5" />
<Button Text="Red" BorderColor="Red" BorderWidth="5" />
<Button Text="Black" BorderColor="Black" BorderWidth="5" />
<Button Text="Red, Image" BorderColor="Red" BorderWidth="5" Image="bank.png" />
</StackLayout>

<Label Text="Circles:" Margin="0,5,0,0" FontAttributes="Bold" />

<Label Text="Defaults: (no padding/shadow)" Margin="0,0,0,-5" />
<StackLayout Padding="0" Spacing="5">
<StackLayout Padding="0" Spacing="5" Orientation="Horizontal">
<Button Text="Square" WidthRequest="100" HeightRequest="100" />
<Button Text="Circle" CornerRadius="50" WidthRequest="100" HeightRequest="100" />
</StackLayout>
<StackLayout Padding="0" Spacing="5" Orientation="Horizontal">
<Button Text="Red Square" BackgroundColor="Red" WidthRequest="100" HeightRequest="100" />
<Button Text="Red Circle" BackgroundColor="Red" CornerRadius="50" WidthRequest="100" HeightRequest="100" />
</StackLayout>
<StackLayout Padding="0" Spacing="5" Orientation="Horizontal">
<Button Text="Image Square" BackgroundColor="Red" Image="bank.png" WidthRequest="100" HeightRequest="100" />
<Button Text="Image Circle" BackgroundColor="Red" CornerRadius="50" Image="bank.png" WidthRequest="100" HeightRequest="100" />
</StackLayout>
</StackLayout>

<Label Text="Specifics: (with padding/shadow)" Margin="0,0,0,-5" />
<StackLayout Padding="0" Spacing="5">
<StackLayout Padding="0" Spacing="5" Orientation="Horizontal">
<Button Text="Square" WidthRequest="100" HeightRequest="100" android:Button.UseDefaultPadding="true" android:Button.UseDefaultShadow="true" />
<Button Text="Circle" CornerRadius="50" WidthRequest="100" HeightRequest="100" android:Button.UseDefaultPadding="true" android:Button.UseDefaultShadow="true" />
</StackLayout>
<StackLayout Padding="0" Spacing="5" Orientation="Horizontal">
<Button Text="Red Square" BackgroundColor="Red" WidthRequest="100" HeightRequest="100" android:Button.UseDefaultPadding="true" android:Button.UseDefaultShadow="true" />
<Button Text="Red Circle" BackgroundColor="Red" CornerRadius="50" WidthRequest="100" HeightRequest="100" android:Button.UseDefaultPadding="true" android:Button.UseDefaultShadow="true" />
</StackLayout>
<StackLayout Padding="0" Spacing="5" Orientation="Horizontal">
<Button Text="Image Square" BackgroundColor="Red" Image="bank.png" WidthRequest="100" HeightRequest="100" android:Button.UseDefaultPadding="true" android:Button.UseDefaultShadow="true" />
<Button Text="Image Circle" BackgroundColor="Red" CornerRadius="50" Image="bank.png" WidthRequest="100" HeightRequest="100" android:Button.UseDefaultPadding="true" android:Button.UseDefaultShadow="true" />
</StackLayout>
</StackLayout>

</StackLayout>
</ScrollView>

</ContentPage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using Xamarin.Forms.Xaml;

namespace Xamarin.Forms.Controls
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ButtonBorderBackgroundGalleryPage : ContentPage
{
public ButtonBorderBackgroundGalleryPage()
: this(VisualMarker.MatchParent)
{
}

public ButtonBorderBackgroundGalleryPage(IVisual visual)
{
InitializeComponent();
Visual = visual;

// buttons are transparent on default iOS, so we have to give them something
if (Device.RuntimePlatform == Device.iOS)
{
if (Visual != VisualMarker.Material)
{
SetBackground(Content);

void SetBackground(View view)
{
if (view is Button button && !button.IsSet(Button.BackgroundColorProperty))
view.BackgroundColor = Color.LightGray;

if (view is Layout layout)
{
foreach (var child in layout.Children)
{
if (child is View childView)
SetBackground(childView);
}
}
}
}
}
}

void HandleChecks_Clicked(object sender, System.EventArgs e)
{
var thisButton = sender as Button;
var layout = thisButton.Parent as Layout;
foreach (var child in layout.Children)
{
var button = child as Button;

Console.WriteLine($"{button.Text} => {button.Bounds}");
}
}
}
}
129 changes: 129 additions & 0 deletions Xamarin.Forms.Controls/GalleryPages/ButtonLayoutGalleryPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Xamarin.Forms.Controls"
x:Class="Xamarin.Forms.Controls.ButtonLayoutGalleryPage"
Title="Button Layout">

<ContentPage.Resources>
<ResourceDictionary>
<local:ThicknessConverter x:Key="ThicknessConverter" />
<Style TargetType="Label">
<Setter Property="FontSize" Value="12" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<ScrollView>
<StackLayout Padding="20" Spacing="10">

<Label Text="Buttons:" Margin="0,5,0,0" FontAttributes="Bold" />

<Label Text="Defaults:" Margin="0,0,0,-5" />
<StackLayout Orientation="Vertical" Padding="0" Spacing="5">
<Button />
<Button Text="Some Text" />
<Button Image="bank.png" />
<Button Text="Some Text" Image="bank.png" />
</StackLayout>

<Label Text="Autosized:" Margin="0,0,0,-5" />
<StackLayout Orientation="Horizontal" Padding="0" Spacing="5">
<Button x:Name="autosizedButton" Text="{Binding ButtonText}" Image="{Binding ButtonImage}" Padding="{Binding ButtonPadding}" ContentLayout="{Binding ButtonImageLayout}" FontSize="{Binding ButtonFontSize}" />
</StackLayout>

<Label Text="Explicit Size:" Margin="0,0,0,-5" />
<Grid Padding="0" RowSpacing="5" ColumnSpacing="5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Button
x:Name="explicitButton" Text="{Binding ButtonText}" Image="{Binding ButtonImage}" Padding="{Binding ButtonPadding}" ContentLayout="{Binding ButtonImageLayout}" FontSize="{Binding ButtonFontSize}"
WidthRequest="120" HeightRequest="60" HorizontalOptions="Start" VerticalOptions="Start" />
<Button
x:Name="explicitWidthButton" Text="{Binding ButtonText}" Image="{Binding ButtonImage}" Padding="{Binding ButtonPadding}" ContentLayout="{Binding ButtonImageLayout}" FontSize="{Binding ButtonFontSize}"
Grid.Column="1" Grid.RowSpan="2" WidthRequest="120" HorizontalOptions="Start" VerticalOptions="Start" />
<Button
x:Name="explicitHeightButton" Text="{Binding ButtonText}" Image="{Binding ButtonImage}" Padding="{Binding ButtonPadding}" ContentLayout="{Binding ButtonImageLayout}" FontSize="{Binding ButtonFontSize}"
Grid.Row="1" Grid.ColumnSpan="2" HeightRequest="60" HorizontalOptions="Start" VerticalOptions="Start" />
</Grid>

<Label Text="Stretched:" Margin="0,0,0,-5" />
<StackLayout Orientation="Vertical" Padding="0" Spacing="5">
<Button x:Name="stretchedButton" Text="{Binding ButtonText}" Image="{Binding ButtonImage}" Padding="{Binding ButtonPadding}" ContentLayout="{Binding ButtonImageLayout}" FontSize="{Binding ButtonFontSize}" />
</StackLayout>

<Label Text="Options:" Margin="0,5,0,0" FontAttributes="Bold" />

<StackLayout Orientation="Horizontal" Padding="0" Spacing="5" HorizontalOptions="FillAndExpand">

<StackLayout Orientation="Vertical" Padding="0" Spacing="0" HorizontalOptions="FillAndExpand">
<Label Text="Text:" />
<Entry Text="{Binding ButtonText}" HorizontalOptions="FillAndExpand" />
</StackLayout>

<StackLayout Orientation="Vertical" Padding="0" Spacing="0">
<Label Text="Text Size:" />
<StackLayout Orientation="Horizontal" Padding="0" Spacing="5">
<Stepper Minimum="-1" Maximum="100" Value="{Binding ButtonFontSize}" VerticalOptions="Center" HorizontalOptions="FillAndExpand" />
<Label Text="{Binding ButtonFontSize}" VerticalOptions="Center" />
</StackLayout>
</StackLayout>

</StackLayout>

<StackLayout Orientation="Horizontal" Padding="0" Spacing="5" HorizontalOptions="FillAndExpand">

<StackLayout Orientation="Vertical" Padding="0" Spacing="0" HorizontalOptions="FillAndExpand">
<Label Text="Image:" />
<Picker ItemsSource="{Binding ButtonImages}" SelectedItem="{Binding ButtonImage}" HorizontalOptions="FillAndExpand" />
</StackLayout>

</StackLayout>

<StackLayout Orientation="Horizontal" Padding="0" Spacing="5" HorizontalOptions="FillAndExpand">

<StackLayout Orientation="Vertical" Padding="0" Spacing="0" HorizontalOptions="FillAndExpand">
<Label Text="Content Position:" />
<Picker ItemsSource="{Binding ButtonImagePositions}" SelectedItem="{Binding ButtonImagePosition}" HorizontalOptions="FillAndExpand" />
</StackLayout>

<StackLayout Orientation="Vertical" Padding="0" Spacing="0">
<Label Text="Content Spacing:" />
<StackLayout Orientation="Horizontal" Padding="0" Spacing="5">
<Stepper Minimum="-100" Maximum="100" Value="{Binding ButtonImageSpacing}" VerticalOptions="Center" HorizontalOptions="FillAndExpand" />
<Label Text="{Binding ButtonImageSpacing}" VerticalOptions="Center" />
</StackLayout>
</StackLayout>

</StackLayout>

<StackLayout Orientation="Horizontal" Padding="0" Spacing="5" HorizontalOptions="FillAndExpand">

<StackLayout Orientation="Vertical" Padding="0" Spacing="0" HorizontalOptions="FillAndExpand">
<Label Text="Padding:" />
<Entry Text="{Binding ButtonPadding, Converter={StaticResource ThicknessConverter}, Mode=OneWayToSource, TargetNullValue='0, 0, 0, 0'}" HorizontalOptions="FillAndExpand" />
</StackLayout>

<StackLayout Orientation="Vertical" Padding="0" Spacing="0">
<Label Text="Border Width:" />
<StackLayout Orientation="Horizontal" Padding="0" Spacing="5">
<Stepper Minimum="-1" Maximum="100" Value="{Binding ButtonBorderWidth}" VerticalOptions="Center" HorizontalOptions="FillAndExpand" />
<Label Text="{Binding ButtonBorderWidth}" VerticalOptions="Center" />
</StackLayout>
</StackLayout>

</StackLayout>

<Label Text="Use Default Shadow/Padding: (Android only)" Margin="0,0,0,-5" />
<Picker ItemsSource="{Binding ButtonFlags}" SelectedIndexChanged="OnButtonDefaultShadowChanged" />

</StackLayout>
</ScrollView>

</ContentPage>
Loading

0 comments on commit 0dd61b7

Please sign in to comment.