<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Maui 實踐:自制輕量級通知組件 NoticeView

      原創 夏群林 2025.8.4

      顯示彈出消息,Microsoft.Maui.Controls 命名空間下的 Page 類,提供了 DisplayAlert / DisplayActionSheet / DisplayPromptAsync 三種方法,滿足一般的對話交互需要,但必須點擊類似 "OK" / "Cancel" 的按鈕關閉窗口才能結束對話。也可以自定義一個 ContenPage 頁,有點麻煩,除非特殊要求,否則沒必要。如果單純顯示消息,發送后不管,官方提供了 Snackbar / Toast,會在可配置的持續時間后被消除。

      但在我的應用中,發現 Snackbar / Toast 不好用,經常顯示反應不及時。更麻煩的是,當有系列的提示密集發送,主體流程早已結束,消息還在慢吞吞的往外嘣,體驗很不好。

      于是我自己做了一個 NoticeView, 作為 MAUI 應用中的輕量級通知組件,核心目標是實現多優先級消息的有序管理與靈活顯示,其解決的關鍵問題,即后續消息到來,前面不太重要的消息,要讓路,要清空。這樣,保證消息的及時顯示。

      具體需求包括:

      • 支持多級優先級(Low/Medium/High/Critical),高優先級消息需“插隊”優先顯示,低優先級消息無條件讓路;
      • 每條消息需保證最小顯示時長(避免閃顯),無后續消息時按默認時長顯示;
      • 自動清理低優先級消息,限制隊列最大長度,防止內存溢出;
      • 支持多線程環境下的消息發送,確保隊列操作安全;
      • 提供手動清空功能,資源釋放時自動清理,避免內存泄漏。

      一、架構設計

      1. 核心組件

      NoticePriority:枚舉定義優先級,Critical 為最高級,權壓一切,比如,用Critical級確保清空所有消息。

      public enum NoticePriority { Low, Medium, High, Critical }
      
      public static void ClearNotice() => DisplayNotice(string.Empty, NoticePriority.Critical); 
      

      NoticeMessage:消息載體,包含內容(Value)和優先級(Priority);

      public class NoticeMessage(string value, NoticePriority priority = NoticePriority.Medium)
      {
          public string Value { get; } = value;
          public NoticePriority Priority { get; } = priority;
      }
      

      NoticeDisplayOptions:配置類,控制顯示時長(MinDisplayDuration/DisplayDuration)、隊列最大長度(MaxQueueLength)。提供了默認顯示樣式,包括字體、顏色、旋轉、陰影,我喜歡浮雕斜上如同驚鴻一瞥的效果,作為默認配置。各人可自行定義。

      public class NoticeDisplayOptions
      {
          public TimeSpan DisplayDuration { get; set; } = TimeSpan.FromSeconds(3);
          public TimeSpan MinDisplayDuration { get; set; } = TimeSpan.FromMilliseconds(500);
          public int MaxQueueLength { get; set; } = 50;
          
          public Color FontColor { get; set; } = Colors.DarkOrchid;
          public float FontSize { get; set; } = 16F;
          public float RotationAngle { get; set; } = -20;
          public bool HasShadow { get; set; } = true;
      }
      

      QueuedNotice:內部隊列消息類,封裝優先級、入隊序號(Order)和內容,實現 IComparable 接口用于排序;

       private class QueuedNotice(NoticePriority priority, int order, string message) : IComparable<QueuedNotice>
       {
           public NoticePriority Priority { get; } = priority;
           public int Order { get; } = order;
           public string Message { get; } = message;
      
           public int CompareTo(QueuedNotice? other)
           {
               if (other is null) return 1;
               // 優先級順序:Critical > High > Medium > Low
               int priorityCompare = other.Priority.CompareTo(Priority);
               return priorityCompare != 0 ? priorityCompare : Order.CompareTo(other.Order);
           }
       }
      

      NoticeView:核心控件,繼承 GraphicsView,實現 IDrawable,用于繪制UI;和 IDisposable,便于資源釋放。NoticeView 負責消息接收、隊列管理、顯示控制。 也提供了發送消息和清除消息的靜態方法。

      public partial class NoticeView : GraphicsView, IDrawable, IDisposable
      {
          private readonly NoticeDisplayOptions _options;
          private readonly ConcurrentDictionary<int, QueuedNotice> _messageQueue = new();
          private readonly Lock _queueSync = new();
          private QueuedNotice? _currentMessage;
          private DateTimeOffset _currentMessageStartTime;
          private int _messageOrder = 0;
          private bool _isTimerRunning;
          private IDispatcherTimer? _timer;
      
          public NoticeView(NoticeDisplayOptions? options = null)
          {
              _options = options ?? new NoticeDisplayOptions();
              Drawable = this;
              VerticalOptions = LayoutOptions.Fill;
              HorizontalOptions = LayoutOptions.Fill;
              InputTransparent = true;
      
              WeakReferenceMessenger.Default.Register<NoticeMessage>(this, (_, m) => OnMessageArrive(m));
          }
          
          // ...
          
      }
      

      2. 整體架構圖

      ┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
      │   外部調用者    │──┬──>│  NoticeMessage  │──┬──>│   NoticeView    │
      └─────────────────┘  │   └─────────────────┘  │   └────────┬────────┘
                           │                        │            │
                           │                        │            ▼
                           │                        │   ┌─────────────────┐
                           │                        └──>│  消息隊列管理   │
                           │                             └────────┬────────┘
                           │                                      │
                           └──────────────────────────────────────┘
                                        發送消息
      

      二、關鍵實現與核心代碼

      1. 優先級與排序機制

      通過自定義排序規則保證消息按“優先級降序+同優先級入隊順序升序”排列,確保高優先級消息先顯示,同優先級消息按發送順序顯示。

      實現細節

      • 自定義 QueuedNotice 類并實現 IComparable<QueuedNotice> 接口,排序規則:
        1. 先比較優先級(Critical > High > Medium > Low);
        2. 優先級相同時,比較入隊序號(Order),序號越小(入隊越早)越優先。
      • 入隊序號通過 Interlocked.Increment 生成,保證多線程環境下的原子性和唯一性,避免序號沖突。
      // 生成唯一入隊序號(多線程安全)
      int enqueueOrder = Interlocked.Increment(ref _messageOrder);
      

      設計考量

      • IComparable 封裝排序邏輯,避免分散在業務代碼中,提高可維護性;
      • 原子操作生成序號,解決多線程并發下的序號重復問題,確保同優先級消息的順序性。

      2. 隊列管理策略

      通過線程安全容器存儲消息,自動清理低優先級消息,控制隊列長度,確保高優先級消息“無障礙”顯示。

      實現細節

      • 采用 ConcurrentDictionary<int, QueuedNotice> 作為隊列容器,以入隊序號(Order)為鍵,支持并發讀寫,減少鎖競爭;
      • 新消息入隊時,根據優先級清理低優先級消息:
        • 非 Critical 級:移除隊列中所有優先級低于新消息的消息;
        • Critical 級:直接清空隊列+清除當前顯示的消息(權壓一切);
      • 隊列長度超過 MaxQueueLength 時,循環移除“最低優先級中最早入隊的消息”,避免隊列無限增長。
      private void OnMessageArrive(NoticeMessage message)
      {
          int enqueueOrder = Interlocked.Increment(ref _messageOrder);
          var enqueueNotice = new QueuedNotice(message.Priority, enqueueOrder, message.Value);
          bool needImmediateSwitch = false;
      
          lock (_queueSync) // 加鎖保證原子性
          {
              if (message.Priority == NoticePriority.Critical)
              {
                  // Critical級:清空隊列+清除當前消息,直接搶占顯示
                  _messageQueue.Clear();
                  _currentMessage = null;
                  needImmediateSwitch = true;
              }
              else
              {
                  // 非Critical級:移除隊列中所有低優先級消息
                  var lowerPriorityItems = _messageQueue.Values
                      .Where(m => m.Priority < message.Priority)
                      .ToList();
                  foreach (var item in lowerPriorityItems)
                      _ = _messageQueue.TryRemove(item.Order, out _);
      
                  // 關鍵:當前顯示的消息若優先級更低,立即清除并標記切換
                  if (_currentMessage != null && _currentMessage.Priority < message.Priority)
                  {
                      _messageQueue.TryRemove(_currentMessage.Order, out _);
                      _currentMessage = null;
                      needImmediateSwitch = true;
                  }
              }
      
              // 隊列長度控制:超過上限時,移除最低優先級中最舊的消息
              while (_messageQueue.Count >= _options.MaxQueueLength)
              {
                  var lowestPriority = _messageQueue.Values.Min(m => m.Priority);
                  var oldestLow = _messageQueue.Values
                      .Where(m => m.Priority == lowestPriority)
                      .OrderBy(m => m.Order)
                      .FirstOrDefault();
                  if (oldestLow != null)
                      _messageQueue.TryRemove(oldestLow.Order, out _);
                  else
                      break; // 極端情況防止死循環
              }
      
              _messageQueue.TryAdd(enqueueNotice.Order, enqueueNotice);
          }
      
          // 高優先級消息立即切換顯示,無需等待當前消息時長
          if (message.Priority == NoticePriority.Critical || needImmediateSwitch)
              MainThread.BeginInvokeOnMainThread(SwitchToNextMessage);
          else
              MainThread.BeginInvokeOnMainThread(UpdateDisplay);
      }
      

      設計考量

      • ConcurrentDictionary 減少簡單操作,如單條添加 / 移除的鎖競爭,提高并發性能;
      • 復合操作,如批量清理+添加,用 lock 保證原子性,避免數據不一致;
      • Critical 級消息直接清空隊列和當前消息,確保“最高優先級”的絕對權威性;
      • 隊列長度控制優先移除“最低優先級中最舊的消息”,平衡了優先級和時效性。

      3. 顯示與切換邏輯

      通過定時器監控消息顯示時長,根據“是否有后續消息”動態調整顯示時長,高優先級消息可強制打斷當前消息顯示。

      實現細節

      • 定時器采用 DispatcherTimer,綁定UI線程,間隔100ms高頻檢查,確保時長判斷精準;
      • 顯示時長規則: 有后續消息時,當前消息至少顯示 MinDisplayDuration,避免閃顯; 無后續消息時,顯示時長為 MinDisplayDurationDisplayDuration 的最大值,保證用戶能看清;
      • 切換邏輯:當滿足時長條件或收到更高優先級消息時,移除當前消息,顯示隊列中優先級最高的下一條消息。
      private void Timer_Tick(object? sender, EventArgs e)
      {
          if (_currentMessage == null)
          {
              StopTimer();
              return;
          }
      
          // 計算當前消息已顯示時長(從開始顯示時起算)
          var elapsed = DateTimeOffset.Now - _currentMessageStartTime;
          bool hasNextMessage;
      
          lock (_queueSync)
          {
              // 檢查是否有除當前消息外的其他消息
              hasNextMessage = _messageQueue.Count > (_currentMessage != null ? 1 : 0);
          }
      
          // 動態計算最大顯示時長
          var maxDuration = hasNextMessage
              ? _options.MinDisplayDuration
              : TimeSpan.FromMilliseconds(Math.Max(
                  _options.MinDisplayDuration.TotalMilliseconds,
                  _options.DisplayDuration.TotalMilliseconds));
      
          // 滿足時長條件則切換消息
          if (elapsed >= maxDuration)
              MainThread.BeginInvokeOnMainThread(SwitchToNextMessage);
      }
      
      // 切換到下一條消息
      private void SwitchToNextMessage()
      {
          lock (_queueSync)
          {
              // 移除當前顯示的消息
              if (_currentMessage != null)
                  _messageQueue.TryRemove(_currentMessage.Order, out _);
      
              // 顯示下一條消息(隊列中優先級最高的)
              var nextNotice = !_messageQueue.IsEmpty
                  ? _messageQueue.Values.OrderBy(m => m).FirstOrDefault()
                  : null;
      
              if (nextNotice != null)
              {
                  _currentMessage = nextNotice;
                  _currentMessageStartTime = DateTimeOffset.Now; // 從顯示時開始計時
                  Notice = nextNotice.Message;
                  Invalidate(); // 觸發UI重繪
              }
              else
              {
                  ClearCurrentMessage(); // 隊列空則清除顯示
              }
          }
      }
      

      設計考量

      • _currentMessageStartTime 僅在消息開始顯示時賦值,確保計時起點與用戶可見時間一致;
      • 高頻定時器(100ms)減少時長判斷的延遲,提升用戶體驗;
      • 動態調整顯示時長(區分有/無后續消息),既避免消息閃顯,又防止無后續消息時顯示過短。

      4. 線程安全與資源管理

      通過鎖機制和線程隔離保證多線程安全,通過 IDisposable 接口和手動清理方法確保資源釋放。

      實現細節

      • 線程安全:
        • 簡單操作(單條消息的添加/移除)依賴 ConcurrentDictionary 的線程安全特性;
        • 復合操作(批量清理、隊列長度控制)用 lock (_queueSync) 保證原子性;
        • 所有UI操作(如刷新顯示、切換消息)通過 MainThread.BeginInvokeOnMainThread 限制在主線程,避免跨線程異常。
      • 資源管理:
        • 實現 IDisposable 接口,釋放時注銷消息訂閱、停止定時器、清空隊列;
        • 提供 ClearQueue 手動清空方法,支持主動清理;
        • ClearNotice 方法通過發送 Critical 級空消息,利用其“清空一切”特性快速清理。
      public void Dispose()
      {
          // 注銷消息訂閱,避免內存泄漏
          WeakReferenceMessenger.Default.UnregisterAll(this);
          StopTimer(); // 停止定時器
          ClearQueue(); // 清空隊列和當前消息
          GC.SuppressFinalize(this);
      }
      
      // 手動清空隊列
      public void ClearQueue()
      {
          lock (_queueSync)
          {
              _messageQueue.Clear();
              ClearCurrentMessage();
          }
      }
      
      // 清空通知(利用Critical級特性)
      public static void ClearNotice() => DisplayNotice(string.Empty, NoticePriority.Critical);
      

      設計考量

      • 最小化鎖范圍(僅復合操作加鎖),平衡線程安全和性能;
      • 消息訂閱使用弱引用 WeakReferenceMessenger,配合 Dispose 注銷,避免組件銷毀后仍接收消息導致的內存泄漏;
      • ClearNotice 復用 Critical 級消息的清理邏輯,減少代碼冗余,同時保證清理徹底性。

      三、使用示例

      使用很方便。在需要顯示的頁面,放一個 NoticeView 實例即可:

      public partial class SearchPage : ContentPage
      {
      
          public SearchPage(SearchViewModel viewModel)
          {
              InitializeComponent();
              this.contentPageLayout.Children.Add(new NoticeView() { ZIndex = 3, InputTransparent = true });
          }
          
      	// ...
      }
      

      并且,可在多個顯示頁面放置 NoticeView 實例。

      在任何需要的地方調用:

      NoticeView.DisplayNotice($"Neither found nor suggested",NoticePriority.High);
      

      四、得意之處

      通過“優先級排序+隊列動態清理+即時切換+線程安全”的設計,NoticeView 實現了高優先級消息優先顯示、低優先級消息自動讓路的核心需求。其設計亮點在于:

      • IComparable 和原子序號保證了多線程下的消息順序;
      • 區分簡單/復合操作的線程安全策略,平衡了性能和安全性;
      • 動態時長控制和強制切換機制,兼顧了用戶體驗和優先級權威性;
      • 完善的資源清理機制,避免了內存泄漏風險。

      該組件可直接集成到 MAUI 應用中,支持自定義樣式和時長,適用于各類輕量級通知場景,如操作提示、狀態更新等。

      本方案源代碼開源,按照 MIT 協議許可。地址 xiaql/Zhally.Toolkit: Practices on specific tool kit in MAUI

      posted @ 2025-08-04 17:40  zhally  閱讀(358)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产福利社区一区二区| 日韩中文字幕精品人妻| 国产一区二区日韩在线| 国产欧美亚洲精品第一页在线| 亚洲第一香蕉视频啪啪爽| 少妇被粗大的猛烈进出视频| 日韩一区二区三区精彩视频| 亚洲成av人片无码天堂下载| 亚洲精品熟女一区二区| 亚洲精品福利一区二区三区蜜桃 | 宁陵县| 久久久久久九九99精品| 国产亚洲精品VA片在线播放| 方正县| 人妻少妇久久久久久97人妻| 亚洲 自拍 另类 欧美 综合| 亚洲人成网站77777在线观看| 亚洲高请码在线精品av| 女主播扒开屁股给粉丝看尿口| 高清自拍亚洲精品二区| 337p粉嫩大胆色噜噜噜| 亚洲码亚洲码天堂码三区| 国产精品成人午夜久久| 欧洲美女黑人粗性暴交视频| 欧美日韩一线| 亚洲精品一二三伦理中文| 插入中文字幕在线一区二区三区 | 欧美成人午夜在线观看视频| 久久综合九色综合久桃花| 亚洲熟妇自偷自拍另欧美| 五月婷婷久久中文字幕| 远安县| 亚洲精品无码久久一线| 在线免费播放av观看| 亚欧乱色精品免费观看| 潘金莲高清dvd碟片| 偷看少妇自慰xxxx| 亚洲夂夂婷婷色拍ww47| 日韩有码中文在线观看| 国产精品国产三级国产a| 亚洲综合精品一区二区三区 |