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

  

posted @ 2020-08-06 11:26  柯腾_wjf  阅读(577)  评论(0编辑  收藏  举报