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
一直想把之前工作、学习时记录的文档整理到博客上,一方面温故而知新,一方面和大家一起学习 -程序小白

浙公网安备 33010602011771号