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 rookiejava committed Oct 27, 2020
1 parent 3ea1828 commit 9c46f7b
Show file tree
Hide file tree
Showing 9 changed files with 256 additions and 56 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;
}
}
}
}
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
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;
}
}
27 changes: 19 additions & 8 deletions Xamarin.Forms.Platform.UAP/FormsButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ void UpdateBorderRadius()
{
var radius = BorderRadius == -1 ? 0 : BorderRadius;
var cornerRadius = new Windows.UI.Xaml.CornerRadius(radius);
if (_contentPresenter != null)
_contentPresenter.CornerRadius = cornerRadius;
if(_rootGrid != null)
if (_contentPresenter != null)
_contentPresenter.CornerRadius = cornerRadius;

if (_rootGrid != null)
_rootGrid.CornerRadius = cornerRadius;
}

Expand All @@ -90,21 +90,32 @@ public void UpdateCharacterSpacing(int characterSpacing)
if (_contentPresenter != null)
_contentPresenter.CharacterSpacing = CharacterSpacing;

if(Content is TextBlock tb)
var textBlock = GetTextBlock(Content);

if (textBlock != null)
textBlock.CharacterSpacing = CharacterSpacing;

}

public TextBlock GetTextBlock(object content)
{
if (content is TextBlock tb)
{
tb.CharacterSpacing = CharacterSpacing;
return tb;
}

if (Content is StackPanel sp)
if (content is StackPanel sp)
{
foreach (var item in sp.Children)
{
if (item is TextBlock textBlock)
{
textBlock.CharacterSpacing = CharacterSpacing;
return textBlock;
}
}
}

return null;
}
}
}
Loading

0 comments on commit 9c46f7b

Please sign in to comment.