NGUI 实现广告页的自动、拖动翻页功能
本篇滑动原理是监听NGUI的UIScrollView的滑动事件onDragStarted、onStoppedMoving、onDragFinished(OnStoppedMoving有几率不触发),UGUI可以用easyTouch等插件监听。
逻辑也很简单,onDragStarted记录开始滑动的位置,onStoppedMoving计算出本次滑动的距离offset,如果offset大于某个边界值EffortsFlip,进行翻页处理,否则还原当前页。逻辑在onMomentumMove方法。
这边没有实现动态加载广告页,因为需求是最多5个广告页轮询,需要的可以自行扩展。理论上是可以用3个广告页gameobject实现n个广告页的切换的。
这边不涉及业务逻辑(广告页可能不只是一张图,显示逻辑可能更复杂),每次分页变化都通过SetIndexPage发送事件ON_DRAG_PAGE_CHANGE通知业务。
实现的大致效果:实现左右翻页、底部跳转指定页面、滑动翻页。
先上源码:
/// <summary> /// NGUI拖动翻页 /// 如果autoSwitch为true,会间隔switchInterval翻一页,翻页方向从第一页到最后一页顺序播放,然后从最后一页到第一页逆序播放 /// </summary> public class UIDragPage : MonoBehaviour { /// /// 每页宽度 /// public float pageWidth; /// /// 翻页力度,拖动距离大于该值才算翻页 /// public int EffortsFlip = 50; /// /// 总页数 /// public int pageNums = 0; /// <summary> /// 自动播放切页 /// </summary> public bool autoSwitch = true; /// /// 当前所在页 /// public int pageIndex { get { return mPageIndex; } set { if(mPageIndex == value) return; value = Mathf.Clamp(value, 1, pageNums); if (isHorizontal) { Page((value - mPageIndex) * - pageWidth); } else { Page((value - mPageIndex) * pageWidth); } } } /// /// 当前所在页 /// private int mPageIndex = 1; private UIScrollView mScrollView = null; private float nowLocation = 0; //拖动开始的坐标,用于计算本次拖动的距离 private bool isDrag = false; private bool isSpringMove = false; private SpringPanel mSp = null; private bool isHorizontal = true; private float lastSwitch = 0; private int switchInterval = 4;//自动切换间隔 private bool isForward = true;//自动翻页方向 private BoxCollider boxMask;//防止自动更新时和玩家滑动冲突 void Awake() { boxMask = gameObject.GetComponent<BoxCollider>(); if(boxMask == null) { boxMask = gameObject.AddComponent<BoxCollider>(); } mScrollView = gameObject.GetComponent<UIScrollView>(); if(mScrollView == null) { mScrollView = gameObject.AddComponent<UIScrollView>(); } mScrollView.onDragStarted = OnDragStarted; mScrollView.onStoppedMoving = onStoppedMoving; mScrollView.onDragFinished = onStoppedMoving; if (mScrollView.movement == UIScrollView.Movement.Horizontal) { isHorizontal = true; } else { isHorizontal = false; } onStoppedMoving(); } private void Update() { if (!autoSwitch) return; if(isDrag || isSpringMove) return;//更新和移动中不更新 if (lastSwitch >= switchInterval) { if (isForward) { if (pageIndex == pageNums) { isForward = false; pageIndex = pageNums - 1; } else { pageIndex = pageIndex + 1; } } else { if (pageIndex == 1) { isForward = true; pageIndex = 2; } else { pageIndex = pageIndex - 1; } } } lastSwitch += Time.deltaTime; } void OnDragStarted() { isDrag = true; SetNowLocation(); } void onStoppedMoving() { onMomentumMove(); isDrag = false; SetNowLocation(); } /// <summary> /// 处理移动事件,当拖动距离大于EffortsFlip才算翻页,否则复原位置 /// </summary> void onMomentumMove() { if (!isDrag) return; Vector3 v3 = transform.localPosition; float value = 0; if (isHorizontal) { value = nowLocation - v3.x; if (Mathf.Abs(value) < EffortsFlip) { Page(0); } else { if (value > 0) { if (mPageIndex < pageNums) Page(-pageWidth); } else { if (mPageIndex > 1) Page(pageWidth); } } } else { value = nowLocation - v3.y; if (Mathf.Abs(value) < EffortsFlip) { Page(0); } else { if (value > 0) { if (mPageIndex > 1) Page(-pageWidth); } else { if (mPageIndex < pageNums) Page(pageWidth); } } } } void Page(float value) { isSpringMove = true; boxMask.enabled = true; mSp = GetComponent<SpringPanel>(); if (mSp == null)mSp = gameObject.AddComponent<SpringPanel>(); //mSp.enabled = false; Vector3 pos = mSp.target; pos = isHorizontal ? new Vector3(pos.x + value, pos.y, pos.z) : new Vector3(pos.x, pos.y + value, pos.z); if (!SetIndexPage(pos)) return; SpringPanel.Begin(gameObject, pos, 8f); mSp.onFinished = SpringPanleMoveEnd; Debug.Log("page index="+mPageIndex); } bool SetIndexPage(Vector3 v3) { float value = isHorizontal ? v3.x : v3.y; //Debug.Log((pageNums - 1) * pageWidth); if(isHorizontal) { if (value > 0 || value < (pageNums - 1) * -pageWidth) return false; } else { if (value < 0 || value > (pageNums - 1) * pageWidth) return false; } value = Mathf.Abs(value); mPageIndex = (int)(value / pageWidth) + 1; lastSwitch = 0; LuaEventMgr.Instance.CallFunc(LuaEventDefine.ON_DRAG_PAGE_CHANGE, mPageIndex); return true; } void SpringPanleMoveEnd() { isSpringMove = false; boxMask.enabled = false; } void SetNowLocation() { if (isHorizontal) { nowLocation = gameObject.transform.localPosition.x; } else { nowLocation = gameObject.transform.localPosition.y; } } #region 公共接口 /// /// 上一页 /// public void PreviousPage() { if (isHorizontal) { if (mPageIndex > 1) Page(pageWidth); } else { if (mPageIndex < pageNums) Page(pageWidth); } } /// /// 下一页 /// public void NextPage() { if (isHorizontal) { if (mPageIndex < pageNums) Page(-pageWidth); } else { if (mPageIndex > 1) Page(-pageWidth); } } #endregion // Test #if UNITY_EDITOR [ContextMenu("上一页")] void GoPrevious() { PreviousPage(); } [ContextMenu("下一页")] void GoNext() { NextPage(); } [ContextMenu("跳转指定页")] void GoAssignPage() { pageIndex = 4; } #endif }
使用方法就比较糙了,直接获取了广告页的对象进行广告图、点击事件设置。
function SpecialSupplyPanel:InitAd() self._adsConfig = importTable("activity_ad") self._adBtnImg = {} local adCount = #self._adsConfig self._dragPage.pageNums = adCount--设置分页数量 for i = 1, MaxAdCount do local isShow = adCount >= i local objBtn = self["BtnAd" .. i].gameObject local objImg = self["TexAD" .. i] objBtn:SetActive(isShow) objImg:SetActive(isShow) if isShow then CS.UIEventListener.Get(objBtn).onClick = function () self:BtnADSwitchClick(i)--设置指定广告页点击事件 end self._adBtnImg[i] = objBtn:GetComponent("UISprite") self:SetAdBtnImage(i, false) local texName = self._adsConfig[i].image local bgPath = "ShopBanner/" .. texName ResourcesManager:LoadUITextureAsync(bgPath, function (data) objImg.TexturePath = "" objImg.mainTexture = data --设置广告页贴图 end) CS.UIEventListener.Get(objImg.gameObject).onClick = function() self:BtnADClick(i)--设置广告页点击事件 end end end end
一直想把之前工作、学习时记录的文档整理到博客上,一方面温故而知新,一方面和大家一起学习 -程序小白