AdaptiveContainer.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. using Avalonia;
  2. using Avalonia.Controls;
  3. using Avalonia.Media;
  4. using YZWater.Core.Utils;
  5. namespace YZWater.Avalonia.Controls;
  6. /// <summary>
  7. /// 鑷傚簲瀹瑰櫒鎺т欢 - 鏍规嵁绐楀彛澶у皬鑷姩缂╂斁鍐呭
  8. /// </summary>
  9. public class AdaptiveContainer : Decorator
  10. {
  11. public static readonly StyledProperty<double> DesignWidthProperty =
  12. AvaloniaProperty.Register<AdaptiveContainer, double>(nameof(DesignWidth), ResolutionManager.DesignWidth);
  13. public static readonly StyledProperty<double> DesignHeightProperty =
  14. AvaloniaProperty.Register<AdaptiveContainer, double>(nameof(DesignHeight), ResolutionManager.DesignHeight);
  15. public static readonly StyledProperty<bool> MaintainAspectRatioProperty =
  16. AvaloniaProperty.Register<AdaptiveContainer, bool>(nameof(MaintainAspectRatio), true);
  17. public static readonly StyledProperty<Stretch> StretchProperty =
  18. AvaloniaProperty.Register<AdaptiveContainer, Stretch>(nameof(Stretch), Stretch.Uniform);
  19. public static readonly StyledProperty<double> MinScaleProperty =
  20. AvaloniaProperty.Register<AdaptiveContainer, double>(nameof(MinScale), 0.5);
  21. public static readonly StyledProperty<double> MaxScaleProperty =
  22. AvaloniaProperty.Register<AdaptiveContainer, double>(nameof(MaxScale), 2.0);
  23. public double DesignWidth
  24. {
  25. get => GetValue(DesignWidthProperty);
  26. set => SetValue(DesignWidthProperty, value);
  27. }
  28. public double DesignHeight
  29. {
  30. get => GetValue(DesignHeightProperty);
  31. set => SetValue(DesignHeightProperty, value);
  32. }
  33. public bool MaintainAspectRatio
  34. {
  35. get => GetValue(MaintainAspectRatioProperty);
  36. set => SetValue(MaintainAspectRatioProperty, value);
  37. }
  38. public Stretch Stretch
  39. {
  40. get => GetValue(StretchProperty);
  41. set => SetValue(StretchProperty, value);
  42. }
  43. public double MinScale
  44. {
  45. get => GetValue(MinScaleProperty);
  46. set => SetValue(MinScaleProperty, value);
  47. }
  48. public double MaxScale
  49. {
  50. get => GetValue(MaxScaleProperty);
  51. set => SetValue(MaxScaleProperty, value);
  52. }
  53. static AdaptiveContainer()
  54. {
  55. AffectsMeasure<AdaptiveContainer>(DesignWidthProperty, DesignHeightProperty, MaintainAspectRatioProperty, StretchProperty, MinScaleProperty, MaxScaleProperty);
  56. AffectsArrange<AdaptiveContainer>(DesignWidthProperty, DesignHeightProperty, MaintainAspectRatioProperty, StretchProperty, MinScaleProperty, MaxScaleProperty);
  57. }
  58. protected override Size MeasureOverride(Size availableSize)
  59. {
  60. var child = Child;
  61. if (child == null)
  62. {
  63. return new Size(0, 0);
  64. }
  65. // 璁╁瓙鍏冪礌鎸夌収璁捐灏哄娴嬮噺
  66. var designSize = new Size(DesignWidth, DesignHeight);
  67. child.Measure(designSize);
  68. // 璁$畻鍙敤绌洪棿
  69. var availableWidth = availableSize.Width;
  70. var availableHeight = availableSize.Height;
  71. // 濡傛灉鍙敤绌洪棿鏄棤闄愮殑锛屼娇鐢ㄨ璁″昂瀵
  72. if (double.IsInfinity(availableWidth))
  73. {
  74. availableWidth = DesignWidth;
  75. }
  76. if (double.IsInfinity(availableHeight))
  77. {
  78. availableHeight = DesignHeight;
  79. }
  80. // 杩斿洖鍙敤绌洪棿锛堝疄闄呯缉鏀惧湪 Arrange 闃舵澶勭悊锛
  81. return new Size(availableWidth, availableHeight);
  82. }
  83. protected override Size ArrangeOverride(Size finalSize)
  84. {
  85. var child = Child;
  86. if (child == null)
  87. {
  88. return finalSize;
  89. }
  90. // 璁$畻缂╂斁姣斾緥
  91. var scaleX = finalSize.Width / DesignWidth;
  92. var scaleY = finalSize.Height / DesignHeight;
  93. var scale = Stretch switch
  94. {
  95. Stretch.Fill => new ScaleTransform(scaleX, scaleY),
  96. Stretch.Uniform => new ScaleTransform(Math.Min(scaleX, scaleY), Math.Min(scaleX, scaleY)),
  97. Stretch.UniformToFill => new ScaleTransform(Math.Max(scaleX, scaleY), Math.Max(scaleX, scaleY)),
  98. _ => new ScaleTransform(1, 1)
  99. };
  100. // 闄愬埗缂╂斁鑼冨洿
  101. var uniformScale = Math.Max(MinScale, Math.Min(MaxScale, scale.ScaleX));
  102. // 鏇存柊鍒嗚鲸鐜囩鐞嗗櫒
  103. ResolutionManager.Instance.UpdateResolution(finalSize.Width, finalSize.Height);
  104. // 璁$畻瀹為檯灏哄
  105. var actualWidth = DesignWidth * uniformScale;
  106. var actualHeight = DesignHeight * uniformScale;
  107. // 璁$畻灞呬腑鍋忕Щ
  108. var offsetX = (finalSize.Width - actualWidth) / 2;
  109. var offsetY = (finalSize.Height - actualHeight) / 2;
  110. // 搴旂敤鍙樻崲
  111. child.RenderTransform = new ScaleTransform(uniformScale, uniformScale);
  112. child.RenderTransformOrigin = new RelativePoint(0, 0, RelativeUnit.Absolute);
  113. // 鎺掑垪瀛愬厓绱
  114. child.Arrange(new Rect(offsetX, offsetY, DesignWidth, DesignHeight));
  115. return finalSize;
  116. }
  117. }