Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> unity,ngui做聊天系統

unity,ngui做聊天系統

編輯:關於Android編程

用ngui做聊天系統有個簡單的方法是用教程Exampl12裡的TextList來做聊天系統。 但顯然一個UILabel做的聊天系統拓展性不高,並且要做特殊點擊事件會變得很麻煩。   所以我們還是用一個UIScrollView下掛一個UITable,把UILabel和其他東西封裝成一個Prefab一個個加載到UITable來實現。   如果不考慮其他因素就是一個簡單的UIScrollView相信大家都沒什麼問題。   不過項目中會有兩個技術難點。 1.要實現圖文混排 2.如果對話多的話(比如世界頻道,每個玩家都可以發信息,很容易就一百條以上),肯定不能每個都實例化一個Prefab,所以UIScrollView要做循環加載。   所以本文主要講的是第二點.循環加載   循環加載的意思就是,比如一個聊天系統,在可顯示的范圍內,用最少的Prefab,通過改裡面的數值去顯示不同數據,而不是每一個數據實例化一個Prefab。   在ngui的教程裡就有教你怎麼用ngui的UIScrollView裡實現循環加載。 但是這裡有一個前提是。它用的是UIScrollView下掛UIGrid,UIGrid下掛Prefab。且每個Prefab的高度一致。 這樣可以准確的計算出最少需要多少個Prefab,現在滑動到哪個Prefab,且現在每個Prefab應該插入什麼數據。   但是像聊天這樣的系統,每個人發的每句話字數都不一樣,也就是每個UILabel的高度不一樣。這樣導致了上面的計算都無法實現。   所以本來做好的UIScrollView的循環加載就需要調整。   首先是不用UIGrid用UITable。因為UITable不要求每一行的間距統一   接著就是寫一個繼承UIScrollView的類來實現循環加載。我這裡叫CUIChatScrollView: UIScrollView   因為代碼比較復雜,在最後的時候在一次過放上代碼,這裡先講思路     首先按一般的循環加載我們要做的是知道這個UISCrollView最多同時要顯示多少個Prefab,我們總共有多少數據。每個Prefab多高。當最上一塊或最下一個滑出邊框就把它移到另一邊。   而由於現在高度不一,所以上面除了總共有多少數據是知道的其他都不能確定。   所以我們只能換種方式。   我們實例化足夠的數,通過設定兩個上線臨界值來判斷是否需要把Prefab移到另一邊,而不通過邊框計算。 通過索引index而不通過計算滑動位置與這個的比例來計算應該插入的數據的索引。     所以對於第一種可以做到的,最多同屏顯示6條數據的話,我們只用實例化7個Prefab,這種最優方案我們沒法使用。 我們只能預估一個值,實例化一個合適的數,比如每一個聊天語句只有一行的話,整個界面有多少條,然後再比這個數多一點。     在我的項目中上下最多顯示3條,不過我這裡也需要6條來實現循環加載。也就是實例化10個Prefab。 如果是文字只有一行的話我的像素是25,我的上下臨界值設為250. (這些數值都還可以再優化,我只是隨便取了一些數)     在原來一般的循環加載邏輯下,實例化10個Prefab,當向下滑動時的Prefab超過下邊框就移到另一邊,向上一樣。   而當前的Prefab應該插入什麼數據不再通過計算當前點擊position除於每個Prefab的高度interver來計算出index來插入數據。而是記錄下index,如果把上面的Prefab移到下面就index++。如果下面的移到上面就index--。 而因為index作為索引如果從0開始,而最下面的index就是index加實例化的Prefab數,我的就是10.     而原本計算目標position的方式也不能用了。原本滑動到頂端把prefab移到低端通過最下面的prefab加高度interver就能知道。 現在最下面的要通過先把文字放到UILabel,通過NGUI的函數NGUIMath.CalculateRelativeWidgetBounds計算UILabel的寬高,加上最下面的Prefab的position來確定位置。     大概思路是這樣     下面貼上代碼
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class CUIChatScrollView : UIScrollView
{

    public delegate void OnMoveCallBack();
    /// 
    /// 每次滑動結束的回調
    /// 
    public OnMoveCallBack mOnMoveCallback;

    public delegate void OnMoveNextPage(int pageindex);
    public OnMoveNextPage mOnMoveNextPage;

    private float mTopOffSetValue = 250;
    private float mBottomOffSetValue = 250;
    /// 
    /// 當前數據總數
    /// 
    private int mTotalCount = 0;
    /// 
    /// 子物體當前臨時坐標
    /// 
    private float mTempPosition = 0;
    /// 
    /// 子物體當前臨時相對坐標(與UIPanel偏移、DynamicComponentTran、自己本身坐標之和,如果UIpanel裁剪區域有偏移還需要加上UIPanel FinalClipRegion的偏移值(X或者Y))
    /// 
    private float mBorderValue = 0;
    /// 
    /// 當前顯示出來的物體列表
    /// 
    private List mCurrentComList = new List();
    /// 
    /// 當前循環臨時加載的列表(達到臨界值需要移動的Components)
    /// 
    private List mTempComList = new List();
    /// 
    ///  掛載UIGrid的組件物體,是components父物體,UIPanel子物體
    /// 
    private Transform DynamicComponentTran;
    /// 
    /// 當前ScrollView依賴的UIPanel
    /// 
    private UIPanel mUIPanel;
    /// 
    /// UIPanel最終的繪制區域、坐標
    /// 
    private Vector4 mPanelFinalClipRegion;
    /// 
    /// 是否需要請求下一頁數據(用於多數據分頁加載情況)
    /// 
    private bool bNeedReqNextPage;
    /// 
    /// 每頁的數量(用於分頁)
    /// 
    private int mPrePageNumber;
    /// 
    /// 是否是排行榜模式
    /// 
    private bool bIsRankModel;
    /// 
    /// 當前自己的排名
    /// 
    private int mCurrentMyRank;
    /// 
    /// 緩存開關
    /// 
    private Dictionary bHasRequestDic = new Dictionary();
    /// 
    /// 用於比較的X坐標
    /// 
    private float xPos;
    /// 
    /// 用於比較的Y坐標
    /// 
    private float yPos;
    /// 
    /// 是否需要3D顯示效果
    /// 
    private bool bShow3DStyle = false;
    /// 
    /// 居中的子物體
    /// 
    public Transform mCenterTranform;
    /// 
    /// 子物體的depath
    /// 
    private UIPanel mTempUIPanel;
    /// 
    ///  ScrollView 的UIPanel depath。
    /// 
    private int mUIPanelDepth = 1;

    private int m_Index = 0;
    private int m_maxShowNum = 0;

    public void Init(List components, int maxShowNum, int totalNumber, Transform dyTransorm, Movement moveMent = Movement.Horizontal, bool needrequest = false, int prepagenum = 0, bool isrank = false, int myrank = 0, bool bshow3d = false) where T : CBaseComponent
    {
        m_Index = maxShowNum-1;
        m_maxShowNum = maxShowNum;
        mCurrentComList.Clear();
        for (int i = 0, length = components.Count; i < length; i++)
        {
            if (components[i] is CBaseComponent)
            {
                mCurrentComList.Add(components[i]);
            }
        }
        //mCurrentComList = components as List;
        DynamicComponentTran = dyTransorm;
        mTotalCount = totalNumber;
        movement = moveMent;
        mPanelFinalClipRegion = (mUIPanel ?? (mUIPanel = gameObject.GetComponent())).finalClipRegion;
        mUIPanelDepth = mUIPanel.depth + 10;//子物體固定高出父物體深度10個單位
        //if (movement == Movement.Vertical)
        //    mOffSetValue = mPanelFinalClipRegion.w / 2 + mItemIntervalValue / 2f;
        //else if (moveMent == Movement.Horizontal)
        //    mOffSetValue = mPanelFinalClipRegion.z / 2 + mItemIntervalValue / 2f;
        bNeedReqNextPage = needrequest;
        mPrePageNumber = prepagenum;
        bIsRankModel = isrank;
        mCurrentMyRank = myrank;
        bHasRequestDic.Clear();
        bShow3DStyle = bshow3d;
        momentumAmount = 35f;
    }

    public override void MoveRelative(Vector3 relative)
    {
        base.MoveRelative(relative);
        CheckScrollView(relative);
    }

    public override void AdjustSpring(Vector3 relative)
    {
        base.AdjustSpring(relative);
        CheckScrollView(relative);
    }

    private void CheckScrollView(Vector3 relative)
    {
        if (mCurrentComList == null || mCurrentComList.Count == 0)
            return;

        if (movement == Movement.Horizontal)
        {
            xPos = relative.x;
            mCurrentComList.Sort(delegate (CBaseComponent a, CBaseComponent b) { return a.LocalPosition.x.CompareTo(b.LocalPosition.x); });
        }
        else if (movement == Movement.Vertical)
        {
            yPos = relative.y;
            mCurrentComList.Sort(delegate (CBaseComponent a, CBaseComponent b) { return b.LocalPosition.y.CompareTo(a.LocalPosition.y); });
        }

        mTempComList.Clear();

        if ((yPos > 0 && movement == Movement.Vertical) || (xPos < 0 && movement == Movement.Horizontal))
        {
            Transform temptran = mCurrentComList[mCurrentComList.Count - 1].ComTransform;
            if (movement == Movement.Horizontal)
                mTempPosition = temptran.localPosition.x;
            else if (movement == Movement.Vertical)
                mTempPosition = temptran.localPosition.y;
            mTempPosition = Mathf.Abs(mTempPosition);

            if (true)
            {
                for (int i = 0, j = mCurrentComList.Count; i < j; i++)
                {
                    temptran = mCurrentComList[i].ComTransform;
                    if (movement == Movement.Horizontal)
                    {
                        mBorderValue = (temptran.localPosition.x*temptran.localScale.x + transform.localPosition.x + DynamicComponentTran.localPosition.x + Mathf.Abs(mPanelFinalClipRegion.x));
                        if (mBorderValue > -mTopOffSetValue)
                        {
                            break;
                        }
                    }
                    else if (movement == Movement.Vertical)
                    {
                        mBorderValue = (temptran.localPosition.y * temptran.localScale.y + transform.localPosition.y + DynamicComponentTran.localPosition.y + Mathf.Abs(mPanelFinalClipRegion.y));
                        if (mBorderValue < mTopOffSetValue)
                        {
                            break;
                        }
                    }
                    mTempComList.Add(mCurrentComList[i]);

                }
            }
            for (int i = 0, j = mTempComList.Count; i < j; i++)
            {
                if (m_Index >= mTotalCount - 1) break;
                m_Index++;
                if (movement == Movement.Vertical)
                {
                    float spriteHeight = NGUIMath.CalculateRelativeWidgetBounds(transform, mCurrentComList[mCurrentComList.Count - 1].ComTransform, true).size.y;
                    mTempComList[i].LocalPosition = new Vector3(0, -(spriteHeight +mTempPosition), 0);
                }
                //mTempComList[i].LocalPosition = new Vector3(0, -(mItemIntervalValue * (i + 1) + mTempPosition), 0);
                mTempComList[i].InitData(m_Index);
            }
        }
        else if ((yPos < 0 && movement == Movement.Vertical) || (xPos > 0 && movement == Movement.Horizontal))
        {
            Transform temptran = mCurrentComList[0].ComTransform;
            if (movement == Movement.Horizontal)
                mTempPosition = temptran.localPosition.x;
            else if (movement == Movement.Vertical)
                mTempPosition = temptran.localPosition.y;
            mTempPosition = Mathf.Abs(mTempPosition);

            if (true)
            {
                for (int i = mCurrentComList.Count - 1; i >= 0; i--)
                {
                    temptran = mCurrentComList[i].ComTransform;
                    if (movement == Movement.Horizontal)
                    {
                        mBorderValue = (temptran.localPosition.x + transform.localPosition.x + DynamicComponentTran.localPosition.x + Mathf.Abs(mPanelFinalClipRegion.x));
                        if (mBorderValue  -mBottomOffSetValue)
                        {
                            break;
                        }
                    }
                    mTempComList.Add(mCurrentComList[i]);
                }
            }
            for (int i = 0, j = mTempComList.Count; i < j; i++)
            {
                if (m_Index <= m_maxShowNum-1) break;

                m_Index--;

                //mTempComList[i].LocalPosition = new Vector3(0, -(mTempPosition - mItemIntervalValue * (i + 1)), 0);
                mTempComList[i].InitData(m_Index - m_maxShowNum+1);

                if (movement == Movement.Vertical)
                {
                    float spriteHeight = NGUIMath.CalculateRelativeWidgetBounds(transform, mTempComList[i].ComTransform, true).size.y;
                    Vector3 newPosition;
                    if (i == 0)
                        newPosition = new Vector3(0, -(mTempPosition - spriteHeight), 0);
                    else
                        newPosition = new Vector3(0, -(Mathf.Abs(mTempComList[i - 1].LocalPosition.y) - spriteHeight), 0);
                    mTempComList[i].LocalPosition = newPosition;
                }
            }
        }
        if (mOnMoveCallback != null)
        {
            mOnMoveCallback();
        }
    }


}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved