Skip to content

Commit

Permalink
xamarinGH-3106 Implemented LineBreakMode to Button (xamarin#11147)
Browse files Browse the repository at this point in the history
* Added LineBreakMode in the Button and TestAttributes

* Added LineBreakMode implementation on Android platform

* Added Issue into the Controls project

* Removed unused method

* Added UWP support for LineBreakMode

* Implemented LineBreakMode on iOS

* Update Xamarin.Forms.Core/Button.cs

Co-authored-by: Stephane Delcroix <stephane@delcroix.org>

Co-authored-by: Stephane Delcroix <stephane@delcroix.org>
Co-authored-by: Rui Marinho <me@ruimarinho.net>

fixes xamarin#3106
  • Loading branch information
pictos authored and Axemasta committed Apr 5, 2021
1 parent dbe1fbb commit 76ecd46
Show file tree
Hide file tree
Showing 11 changed files with 273 additions and 84 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;

namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 3106, "Added LineBreakMode on Button")]
public class Issue3106 : TestContentPage
{
int count;
const string content = "Welcome to Xamarin.Forms! Welcome to Xamarin.Forms! Welcome to Xamarin.Forms! Welcome to Xamarin.Forms!";
const string content2 = "Now users can set a line break mode to texts on Button, the default value doesn't affect any user.";

Button mainButton;
Button materialButton;
Label lineBreakModeType;

protected override void Init()
{
mainButton = new Button
{
Text = content,
LineBreakMode = LineBreakMode.WordWrap,
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.CenterAndExpand
};
mainButton.Clicked += MainButton_Clicked;

materialButton = new Button
{
Text = content,
LineBreakMode = LineBreakMode.WordWrap,
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.CenterAndExpand,
Visual = VisualMarker.Material
};
materialButton.Clicked += MaterialButton_Clicked;

lineBreakModeType = new Label
{
Text = LineBreakMode.WordWrap.ToString(),
VerticalOptions = LayoutOptions.EndAndExpand,
LineBreakMode = LineBreakMode.WordWrap,
};
var layout = new StackLayout
{
Children =
{
new Label
{
Text = "Press the first button to change the LineBreakMode. Press the second button to change the text",
VerticalOptions = LayoutOptions.StartAndExpand
},
mainButton,
materialButton,
lineBreakModeType
}
};

Content = layout;
}

void MaterialButton_Clicked(object sender, EventArgs e)
{
if (materialButton.Text.Equals(content2))
materialButton.Text = mainButton.Text = content;
else
materialButton.Text = mainButton.Text = content2;
}

void MainButton_Clicked(object sender, EventArgs e)
{
materialButton.LineBreakMode = mainButton.LineBreakMode = SelectLineBreakMode();
lineBreakModeType.Text = mainButton.LineBreakMode.ToString();
}

LineBreakMode SelectLineBreakMode()
{
count++;
switch (count)
{
case 1:
return LineBreakMode.CharacterWrap;
case 2:
return LineBreakMode.HeadTruncation;
case 3:
return LineBreakMode.MiddleTruncation;
case 4:
return LineBreakMode.NoWrap;
case 5:
return LineBreakMode.TailTruncation;
default:
count = 0;
return LineBreakMode.WordWrap;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,34 +51,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue10744.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue11090.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue10909.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue11931.xaml.cs">
<DependentUpon>Issue11931.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue11709.xaml.cs">
<DependentUpon>Issue11709.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue11794.xaml.cs">
<DependentUpon>Issue11794.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue11769.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12079.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12060.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12344.xaml.cs">
<DependentUpon>Issue12344.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue12246.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12429.xaml.cs">
<DependentUpon>Issue12429.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue12652.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12714.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2447.xaml.cs">
<DependentUpon>Issue2447.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue2448.xaml.cs">
<DependentUpon>Issue2448.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue3106.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8613.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue8814.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue13203.cs" />
Expand Down
9 changes: 9 additions & 0 deletions Xamarin.Forms.Core/Button.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ public class Button : View, IFontElement, ITextElement, IBorderElement, IButtonC

public static readonly BindableProperty PaddingProperty = PaddingElement.PaddingProperty;

public static readonly BindableProperty LineBreakModeProperty = BindableProperty.Create(nameof(LineBreakMode), typeof(LineBreakMode), typeof(Button), LineBreakMode.NoWrap,
propertyChanged: (bindable, oldvalue, newvalue) => ((Button)bindable).InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged));

public Thickness Padding
{
get { return (Thickness)GetValue(PaddingElement.PaddingProperty); }
Expand All @@ -70,6 +73,12 @@ Thickness IPaddingElement.PaddingDefaultValueCreator()
return default(Thickness);
}

public LineBreakMode LineBreakMode
{
get { return (LineBreakMode)GetValue(LineBreakModeProperty); }
set { SetValue(LineBreakModeProperty, value); }
}

void IPaddingElement.OnPaddingPropertyChanged(Thickness oldValue, Thickness newValue)
{
InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
Expand Down
3 changes: 2 additions & 1 deletion Xamarin.Forms.CustomAttributes/TestAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ public enum Button
BorderRadius,
Image,
Padding,
Pressed
Pressed,
LineBreakMode
}

public enum VisualElement
Expand Down
16 changes: 16 additions & 0 deletions Xamarin.Forms.Platform.Android/ButtonLayoutManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using AButton = Android.Widget.Button;
using ARect = Android.Graphics.Rect;
using AView = Android.Views.View;
using AButton = Android.Widget.Button;
using Android.Text;

namespace Xamarin.Forms.Platform.Android
{
Expand Down Expand Up @@ -193,6 +195,7 @@ public void Update()
UpdateImage();

UpdatePadding();
UpdateLineBreakMode();
}

void OnElementChanged(object sender, VisualElementChangedEventArgs e)
Expand Down Expand Up @@ -225,6 +228,8 @@ void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
UpdateTextAndImage();
else if (e.PropertyName == Button.BorderWidthProperty.PropertyName && _borderAdjustsPadding)
_element.InvalidateMeasureNonVirtual(InvalidationTrigger.MeasureChanged);
else if (e.PropertyName == Button.LineBreakModeProperty.PropertyName)
UpdateLineBreakMode();
}

void UpdatePadding()
Expand Down Expand Up @@ -362,5 +367,16 @@ void UpdateImage()
});
}
}

