Unity高級UI拖動控制器教程

在游戲開發過程中,UI組件的拖動功能是一個常見的需求。特別是在需要實現拖動、邊界檢測、透明度控制以及動畫反饋等功能時,編寫一個高級UI拖動控制器將非常有用。在本文中,我們將創建一個支持多種Canvas模式和更精確邊界檢測的高級UI拖動控制器。

1. 腳本概述

AdvancedUIDragController是一個實現了IBeginDragHandlerIDragHandlerIEndDragHandler接口的Unity腳本。它提供了UI元素拖動功能,并且支持透明度調整、邊界限制、鼠標指針變化、邊框顯示等多種特性。

2. 腳本結構

這個腳本包含多個功能模塊:

  • 拖動設置:控制拖動是否啟用、拖動時的透明度等。
  • 邊界限制:控制UI元素是否會被限制在屏幕、Canvas或父物體的邊界內。
  • 拖動反饋:改變鼠標指針、顯示拖動邊框等。
  • 動畫設置:拖動結束時是否使用緩動動畫。

3. 代碼分析

3.1. 變量聲明
// 拖動設置
public bool enableDrag = true; // 是否啟用拖動功能
public bool showTransparencyOnDrag = true; // 拖動時是否顯示半透明效果
public float dragTransparency = 1f; // 拖動時的透明度// 邊界限制
public bool limitToScreenBounds = true; // 是否限制在屏幕邊界內
public float boundaryMargin = 10f; // 邊界邊距
public BoundaryMode boundaryMode = BoundaryMode.ScreenSpace; // 邊界限制模式// 拖動反饋
public bool changeCursorOnDrag = true; // 拖動時是否改變鼠標指針
public Texture2D dragCursor; // 拖動時的鼠標指針
public bool showBorderOnDrag = true; // 拖動時是否顯示邊框
public Color dragBorderColor = Color.yellow; // 拖動時的邊框顏色// 動畫設置
public bool useEasingAnimation = true; // 拖動結束時是否使用緩動動畫
public float animationDuration = 0.2f; // 緩動動畫持續時間
public AnimationCurve easingCurve = AnimationCurve.EaseInOut(0, 0, 1, 1); // 緩動動畫曲線
3.2. 初始化組件

Start()函數中,獲取UI組件引用并設置必要的初始化。

void Start()
{InitializeComponents();SetupBorder();
}private void InitializeComponents()
{rectTransform = GetComponent<RectTransform>();canvas = GetComponentInParent<Canvas>();canvasScaler = canvas.GetComponent<CanvasScaler>();canvasGroup = GetComponent<CanvasGroup>();if (canvasGroup == null && showTransparencyOnDrag){canvasGroup = gameObject.AddComponent<CanvasGroup>();}originalAlpha = canvasGroup != null ? canvasGroup.alpha : 1f;
}
3.3. 拖動開始

當拖動開始時,記錄鼠標偏移量、設置透明度、顯示邊框等。

public void OnBeginDrag(PointerEventData eventData)
{if (!enableDrag) return;isDragging = true;Vector2 localPointerPosition;RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out localPointerPosition);dragOffset = localPointerPosition;originalPosition = rectTransform.anchoredPosition;if (showTransparencyOnDrag && canvasGroup != null){canvasGroup.alpha = dragTransparency;}if (showBorderOnDrag && borderImage != null){borderImage.gameObject.SetActive(true);}if (changeCursorOnDrag && dragCursor != null){Cursor.SetCursor(dragCursor, hotSpot, cursorMode);}
}
3.4. 拖動中

在拖動過程中,計算UI元素的新位置,并應用邊界限制。

public void OnDrag(PointerEventData eventData)
{if (!enableDrag || !isDragging) return;Vector2 localPointerPosition;RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform.parent as RectTransform, eventData.position, eventData.pressEventCamera, out localPointerPosition);Vector2 newPosition = localPointerPosition - dragOffset;if (limitToScreenBounds){newPosition = ClampToBounds(newPosition);}rectTransform.anchoredPosition = newPosition;targetPosition = newPosition;
}
3.5. 拖動結束

