UGUI各种优化效果
本文所实现的UGUI效果需求如下:
- 支持缩放滑动效果
- 支持动态缩放循环加载
- 支持大数据固定Item复用加载
- 支持不用Mask遮罩无限循环加载
- 支持ObjectPool动态加载
- 支持无限不规则子物体动态加载
- 支持拖动并点击和拖拽
- 支持拖动并拖拽
- 支持ScrollRect拖动自动吸附功能(拖动是否超过一半自动进退)
缩放滑动效果
缩放循环展示卡牌效果
大量数据无卡顿动态加载,并且支持拖拽、点击和吸附功能
大量数据循固定Item复用
无限无遮罩动态加载
不规则子物体动态循环加载
有遮罩无卡顿加载
思路:并没有使用UGUI的ScrollRect组件,摆放几张卡片,通过移动和缩放来实现
usingUnityEngine;usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine.UI;publicclassEnhancelScrollView : MonoBehaviour{// 缩放曲线publicAnimationCurve scaleCurve;// 位移曲线publicAnimationCurve positionCurve;// 位移系数publicfloatposCurveFactor =500.0f;// y轴坐标固定值(所有的item的y坐标一致)publicfloatyPositionValue =46.0f;// 添加到EnhanceScrollView的目标对象publicList
有遮罩无卡顿加载
思路:协程加载,先加载屏幕显示的数量,然后返回一帧在继续加载,防止出现数量太大卡顿的现象。
while(CardsList.Count > roleInfo.Count){ DestroyImmediate(CardsList[0].gameObject); CardsList.RemoveAt(0);}StartCoroutine(createRoleCards());privateIEnumeratorcreateRoleCards(){ List charInfos =newList(); charInfos.AddRange(roleInfo);intindex =0;for(inti =0; i < charInfos.Count; i++) { _createRoleCard(charInfos[i], index++);if(index %10==0)yieldreturnnull; }}privatevoid_createRoleCard(CLocalCharInfo roleInfo,intindex){ CUIPlayedCharCardWidget charCardWidget =null;if(CardsList.Count > index) { charCardWidget = CardsList[index]; }else{varobj = Instantiate(Resources.Load("Prefab/RoleCard"))asGameObject;if(obj ==null) { UnityEngine.Debug.LogError("有误");return; } obj.name = roleInfo.Name; charCardWidget = obj.GetComponent();if(charCardWidget ==null) { UnityEngine.Debug.LogError("有误");return; } obj.transform.parent = Obj_ScrollViewContent.transform; obj.transform.localScale = Vector3.one; CardsList.Add(charCardWidget); } CUIPlayedCharCardWidget.CUIContent uiContent =newCUIPlayedCharCardWidget.CUIContent(); uiContent.RoleInfo = roleInfo; uiContent.ScrollRectObj = m_ScrollRect; uiContent.FixGridRect = m_FixGrid; charCardWidget.InitContent(uiContent);}
支持ScrollRect拖拽或点击
思路:在卡片的Image上添加一个继承了IBeginDragHandler,IGradHandler,IEndDragHandler的脚本,重写接口里面的Drag事件方法。
usingUnityEngine;usingUnityEngine.EventSystems;usingUnityEngine.UI;namespace Mga{ [RequireComponent(typeof(Image))]publicclassCPlayedCardOnDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler {publicbooldragOnSurfaces =true;publicScrollRect m_ScrollRect =null;publicCFixGridRect m_FixGridRect =null;privateGameObject m_DraggingCard;privateRectTransform m_DraggingPlane;publicboolisVertical =false;privateboolisSelf =false;privateSystem.Action m_OnBeginDragCallBack =null;privateSystem.Action m_OnEndDragCallBack =null;privateSystem.Action m_OnBeginScroll =null;privateSystem.Action m_OnEndScroll =null;publicvoidInit(CLocalCharInfo roleInfo, System.Action beginCallBack =null, System.Action endCallBack =null, System.Action beginScroll =null, System.Action endScroll =null) { m_OnBeginDragCallBack = beginCallBack; m_OnEndDragCallBack = endCallBack; m_OnBeginScroll = beginScroll; m_OnEndScroll = endScroll; }publicvoidOnBeginDrag(PointerEventData eventData) { Vector2 touchDeltaPosition = Vector2.zero;#ifUNITY_EDITORfloatdelta_x = Input.GetAxis("Mouse X");floatdelta_y = Input.GetAxis("Mouse Y"); touchDeltaPosition =newVector2(delta_x, delta_y);#elifUNITY_ANDROID || UNITY_IPHONEtouchDeltaPosition = Input.GetTouch(0).deltaPosition;#endifif(isVertical) {if(Mathf.Abs(touchDeltaPosition.x) > Mathf.Abs(touchDeltaPosition.y)) { isSelf =true;varcanvas = FindInParents
如果想要实现拖拽到目标位置的检测,还要在目标位置放一个Image并且添加上继承了IDropHandler,IPointerEnterHandler,IPointerExitHanler的组件。
在ScrollRect物体上添加吸附功能组件,工程里面要使用DoTween插件
usingSystem.Collections.Generic;usingDG.Tweening;usingUnityEngine;usingUnityEngine.EventSystems;usingUnityEngine.UI;//TODO:当前只试应横向的ScrollRect,还需要扩展支持纵向publicclassCFixGridRect : MonoBehaviour, IEndDragHandler{publicGameObject content;publicScrollRect scorllRect;publicfloatitemWidth;privateRectTransform contentRectTf;privatefloatformalPosX =0;privatefloatcurrentPosX =0;privatefloathalfItemLength =0;voidStart() {if(itemWidth <=0) UnityEngine.Debug.LogError("请设置Item的宽度"); halfItemLength = itemWidth /2;this.contentRectTf =this.content.GetComponent(); }publicvoidOnEndDrag(PointerEventData eventData) {this.scorllRect.StopMovement(); Vector2 afterDragPagePos =this.content.transform.localPosition; currentPosX = afterDragPagePos.x;//当前拖动的位置 负if(scorllRect.horizontalNormalizedPosition <0|| scorllRect.horizontalNormalizedPosition >1)return;intcount = (int)(Mathf.Abs(currentPosX) / itemWidth);vartargetPos = -(float)(count * itemWidth);if(((float)(count * itemWidth + halfItemLength)) < Mathf.Abs(currentPosX)) { targetPos = -(float)((count +1) * itemWidth); } formalPosX = targetPos;this.contentRectTf.DOLocalMoveX(targetPos,.2f); }}
usingSystem.Collections.Generic;usingDG.Tweening;usingUnityEngine;usingUnityEngine.EventSystems;usingUnityEngine.UI;namespace Mga{publicenumDragDirection { Horizontal, Vertical, }publicclassCFixGridRectBase : MonoBehaviour, IEndDragHandler {publicclassCUIContent {publicGameObject ScrollRectContent;publicScrollRect m_ScorllRect;publicfloatItemSize;publicfloatItemSpaceLength;//间隙publicfloatMargin =0;//顶部边缘间隙publicDragDirection m_DragDirection = DragDirection.Vertical; }privateRectTransform contentRectTf;privatefloathalfItemLength =0;privateCUIContent m_uiContent =null;privateboolm_bWidgetReady =false;voidStart() { m_bWidgetReady =true; _initContent(); }publicvoidInitContent(CUIContent uiContent) { m_uiContent = uiContent;if(m_bWidgetReady) _initContent(); }privatevoid_initContent() {if(m_uiContent ==null)return;if(m_uiContent.ItemSize <=0) { UnityEngine.Debug.LogError("请设置Item的宽度");return; } halfItemLength = m_uiContent.ItemSize /2;this.contentRectTf = m_uiContent.ScrollRectContent.GetComponent(); }publicvoidOnEndDrag(PointerEventData eventData) { m_uiContent.m_ScorllRect.StopMovement(); Vector2 afterDragPagePos = m_uiContent.ScrollRectContent.transform.localPosition;varitemLength = m_uiContent.ItemSize + m_uiContent.ItemSpaceLength;if(m_uiContent.m_DragDirection == DragDirection.Horizontal) {varcurrentPosX = afterDragPagePos.x;//当前拖动的位置 负currentPosX -= m_uiContent.Margin;intcount = (int)(Mathf.Abs(currentPosX) / m_uiContent.ItemSize);if(m_uiContent.m_ScorllRect.horizontalNormalizedPosition <=0) {return; }elseif(m_uiContent.m_ScorllRect.horizontalNormalizedPosition >=1)//总数-当前显示的数量{return; }vartargetPosX = -(float)(count * itemLength);if(((float)(targetPosX + halfItemLength)) < Mathf.Abs(currentPosX)) { count++; targetPosX = -(float)(count * itemLength); }this.contentRectTf.DOLocalMoveX(targetPosX,.2f); }else{varcurrentPosY = afterDragPagePos.y;//当前拖动的位置 正currentPosY -= m_uiContent.Margin;intcount = (int)(Mathf.Abs(currentPosY) / itemLength);if(m_uiContent.m_ScorllRect.verticalNormalizedPosition <=0) {return; }elseif(m_uiContent.m_ScorllRect.verticalNormalizedPosition >=1)//总数-当前显示的数量{return; }vartargetPosY = (float)(count * itemLength);if(((float)(targetPosY + halfItemLength)) < Mathf.Abs(currentPosY)) { count++; targetPosY = (float)(count * itemLength); }this.contentRectTf.DOLocalMoveY(targetPosY,.2f); } } }}
如果代码创建AnimationCurve默认是曲线,如果想要直线效果,可以在面板里面设置,也可以代码设置,如果代码设置如下:
var curve2 = new AnimationCurve();var key1 = new Keyframe(0,0);key1.outTangent=1;var key2 = new Keyframe(1,1);key2.inTangent=1;curve2.AddKey(key1);curve2.AddKey(key2);curve2.postWrapMode= WrapMode.Loop;curve2.preWrapMode= WrapMode.Loop;
这样的话就是直线了。
网友评论