void UpdateLineBreakMode()
{
AButton view = View;

if (view == null || _element == null || _renderer?.View == null)
return;

view.SetLineBreakMode(_element);
_renderer.View.SetAllCaps(_element.TextTransform == TextTransform.Default);
}
}
}
23 changes: 11 additions & 12 deletions Xamarin.Forms.Platform.Android/Extensions/TextViewExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,26 @@ public static void SetMaxLines(this TextView textView, Label label)
textView.SetMaxLines(maxLines);
}

static void SetMaxLines(this TextView textView, Label label, int lines)
public static void SetLineBreakMode(this TextView textView, Label label)
{
// If the Label's MaxLines has been explicitly set, we should not set it here
if (label.MaxLines != (int)Label.MaxLinesProperty.DefaultValue)
{
return;
}

textView.SetMaxLines(lines);
var maxLines = SetLineBreak(textView, label.LineBreakMode);
textView.SetMaxLines(maxLines);
}

public static void SetLineBreakMode(this TextView textView, Label label)
{
var lineBreakMode = label.LineBreakMode;
public static void SetLineBreakMode(this TextView textView, Button button) =>
SetLineBreak(textView, button.LineBreakMode);


public static int SetLineBreak( TextView textView, LineBreakMode lineBreakMode)
{
int maxLines = Int32.MaxValue;
bool singleLine = false;

switch (lineBreakMode)
{
case LineBreakMode.NoWrap:
maxLines = 1;
singleLine = true;
textView.Ellipsize = null;
break;
case LineBreakMode.WordWrap:
Expand All @@ -59,6 +57,7 @@ public static void SetLineBreakMode(this TextView textView, Label label)
break;
case LineBreakMode.TailTruncation:
maxLines = 1;
singleLine = true;
textView.Ellipsize = TextUtils.TruncateAt.End;
break;
case LineBreakMode.MiddleTruncation:
Expand All @@ -69,7 +68,7 @@ public static void SetLineBreakMode(this TextView textView, Label label)
}

textView.SetSingleLine(singleLine);
textView.SetMaxLines(label, maxLines);
return maxLines;
}

public static void RecalculateSpanPositions(this TextView textView, Label element, SpannableString spannableString, SizeRequest finalSize)
Expand Down
25 changes: 22 additions & 3 deletions Xamarin.Forms.Platform.UAP/ButtonRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
using WImage = Windows.UI.Xaml.Controls.Image;
using WStretch = Windows.UI.Xaml.Media.Stretch;
using WThickness = Windows.UI.Xaml.Thickness;
using System;
using Xamarin.Forms.Platform.UAP.Extensions;
using System.Linq;

namespace Xamarin.Forms.Platform.UWP
{
public class ButtonRenderer : ViewRenderer<Button, FormsButton>
{
bool _fontApplied;
TextBlock _textBlock = null;

FormsButton _button;
PointerEventHandler _pointerPressedHandler;
Expand Down Expand Up @@ -74,6 +78,15 @@ protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
void ButtonOnLoaded(object o, RoutedEventArgs routedEventArgs)
{
WireUpFormsVsm();
UpdateLineBreakMode();
}


void UpdateLineBreakMode()
{
_textBlock = Control.GetTextBlock(Control.Content);

_textBlock?.UpdateLineBreakMode(Element.LineBreakMode);
}

void WireUpFormsVsm()
Expand Down Expand Up @@ -124,6 +137,8 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE
{
UpdatePadding();
}
else if (e.PropertyName == Button.LineBreakModeProperty.PropertyName)
UpdateLineBreakMode();
}

protected override void UpdateBackgroundColor()
Expand Down Expand Up @@ -188,8 +203,9 @@ async void UpdateContent()
// No image, just the text
if (elementImage == null)
{
Control.Content = text;
Control.Content = new TextBlock { Text = text };
Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
UpdateLineBreakMode();
return;
}

Expand All @@ -208,7 +224,8 @@ async void UpdateContent()
// when this happens, we want to resize the button
if (elementImage is BitmapImage bmp)
{
bmp.ImageOpened += (sender, args) => {
bmp.ImageOpened += (sender, args) =>
{
var actualSize = bmp.GetImageSourceSize();
image.Width = actualSize.Width;
image.Height = actualSize.Height;
Expand All @@ -227,12 +244,14 @@ async void UpdateContent()
// Both image and text, so we need to build a container for them
Control.Content = CreateContentContainer(Element.ContentLayout, image, text);
Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
UpdateLineBreakMode();
}

static StackPanel CreateContentContainer(Button.ButtonContentLayout layout, WImage image, string text)
{
var container = new StackPanel();
var textBlock = new TextBlock {
var textBlock = new TextBlock
{
Text = text,
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center
Expand Down
50 changes: 50 additions & 0 deletions Xamarin.Forms.Platform.UAP/Extensions/TextBlockExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Xamarin.Forms.Platform.UAP.Extensions
{
internal static class TextBlockExtensions
{
public static void UpdateLineBreakMode(this TextBlock textBlock, LineBreakMode lineBreakMode)
{
if (textBlock == null)
return;

switch (lineBreakMode)
{
case LineBreakMode.NoWrap:
textBlock.TextTrimming = TextTrimming.Clip;
textBlock.TextWrapping = TextWrapping.NoWrap;
break;
case LineBreakMode.WordWrap:
textBlock.TextTrimming = TextTrimming.None;
textBlock.TextWrapping = TextWrapping.Wrap;
break;
case LineBreakMode.CharacterWrap:
textBlock.TextTrimming = TextTrimming.WordEllipsis;
textBlock.TextWrapping = TextWrapping.Wrap;
break;
case LineBreakMode.HeadTruncation:
// TODO: This truncates at the end.
textBlock.TextTrimming = TextTrimming.WordEllipsis;
DetermineTruncatedTextWrapping(textBlock);
break;
case LineBreakMode.TailTruncation:
textBlock.TextTrimming = TextTrimming.CharacterEllipsis;
DetermineTruncatedTextWrapping(textBlock);
break;
case LineBreakMode.MiddleTruncation:
// TODO: This truncates at the end.
textBlock.TextTrimming = TextTrimming.WordEllipsis;
DetermineTruncatedTextWrapping(textBlock);
break;
default:
throw new ArgumentOutOfRangeException();
}
}

static void DetermineTruncatedTextWrapping(TextBlock textBlock) =>
textBlock.TextWrapping = textBlock.MaxLines > 1 ? TextWrapping.Wrap : TextWrapping.NoWrap;
}
}
Loading

0 comments on commit 76ecd46

Please sign in to comment.