拖動結束時,恢復透明度、隱藏邊框、恢復鼠標指針,并應用緩動動畫。

public void OnEndDrag(PointerEventData eventData)
{if (!isDragging) return;isDragging = false;if (showTransparencyOnDrag && canvasGroup != null){canvasGroup.alpha = originalAlpha;}if (showBorderOnDrag && borderImage != null){borderImage.gameObject.SetActive(false);}if (changeCursorOnDrag){Cursor.SetCursor(null, Vector2.zero, cursorMode);}if (useEasingAnimation){Vector2 finalPosition = limitToScreenBounds ? ClampToBounds(targetPosition) : targetPosition;if (Vector2.Distance(rectTransform.anchoredPosition, finalPosition) > 0.1f){easingCoroutine = StartCoroutine(EaseToPosition(finalPosition));}}
}
3.6. 邊界限制與動畫

ClampToBounds方法用于根據不同的模式限制拖動元素的位置,EaseToPosition方法則負責緩動動畫的執行。

4. 邊界限制模式

我們提供了三種邊界限制模式:

  • ScreenSpace:限制元素在屏幕空間內。
  • CanvasSpace:限制元素在Canvas空間內。
  • ParentSpace:限制元素在父物體空間內。

5. 實現拖動動畫

緩動動畫會在拖動結束時平滑地將UI元素移動到目標位置。

private System.Collections.IEnumerator EaseToPosition(Vector2 targetPos)
{Vector2 startPos = rectTransform.anchoredPosition;float elapsedTime = 0f;while (elapsedTime < animationDuration){t = easingCurve.Evaluate(t);rectTransform.anchoredPosition = Vector2.Lerp(startPos, targetPos, t);yield return null;}rectTransform.anchoredPosition = targetPos;easingCoroutine = null;
}

6. 使用方法

  1. 將該腳本附加到任何UI元素(如Panel、Image等)。
  2. 在Inspector面板中設置各項參數,例如是否啟用拖動、透明度、邊界限制等。
  3. 運行游戲并測試拖動效果。

