mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-22 00:46:48 +08:00
feat(TextArea): implement dynamic height adjustment with min/max constraints
This commit is contained in:
@@ -348,20 +348,20 @@
|
||||
Title="With character counting"
|
||||
Description="Show character counting.">
|
||||
<StackPanel Orientation="Vertical" Spacing="10" Margin="0, 0, 20, 0">
|
||||
<atom:LineEdit IsShowCount="True" MaxLength="20" />
|
||||
<!-- <atom:LineEdit IsShowCount="True" MaxLength="20" /> -->
|
||||
<atom:TextArea IsShowCount="True" MaxLength="100" PlaceholderText="can resize" IsResizable="True" />
|
||||
<atom:TextArea IsShowCount="True" MaxLength="100" PlaceholderText="disable resize" Height="120"
|
||||
IsResizable="True" />
|
||||
</StackPanel>
|
||||
</gallery:ShowCaseItem>
|
||||
|
||||
<gallery:ShowCaseItem
|
||||
Title="Status"
|
||||
Description="Add status to TextArea with status, which could be error or warning.">
|
||||
<StackPanel Orientation="Vertical" Spacing="10" Margin="0, 0, 20, 0">
|
||||
<atom:TextArea IsShowCount="True" MaxLength="100" PlaceholderText="Error" IsResizable="True" Status="Error" />
|
||||
<atom:TextArea IsShowCount="True" MaxLength="100" PlaceholderText="Warning" IsResizable="True" Status="Warning"/>
|
||||
<!-- <atom:TextArea IsShowCount="True" MaxLength="100" PlaceholderText="disable resize" Height="120" -->
|
||||
<!-- IsResizable="False" /> -->
|
||||
</StackPanel>
|
||||
</gallery:ShowCaseItem>
|
||||
<!-- -->
|
||||
<!-- <gallery:ShowCaseItem -->
|
||||
<!-- Title="Status" -->
|
||||
<!-- Description="Add status to TextArea with status, which could be error or warning."> -->
|
||||
<!-- <StackPanel Orientation="Vertical" Spacing="10" Margin="0, 0, 20, 0"> -->
|
||||
<!-- <atom:TextArea IsShowCount="True" MaxLength="100" PlaceholderText="Error" IsResizable="True" Status="Error" /> -->
|
||||
<!-- <atom:TextArea IsShowCount="True" MaxLength="100" PlaceholderText="Warning" IsResizable="True" Status="Warning"/> -->
|
||||
<!-- </StackPanel> -->
|
||||
<!-- </gallery:ShowCaseItem> -->
|
||||
</gallery:ShowCasePanel>
|
||||
</UserControl>
|
||||
|
||||
@@ -16,8 +16,9 @@ internal class ResizeHandle : TemplatedControl
|
||||
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
||||
{
|
||||
base.OnPointerPressed(e);
|
||||
e.Handled = true;
|
||||
_lastPoint = e.GetPosition(TopLevel.GetTopLevel(this));
|
||||
e.Handled = true;
|
||||
_lastPoint = e.GetPosition(TopLevel.GetTopLevel(this));
|
||||
e.Pointer.Capture(this);
|
||||
}
|
||||
|
||||
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||
@@ -26,9 +27,10 @@ internal class ResizeHandle : TemplatedControl
|
||||
if (_lastPoint.HasValue)
|
||||
{
|
||||
Owner?.NotifyResizeCompleted();
|
||||
e.Handled = true;
|
||||
_lastPoint = null;
|
||||
_dragging = false;
|
||||
e.Handled = true;
|
||||
_lastPoint = null;
|
||||
_dragging = false;
|
||||
e.Pointer.Capture(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -185,6 +185,8 @@ public class TextArea : AvaloniaTextBox,
|
||||
private ResizeHandle? _resizeHandle;
|
||||
private CompositeDisposable? _contentRightAddOnBindings;
|
||||
private double? _originHeight; // 拖动改变高度的初始值
|
||||
private double _minResizeHeight; // 拖动改变高度时允许的最小 TextArea.Height
|
||||
private double _maxResizeHeight; // 拖动改变高度时允许的最大 TextArea.Height
|
||||
|
||||
static TextArea()
|
||||
{
|
||||
@@ -323,14 +325,8 @@ public class TextArea : AvaloniaTextBox,
|
||||
{
|
||||
if (Lines > 0 && double.IsNaN(Height))
|
||||
{
|
||||
var height = double.NaN;
|
||||
Lines = Math.Max(Lines, MinLines);
|
||||
var fontSize = FontSize;
|
||||
var typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
|
||||
var paragraphProperties = TextLayoutReflectionExtensions.CreateTextParagraphProperties(typeface, fontSize, null, default, default, null, default, LineHeight, default, FontFeatures);
|
||||
var textLayout = new TextLayout(new LineTextSource(Lines), paragraphProperties);
|
||||
var verticalSpace = this.GetVerticalSpaceBetweenScrollViewerAndPresenter();
|
||||
height = Math.Ceiling(textLayout.Height + verticalSpace);
|
||||
var height = CalculateScrollViewerHeight(Lines);
|
||||
_scrollViewer.SetCurrentValue(MinHeightProperty, height);
|
||||
_scrollViewer.SetCurrentValue(MaxHeightProperty, height);
|
||||
}
|
||||
@@ -338,6 +334,16 @@ public class TextArea : AvaloniaTextBox,
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
private double CalculateScrollViewerHeight(int lines)
|
||||
{
|
||||
var fontSize = FontSize;
|
||||
var typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
|
||||
var paragraphProperties = TextLayoutReflectionExtensions.CreateTextParagraphProperties(typeface, fontSize, null, default, default, null, default, LineHeight, default, FontFeatures);
|
||||
var textLayout = new TextLayout(new LineTextSource(lines), paragraphProperties);
|
||||
var verticalSpace = this.GetVerticalSpaceBetweenScrollViewerAndPresenter();
|
||||
return Math.Ceiling(textLayout.Height + verticalSpace);
|
||||
}
|
||||
|
||||
private void ConfigureEffectiveShowClearButton()
|
||||
{
|
||||
@@ -384,32 +390,33 @@ public class TextArea : AvaloniaTextBox,
|
||||
|
||||
internal void NotifyAboutToResize()
|
||||
{
|
||||
_originHeight = Bounds.Height;
|
||||
SetCurrentValue(HeightProperty, Bounds.Height);
|
||||
if (_scrollViewer != null)
|
||||
{
|
||||
if (!double.IsNaN(Height))
|
||||
{
|
||||
_scrollViewer.SetCurrentValue(HeightProperty, _scrollViewer.Bounds.Height);
|
||||
}
|
||||
var minHeight = _scrollViewer.MinHeight;
|
||||
var height = _scrollViewer.Height;
|
||||
if (double.IsNaN(height))
|
||||
{
|
||||
height = minHeight;
|
||||
}
|
||||
_originHeight = height;
|
||||
SetCurrentValue(HeightProperty, double.NaN);
|
||||
var overhead = Math.Max(0, Bounds.Height - _scrollViewer.Bounds.Height);
|
||||
var minScrollHeight = MinLines > 0 ? CalculateScrollViewerHeight(MinLines) : 0;
|
||||
_minResizeHeight = overhead + minScrollHeight;
|
||||
_maxResizeHeight = MaxLines > 0
|
||||
? overhead + CalculateScrollViewerHeight(MaxLines)
|
||||
: double.PositiveInfinity;
|
||||
_scrollViewer.ClearValue(MinHeightProperty);
|
||||
_scrollViewer.ClearValue(MaxHeightProperty);
|
||||
}
|
||||
else
|
||||
{
|
||||
_minResizeHeight = 0;
|
||||
_maxResizeHeight = double.PositiveInfinity;
|
||||
}
|
||||
}
|
||||
|
||||
internal void NotifyResizing(Point delta)
|
||||
{
|
||||
if (_scrollViewer != null && _originHeight != null)
|
||||
if (_originHeight != null)
|
||||
{
|
||||
var minHeight = _scrollViewer.MinHeight;
|
||||
var maxHeight = _scrollViewer.MaxHeight;
|
||||
var height = _originHeight.Value + delta.Y;
|
||||
height = Math.Max(minHeight, Math.Min(height, maxHeight));
|
||||
_scrollViewer.SetCurrentValue(HeightProperty, height);
|
||||
height = Math.Max(_minResizeHeight, Math.Min(height, _maxResizeHeight));
|
||||
SetCurrentValue(HeightProperty, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
Value="{atom:SharedTokenResource ColorTextPlaceholder}" />
|
||||
<Setter Property="TextWrapping" Value="Wrap" />
|
||||
<Setter Property="AcceptsReturn" Value="True" />
|
||||
<Setter Property="MinLines" Value="1" />
|
||||
|
||||
<Style Selector="^ /template/ Panel#ContentLayout">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
|
||||
Reference in New Issue
Block a user