Dreamine.UI.Maui 1.0.1
Windows(WinUI)의 네이티브 `CheckBox`는 `WidthRequest`로 줄일 수 없는 거대한 최소 너비를 가져서 라벨과의 간격이 벌어지는 문제가 있어, 처음부터 직접 그려서 만들었습니다.
로딩중...
검색중...
일치하는것 없음
DreamineCheckLed.xaml.cs
이 파일의 문서화 페이지로 가기
1namespace Dreamine.UI.Maui;
2
50
59public partial class DreamineCheckLed : ContentView
60{
69 public static readonly BindableProperty IsOnProperty = BindableProperty.Create(
70 nameof(IsOn), typeof(bool), typeof(DreamineCheckLed), false, propertyChanged: OnVisualChanged);
71
80 public static readonly BindableProperty IsPulseProperty = BindableProperty.Create(
81 nameof(IsPulse), typeof(bool), typeof(DreamineCheckLed), false, propertyChanged: OnVisualChanged);
82
91 public static readonly BindableProperty DiameterProperty = BindableProperty.Create(
92 nameof(Diameter), typeof(double), typeof(DreamineCheckLed), 24d, propertyChanged: OnDiameterChanged);
93
102 public static readonly BindableProperty CornerProperty = BindableProperty.Create(
103 nameof(Corner), typeof(DreamineCheckLedCorner), typeof(DreamineCheckLed), DreamineCheckLedCorner.TopLeft,
104 propertyChanged: OnCornerChanged);
105
114 public bool IsOn
115 {
116 get => (bool)GetValue(IsOnProperty);
117 set => SetValue(IsOnProperty, value);
118 }
119
128 public bool IsPulse
129 {
130 get => (bool)GetValue(IsPulseProperty);
131 set => SetValue(IsPulseProperty, value);
132 }
133
142 public double Diameter
143 {
144 get => (double)GetValue(DiameterProperty);
145 set => SetValue(DiameterProperty, value);
146 }
147
157 {
158 get => (DreamineCheckLedCorner)GetValue(CornerProperty);
159 set => SetValue(CornerProperty, value);
160 }
161
171 {
172 InitializeComponent();
174 ApplyCorner();
175
176 // 생성자 시점엔 펄스를 건너뛰었으니, 실제로 화면에 붙어 Handler가 생기면 다시 적용한다.
177 HandlerChanged += (_, _) => ApplyVisualState();
178 }
179
212 private static void OnCornerChanged(BindableObject bindable, object oldValue, object newValue)
213 {
214 if (bindable is DreamineCheckLed led)
215 led.ApplyCorner();
216 }
217
226 private void ApplyCorner()
227 {
229 ? LayoutOptions.Start
230 : LayoutOptions.End;
231
233 ? LayoutOptions.Start
234 : LayoutOptions.End;
235 }
236
269 private static void OnVisualChanged(BindableObject bindable, object oldValue, object newValue)
270 {
271 if (bindable is DreamineCheckLed led)
272 led.ApplyVisualState();
273 }
274
307 private static void OnDiameterChanged(BindableObject bindable, object oldValue, object newValue)
308 {
309 if (bindable is DreamineCheckLed led)
310 {
311 led.Dot.WidthRequest = led.Diameter;
312 led.Dot.HeightRequest = led.Diameter;
313 led.Dot.StrokeShape = new Microsoft.Maui.Controls.Shapes.RoundRectangle { CornerRadius = led.Diameter / 2 };
314 }
315 }
316
325 private void ApplyVisualState()
326 {
327 Dot.BackgroundColor = IsOn ? Color.FromArgb("#1FD36B") : Color.FromArgb("#1A2A1A");
328 Dot.Stroke = IsOn ? Color.FromArgb("#7DD9B7") : Color.FromArgb("#556677");
329
330 // Handler가 아직 없으면(= 화면에 붙기 전, 보통 생성자에서 호출되는 경우) IAnimationManager가
331 // 없어서 AbortAnimation/Animation.Commit이 ArgumentException을 던진다. 그 시점엔 애니메이션을
332 // 건너뛰고 단순히 최종 Opacity만 맞춰둔다 — 실제 애니메이션은 화면에 붙은 뒤 토글될 때 적용된다.
333 if (Handler is null)
334 {
335 Dot.Opacity = 1.0;
336 return;
337 }
338
339 this.AbortAnimation("PulseAnimation");
340
341 if (IsOn && IsPulse)
342 {
343 var animation = new Animation(v => Dot.Opacity = v, 1.0, 0.4);
344 animation.Commit(this, "PulseAnimation", 16, 450, Easing.SinInOut, finished: null, repeat: () => IsOn && IsPulse);
345 }
346 else
347 {
348 Dot.Opacity = 1.0;
349 }
350 }
351}
static readonly BindableProperty DiameterProperty
static readonly BindableProperty CornerProperty
static void OnDiameterChanged(BindableObject bindable, object oldValue, object newValue)
static readonly BindableProperty IsPulseProperty
static void OnCornerChanged(BindableObject bindable, object oldValue, object newValue)
static void OnVisualChanged(BindableObject bindable, object oldValue, object newValue)
static readonly BindableProperty IsOnProperty