7. 完整代碼

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;/// <summary>
/// 高級UI拖動控制器 - 支持多種Canvas模式和更精確的邊界檢測
/// </summary>
public class AdvancedUIDragController : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{[Header("拖動設置")][Tooltip("是否啟用拖動功能")]public bool enableDrag = true;[Tooltip("拖動時是否顯示半透明效果")]public bool showTransparencyOnDrag = true;[Tooltip("拖動時的透明度")][Range(0f, 1f)]public float dragTransparency = 0.7f;[Header("邊界限制")][Tooltip("是否限制在屏幕邊界內")]public bool limitToScreenBounds = true;[Tooltip("邊界邊距(像素)")]public float boundaryMargin = 10f;[Tooltip("邊界限制模式")]public BoundaryMode boundaryMode = BoundaryMode.ScreenSpace;[Header("拖動反饋")][Tooltip("拖動時是否改變鼠標指針")]public bool changeCursorOnDrag = true;[Tooltip("拖動時的鼠標指針")]public Texture2D dragCursor;[Tooltip("拖動時是否顯示邊框")]public bool showBorderOnDrag = true;[Tooltip("拖動時的邊框顏色")]public Color dragBorderColor = Color.yellow;[Header("動畫設置")][Tooltip("拖動結束時是否使用緩動動畫")]public bool useEasingAnimation = true;[Tooltip("緩動動畫持續時間")]public float animationDuration = 0.2f;[Tooltip("緩動動畫曲線")]public AnimationCurve easingCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);// 邊界模式枚舉public enum BoundaryMode{ScreenSpace,    // 屏幕空間CanvasSpace,    // Canvas空間ParentSpace     // 父對象空間}// 私有變量private RectTransform rectTransform;private Canvas canvas;private CanvasScaler canvasScaler;private Vector2 originalPosition;private Vector2 dragOffset;private float originalAlpha;private CanvasGroup canvasGroup;private bool isDragging = false;private CursorMode cursorMode = CursorMode.Auto;private Vector2 hotSpot = Vector2.zero;private Coroutine easingCoroutine;private UnityEngine.UI.Image borderImage;private Vector2 targetPosition;void Start(){InitializeComponents();SetupBorder();}private void InitializeComponents(){// 獲取組件引用rectTransform = GetComponent<RectTransform>();canvas = GetComponentInParent<Canvas>();canvasScaler = canvas.GetComponent<CanvasScaler>();// 如果沒有CanvasGroup,添加一個用于透明度控制canvasGroup = GetComponent<CanvasGroup>();if (canvasGroup == null && showTransparencyOnDrag){canvasGroup = gameObject.AddComponent<CanvasGroup>();}// 保存原始透明度if (canvasGroup != null){originalAlpha = canvasGroup.alpha;}// 設置鼠標指針熱點if (dragCursor != null){hotSpot = new Vector2(dragCursor.width / 2, dragCursor.height / 2);}}private void SetupBorder(){if (showBorderOnDrag){// 創建邊框UIGameObject borderObj = new GameObject("DragBorder");borderObj.transform.SetParent(transform, false);borderImage = borderObj.AddComponent<UnityEngine.UI.Image>();borderImage.color = dragBorderColor;borderImage.raycastTarget = false;RectTransform borderRect = borderObj.GetComponent<RectTransform>();borderRect.anchorMin = Vector2.zero;borderRect.anchorMax = Vector2.one;borderRect.offsetMin = Vector2.zero;borderRect.offsetMax = Vector2.zero;// 添加邊框效果borderImage.sprite = CreateBorderSprite();borderImage.type = UnityEngine.UI.Image.Type.Sliced;borderObj.SetActive(false);}}private Sprite CreateBorderSprite(){// 創建一個簡單的邊框精靈Texture2D borderTexture = new Texture2D(3, 3);Color[] pixels = new Color[9];// 設置邊框像素為白色,內部為透明for (int i = 0; i < 9; i++){int x = i % 3;int y = i / 3;if (x == 0 || x == 2 || y == 0 || y == 2)pixels[i] = Color.white;elsepixels[i] = Color.clear;}borderTexture.SetPixels(pixels);borderTexture.Apply();return Sprite.Create(borderTexture, new Rect(0, 0, 3, 3), new Vector2(0.5f, 0.5f), 1f, 0, SpriteMeshType.FullRect, new Vector4(1, 1, 1, 1));}public void OnBeginDrag(PointerEventData eventData){if (!enableDrag) return;isDragging = true;// 停止任何正在進行的緩動動畫if (easingCoroutine != null){StopCoroutine(easingCoroutine);easingCoroutine = null;}// 計算拖動偏移量Vector2 localPointerPosition;RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out localPointerPosition);dragOffset = localPointerPosition;// 保存原始位置originalPosition = rectTransform.anchoredPosition;// 設置透明度if (showTransparencyOnDrag && canvasGroup != null){canvasGroup.alpha = dragTransparency;}// 顯示邊框if (showBorderOnDrag && borderImage != null){borderImage.gameObject.SetActive(true);}// 改變鼠標指針if (changeCursorOnDrag && dragCursor != null){Cursor.SetCursor(dragCursor, hotSpot, cursorMode);}}public void OnDrag(PointerEventData eventData){if (!enableDrag || !isDragging) return;// 計算新位置Vector2 localPointerPosition;RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform.parent as RectTransform, eventData.position, eventData.pressEventCamera, out localPointerPosition);Vector2 newPosition = localPointerPosition - dragOffset;// 應用屏幕邊界限制if (limitToScreenBounds){newPosition = ClampToBounds(newPosition);}// 更新位置rectTransform.anchoredPosition = newPosition;targetPosition = newPosition;}public void OnEndDrag(PointerEventData eventData){if (!isDragging) return;isDragging = false;// 恢復透明度if (showTransparencyOnDrag && canvasGroup != null){canvasGroup.alpha = originalAlpha;}// 隱藏邊框if (showBorderOnDrag && borderImage != null){borderImage.gameObject.SetActive(false);}// 恢復鼠標指針if (changeCursorOnDrag){Cursor.SetCursor(null, Vector2.zero, cursorMode);}// 應用緩動動畫if (useEasingAnimation){Vector2 finalPosition = limitToScreenBounds ? ClampToBounds(targetPosition) : targetPosition;if (Vector2.Distance(rectTransform.anchoredPosition, finalPosition) > 0.1f){easingCoroutine = StartCoroutine(EaseToPosition(finalPosition));}}}/// <summary>/// 根據邊界模式限制位置/// </summary>private Vector2 ClampToBounds(Vector2 position){switch (boundaryMode){case BoundaryMode.ScreenSpace:return ClampToScreenBounds(position);case BoundaryMode.CanvasSpace:return ClampToCanvasBounds(position);case BoundaryMode.ParentSpace:return ClampToParentBounds(position);default:return position;}}/// <summary>/// 限制在屏幕邊界內/// </summary>private Vector2 ClampToScreenBounds(Vector2 position){if (canvas == null) return position;// 獲取屏幕尺寸Vector2 screenSize = new Vector2(Screen.width, Screen.height);// 獲取UI元素在屏幕空間中的尺寸Vector2 uiSize = GetUISizeInScreenSpace();// 計算邊界float minX = uiSize.x / 2 + boundaryMargin;float maxX = screenSize.x - uiSize.x / 2 - boundaryMargin;float minY = uiSize.y / 2 + boundaryMargin;float maxY = screenSize.y - uiSize.y / 2 - boundaryMargin;// 將屏幕坐標轉換為本地坐標Vector2 screenPosition = RectTransformUtility.WorldToScreenPoint(null, rectTransform.TransformPoint(position));screenPosition.x = Mathf.Clamp(screenPosition.x, minX, maxX);screenPosition.y = Mathf.Clamp(screenPosition.y, minY, maxY);// 轉換回本地坐標Vector2 localPosition;RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform.parent as RectTransform, screenPosition, null, out localPosition);return localPosition;}/// <summary>/// 限制在Canvas邊界內/// </summary>private Vector2 ClampToCanvasBounds(Vector2 position){if (canvas == null) return position;RectTransform canvasRect = canvas.GetComponent<RectTransform>();if (canvasRect == null) return position;Vector2 uiSize = rectTransform.sizeDelta;float minX = -canvasRect.sizeDelta.x / 2 + uiSize.x / 2 + boundaryMargin;float maxX = canvasRect.sizeDelta.x / 2 - uiSize.x / 2 - boundaryMargin;float minY = -canvasRect.sizeDelta.y / 2 + uiSize.y / 2 + boundaryMargin;float maxY = canvasRect.sizeDelta.y / 2 - uiSize.y / 2 - boundaryMargin;position.x = Mathf.Clamp(position.x, minX, maxX);position.y = Mathf.Clamp(position.y, minY, maxY);return position;}/// <summary>/// 限制在父對象邊界內/// </summary>private Vector2 ClampToParentBounds(Vector2 position){RectTransform parentRect = rectTransform.parent as RectTransform;if (parentRect == null) return position;Vector2 uiSize = rectTransform.sizeDelta;Vector2 parentSize = parentRect.sizeDelta;float minX = -parentSize.x / 2 + uiSize.x / 2 + boundaryMargin;float maxX = parentSize.x / 2 - uiSize.x / 2 - boundaryMargin;float minY = -parentSize.y / 2 + uiSize.y / 2 + boundaryMargin;float maxY = parentSize.y / 2 - uiSize.y / 2 - boundaryMargin;position.x = Mathf.Clamp(position.x, minX, maxX);position.y = Mathf.Clamp(position.y, minY, maxY);return position;}/// <summary>/// 獲取UI元素在屏幕空間中的尺寸/// </summary>private Vector2 GetUISizeInScreenSpace(){Vector3[] corners = new Vector3[4];rectTransform.GetWorldCorners(corners);Vector2 size = new Vector2(Vector3.Distance(corners[0], corners[3]),Vector3.Distance(corners[0], corners[1]));return size;}/// <summary>/// 緩動到目標位置/// </summary>private System.Collections.IEnumerator EaseToPosition(Vector2 targetPos){Vector2 startPos = rectTransform.anchoredPosition;float elapsedTime = 0f;while (elapsedTime < animationDuration){elapsedTime += Time.deltaTime;float t = elapsedTime / animationDuration;t = easingCurve.Evaluate(t);rectTransform.anchoredPosition = Vector2.Lerp(startPos, targetPos, t);yield return null;}rectTransform.anchoredPosition = targetPos;easingCoroutine = null;}/// <summary>/// 重置到原始位置/// </summary>public void ResetToOriginalPosition(){if (rectTransform != null){if (useEasingAnimation){if (easingCoroutine != null){StopCoroutine(easingCoroutine);}easingCoroutine = StartCoroutine(EaseToPosition(originalPosition));}else{rectTransform.anchoredPosition = originalPosition;}}}/// <summary>/// 設置拖動是否啟用/// </summary>public void SetDragEnabled(bool enabled){enableDrag = enabled;}/// <summary>/// 設置邊界限制是否啟用/// </summary>public void SetBoundaryLimitEnabled(bool enabled){limitToScreenBounds = enabled;}/// <summary>/// 設置邊界模式/// </summary>public void SetBoundaryMode(BoundaryMode mode){boundaryMode = mode;}void OnDisable(){// 確保在禁用時恢復鼠標指針和停止動畫if (isDragging && changeCursorOnDrag){Cursor.SetCursor(null, Vector2.zero, cursorMode);}if (easingCoroutine != null){StopCoroutine(easingCoroutine);easingCoroutine = null;}}void OnDestroy(){// 清理邊框精靈if (borderImage != null && borderImage.sprite != null){DestroyImmediate(borderImage.sprite.texture);DestroyImmediate(borderImage.sprite);}}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/95018.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/95018.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/95018.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

