Browse Source

Merge pull request #4055 from jp2masa/textblock-maxlines

Added MaxLines property to TextBlock
Benedikt Stebner 5 years ago
parent
commit
e87bedd21f

+ 21 - 1
src/Avalonia.Controls/TextBlock.cs

@@ -70,6 +70,14 @@ namespace Avalonia.Controls
                 Brushes.Black,
                 inherits: true);
 
+        /// <summary>
+        /// Defines the <see cref="MaxLines"/> property.
+        /// </summary>
+        public static readonly StyledProperty<int> MaxLinesProperty =
+            AvaloniaProperty.Register<TextBlock, int>(
+                nameof(MaxLines),
+                validate: IsValidMaxLines);
+
         /// <summary>
         /// Defines the <see cref="Text"/> property.
         /// </summary>
@@ -222,6 +230,15 @@ namespace Avalonia.Controls
             set { SetValue(ForegroundProperty, value); }
         }
 
+        /// <summary>
+        /// Gets or sets the maximum number of text lines.
+        /// </summary>
+        public int MaxLines
+        {
+            get => GetValue(MaxLinesProperty);
+            set => SetValue(MaxLinesProperty, value);
+        }
+
         /// <summary>
         /// Gets or sets the control's text wrapping mode.
         /// </summary>
@@ -404,7 +421,8 @@ namespace Avalonia.Controls
                 TextTrimming,
                 TextDecorations,
                 constraint.Width,
-                constraint.Height);
+                constraint.Height,
+                MaxLines);
         }
 
         /// <summary>
@@ -451,5 +469,7 @@ namespace Avalonia.Controls
 
             InvalidateMeasure();
         }
+
+        private static bool IsValidMaxLines(int maxLines) => maxLines >= 0;
     }
 }

+ 12 - 2
src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs

@@ -32,6 +32,7 @@ namespace Avalonia.Media.TextFormatting
         /// <param name="textDecorations">The text decorations.</param>
         /// <param name="maxWidth">The maximum width.</param>
         /// <param name="maxHeight">The maximum height.</param>
+        /// <param name="maxLines">The maximum number of text lines.</param>
         /// <param name="textStyleOverrides">The text style overrides.</param>
         public TextLayout(
             string text,
@@ -44,6 +45,7 @@ namespace Avalonia.Media.TextFormatting
             TextDecorationCollection textDecorations = null,
             double maxWidth = double.PositiveInfinity,
             double maxHeight = double.PositiveInfinity,
+            int maxLines = 0,
             IReadOnlyList<TextStyleRun> textStyleOverrides = null)
         {
             _text = string.IsNullOrEmpty(text) ?
@@ -59,6 +61,8 @@ namespace Avalonia.Media.TextFormatting
 
             MaxHeight = maxHeight;
 
+            MaxLines = maxLines;
+
             UpdateLayout();
         }
 
@@ -73,6 +77,12 @@ namespace Avalonia.Media.TextFormatting
         /// </summary>
         public double MaxHeight { get; }
 
+
+        /// <summary>
+        /// Gets the maximum number of text lines.
+        /// </summary>
+        public double MaxLines { get; }
+
         /// <summary>
         /// Gets the text lines.
         /// </summary>
@@ -192,7 +202,7 @@ namespace Avalonia.Media.TextFormatting
 
                 var currentPosition = 0;
 
-                while (currentPosition < _text.Length)
+                while (currentPosition < _text.Length && (MaxLines == 0 || textLines.Count < MaxLines))
                 {
                     int length;
 
@@ -222,7 +232,7 @@ namespace Avalonia.Media.TextFormatting
 
                     var remainingLength = length;
 
-                    while (remainingLength > 0)
+                    while (remainingLength > 0 && (MaxLines == 0 || textLines.Count < MaxLines))
                     {
                         var textSlice = _text.AsSlice(currentPosition, remainingLength);
 

+ 20 - 0
tests/Avalonia.Skia.UnitTests/TextLayoutTests.cs

@@ -506,6 +506,26 @@ namespace Avalonia.Skia.UnitTests
             }
         }
 
+        [InlineData("0123456789\r\n0123456789\r\n0123456789", 0, 3)]
+        [InlineData("0123456789\r\n0123456789\r\n0123456789", 1, 1)]
+        [InlineData("0123456789\r\n0123456789\r\n0123456789", 4, 3)]
+        [Theory]
+        public void Should_Not_Exceed_MaxLines(string text, int maxLines, int expectedLines)
+        {
+            using (Start())
+            {
+                var layout = new TextLayout(
+                    text,
+                    Typeface.Default,
+                    12,
+                    Brushes.Black,
+                    maxWidth: 50,
+                    maxLines: maxLines);
+
+                Assert.Equal(expectedLines, layout.TextLines.Count);
+            }
+        }
+
         private const string Text = "日本でTest一番読まれている英字新聞・ジャパンタイムズが発信する国内外ニュースと、様々なジャンルの特集記事。";
 
         [Fact(Skip= "Only used for profiling.")]