零基礎上手:Cursor + MCP 爬取 YouTube 視頻數據

前言 大模型與 AI 應用越來越普及的今天&#xff0c;實時、穩定地獲取網絡數據變得尤為重要。無論是做內容分析、趨勢研究還是自動化任務&#xff0c;爬取和處理數據始終是繞不開的一環。 傳統爬蟲往往面臨封禁、驗證碼、動態渲染等難題&#xff0c;而 Bright Data MCP&#x…

frp 一個高性能的反向代理服務

文章目錄項目概述核心特性系統架構快速開始1. 下載安裝2. 服務端快速配置3. 客戶端快速配置4. 驗證連接配置文件說明代理類型TCP/UDP 代理HTTP/HTTPS 代理安全代理 (STCP/SUDP)P2P 代理 (XTCP)插件系統靜態文件服務HTTP/SOCKS5 代理協議轉換使用場景遠程辦公Web 服務發布游戲服…

Android -第二十一次技術總結

一、activity與Fragment的通信有哪些&#xff1f;使用接口進行通信的邏輯與代碼示例使用接口通信的核心是解耦&#xff0c;通過定義一個接口作為通信契約&#xff0c;讓 Fragment 不依賴于具體的 Activity 類型。1. 定義通信接口&#xff08;在 Fragment 內&#xff09;首先&am…

【算法】78.子集--通俗講解

通俗易懂講解“子集”算法題目 一、題目是啥?一句話說清 給你一個不含重復元素的整數數組,返回所有可能的子集(包括空集和它本身)。 示例: 輸入:nums = [1,2,3] 輸出:[[], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]] 二、解題核心 使用回溯法(遞歸)或位運算來…

Cherrystudio的搭建和使用

1、下載和安裝 Cherry Studio 官方網站 - 全能的 AI 助手 2、配置LLM 3、聊天助手 3.1 添加和編輯助手 3.2 選擇LLM 3.3 對話聊天 4、配置MCP 4.1 安裝MCP執行插件 4.2 安裝 node和npm Node.js — Download Node.js npm -v 10.9.3 node -v v22…

基于Matlab結合膚色檢測與卷積神經網絡的人臉識別方法研究

近年來&#xff0c;隨著人工智能與計算機視覺技術的發展&#xff0c;人臉識別在人機交互、安防監控、身份認證等領域得到了廣泛應用。本文提出了一種基于 MATLAB 平臺&#xff0c;結合 膚色檢測與卷積神經網絡&#xff08;CNN&#xff09; 的人臉識別方法。該方法首先利用膚色模…

在八月點燃AI智慧之火:CSDN創作之星挑戰賽開啟靈感盛宴

在八月點燃AI智慧之火&#xff1a;CSDN創作之星挑戰賽開啟靈感盛宴八月驕陽似火&#xff0c;智能時代的技術熱情同樣熾熱。在這個充滿創新活力的季節&#xff0c;「AIcoding八月創作之星挑戰賽」正式拉開帷幕&#xff0c;為CSDN的創作者們打造一個展示才華、碰撞靈感的專業舞臺…

解密 Vue 3 shallowRef:淺層響應式 vs 深度響應式的性能對決

&#x1f4d6; 概述 shallowRef() 是 Vue 3 中的一個組合式 API 函數&#xff0c;用于創建淺層響應式引用。與 ref() 不同&#xff0c;shallowRef() 只在其 .value 被直接替換時觸發響應式更新&#xff0c;不會深度監聽對象內部屬性的變化。 &#x1f3af; 基本概念 什么是 sh…

Linux進程間通信(IPC)深入解析

Linux進程間通信&#xff08;IPC&#xff09;深入解析 1 概述 Linux 進程間通信 (Inter-Process Communication, IPC) 是不同進程之間交換數據與同步操作的機制。現代 Linux 內核提供了多種 IPC 方式&#xff0c;從傳統的管道和 System V IPC 到現代的套接字和 D-Bus&#xff0…

TensorFlow-GPU版本安裝

前言&#xff1a; &#xff08;1&#xff09;因項目需求&#xff0c;需要安裝TensorFlow-GPU版本&#xff0c;故本文在此記錄安裝過程。 &#xff08;2&#xff09;有注釋&#xff0c;優先看注釋 &#xff08;3&#xff09;本文所使用的GPU為NVIDIA GeForce RTX 5080 Laptop GP…

Elasticsearch 索引字段刪除,除了 Reindex 重建索引還有沒有別的解決方案?

unsetunset1、問題來源unsetunset在生產環境維護 Elasticsearch 集群的過程中&#xff0c;經常會遇到這樣的場景&#xff1a;業務需求變更導致某些字段不再使用&#xff0c;或者早期設計時添加了一些冗余字段&#xff0c;現在需要清理掉。最近球友在公司的一個項目中就遇到了這…

Ubuntu虛擬機磁盤空間擴展指南

這是一份詳細且易于理解的 Ubuntu 虛擬機磁盤空間擴展指南。本指南涵蓋了兩種主流虛擬機軟件&#xff08;VirtualBox 和 VMware&#xff09;的操作步驟&#xff0c;并分為 “擴展虛擬磁盤” 和 “在 Ubuntu 內部分配新空間” 兩大部分。重要提示&#xff1a;在進行任何磁盤操作…

教程1:用vscode->ptvsd-創建和調試一個UI(python)-轉載官方翻譯(有修正)

vscode用python開發maya聯動調試設置 3dsMax Python開發環境搭建 3文聯動之debugpy調試max‘python. 3文聯動之socket插槽注入max‘python 本教程是max主動接收創建代碼的方式&#xff08;預先運行界面&#xff0c;通過按鈕主動讀取py腳本&#xff0c;執行斷點&#xff09;&…

龍迅#LT7621GX適用于兩路HDMI2.1/DP1.4A轉HDMI2.1混切應用,分辨率高達8K60HZ!

1. 描述LT7621GX是一款高性能兩路HDMI2.1/DP1.4轉HDMI2.1混合開關芯片&#xff0c;用于顯示應用。 HDCP RX作為HDCP中繼器的上游&#xff0c;可以與其他芯片的HDCP TX配合&#xff0c;實現中繼器功能。 對于HDMI2.1輸入&#xff0c;LT7621GX可以配置為3/4通道。自適應均衡使其適…

【Ruoyi 解密 - 12. JDK17的新特性】------ 從Java 8 到 Java 17:向Scala看齊的“簡潔革命”,同宗JVM下的效率狂飆

從Java 8到Java 17&#xff1a;抄作業Scala&#xff1f;JVM同宗下的Ruoyi開發效率狂飆&#xff01; 上一篇我們聊到JDK 17對Python的柔性借鑒&#xff0c;可深入用下來才發現——這哪夠&#xff01;對Ruoyi開發者來說&#xff0c;JDK 17真正的“王炸”&#xff0c;是把同根JVM的…

大模型 “輕量化” 之戰:從千億參數到端側部署,AI 如何走進消費電子?

一、大模型 “輕量化” 的行業背景在 AI 技術蓬勃發展的當下&#xff0c;大模型已然成為行業焦點。從 GPT-4 突破萬億級參數量&#xff0c;到 DeepSeek-R1 邁向千億參數規模&#xff0c;大模型的參數擴張趨勢顯著。然而&#xff0c;這種規模的增長也帶來了諸多挑戰。以 GPT-4 為…

香港電訊與Microsoft香港推出新世代“Teams Phone” 解決方案

香港電訊成為香港首家提供 “Microsoft Operator Connect”的本地電訊營運商1 香港電訊&#xff08;股份代號&#xff1a;6823&#xff09;【香港 ? 2025年2月11日】 – 香港電訊宣布與 Microsoft 香港合作推出 “Operator Connect”&#xff0c;成為全港首家為企業客戶提供全…

PlantUML描述《分析模式》第3章觀察和測量(2)

lantUML描述《分析模式》第2章“當責”&#xff08;1&#xff09; PlantUML描述《分析模式》第2章“當責”&#xff08;2&#xff09; PlantUML描述《分析模式》第3章觀察和測量&#xff08;1&#xff09; 原圖3.8 EA繪制 圖3.8 遞歸關系用于記錄證據和評估。 PlantUML sta…

輪廓周長,面積,外界圓,外界矩形近似輪廓和模板匹配和argparse模塊實現代碼參數的動態配置

目錄 一.輪廓操作 1.輪廓特征的引入與篩選 2.輪廓排序和精準定位 3.外接圓與外接矩形的計算與繪制 二.輪廓近似 1.輪廓近似的基本概念 2.輪廓近似的實現方法和核心步驟 3. 近似精度參數的設定邏輯 4.輪廓定位方法 三.模板匹配 1.模板匹配技術原理與實現流程 2.技術要…

【第三方網站測評:會話管理漏洞的測試與加固】

會話管理是Web應用安全的用于在無狀態的HTTP協議上維持用戶狀態。漏洞主要源于會話令牌(Session Token)的生成、傳輸、驗證和銷毀過程中的缺陷。攻擊者利用這些缺陷可劫持用戶會話,未經授權訪問敏感數據或執行特權操作,屬于OWASP TOP 10中身份驗證失效的高頻風險。 會話管…