标签:
用ngui做聊天系统有个简单的方法是用教程Exampl12里的TextList来做聊天系统。
但显然一个UILabel做的聊天系统拓展性不高,并且要做特殊点击事件会变得很麻烦。
所以我们还是用一个UIScrollView下挂一个UITable,把UILabel和其他东西封装成一个Prefab一个个加载到UITable来实现。
如果不考虑其他因素就是一个简单的UIScrollView相信大家都没什么问题。
不过项目中会有两个技术难点。
1.要实现图文混排
2.如果对话多的话(比如世界频道,每个玩家都可以发信息,很容易就一百条以上),肯定不能每个都实例化一个Prefab,所以UIScrollView要做循环加载。
1.关于图文混排在之前的文章中就讲到怎么实现
http://www.cnblogs.com/chrisfxs/p/5737607.html
所以本文主要讲的是第二点.循环加载
循环加载的意思就是,比如一个聊天系统,在可显示的范围内,用最少的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();
- /// <summary>
- /// 每次滑动结束的回调
- /// </summary>
- public OnMoveCallBack mOnMoveCallback;
-
- public delegate void OnMoveNextPage(int pageindex);
- public OnMoveNextPage mOnMoveNextPage;
-
- private float mTopOffSetValue = 250;
- private float mBottomOffSetValue = 250;
- /// <summary>
- /// 当前数据总数
- /// </summary>
- private int mTotalCount = 0;
- /// <summary>
- /// 子物体当前临时坐标
- /// </summary>
- private float mTempPosition = 0;
- /// <summary>
- /// 子物体当前临时相对坐标(与UIPanel偏移、DynamicComponentTran、自己本身坐标之和,如果UIpanel裁剪区域有偏移还需要加上UIPanel FinalClipRegion的偏移值(X或者Y))
- /// </summary>
- private float mBorderValue = 0;
- /// <summary>
- /// 当前显示出来的物体列表
- /// </summary>
- private List<CBaseComponent> mCurrentComList = new List<CBaseComponent>();
- /// <summary>
- /// 当前循环临时加载的列表(达到临界值需要移动的Components)
- /// </summary>
- private List<CBaseComponent> mTempComList = new List<CBaseComponent>();
- /// <summary>
- /// 挂载UIGrid的组件物体,是components父物体,UIPanel子物体
- /// </summary>
- private Transform DynamicComponentTran;
- /// <summary>
- /// 当前ScrollView依赖的UIPanel
- /// </summary>
- private UIPanel mUIPanel;
- /// <summary>
- /// UIPanel最终的绘制区域、坐标
- /// </summary>
- private Vector4 mPanelFinalClipRegion;
- /// <summary>
- /// 是否需要请求下一页数据(用于多数据分页加载情况)
- /// </summary>
- private bool bNeedReqNextPage;
- /// <summary>
- /// 每页的数量(用于分页)
- /// </summary>
- private int mPrePageNumber;
- /// <summary>
- /// 是否是排行榜模式
- /// </summary>
- private bool bIsRankModel;
- /// <summary>
- /// 当前自己的排名
- /// </summary>
- private int mCurrentMyRank;
- /// <summary>
- /// 缓存开关
- /// </summary>
- private Dictionary<int, bool> bHasRequestDic = new Dictionary<int, bool>();
- /// <summary>
- /// 用于比较的X坐标
- /// </summary>
- private float xPos;
- /// <summary>
- /// 用于比较的Y坐标
- /// </summary>
- private float yPos;
- /// <summary>
- /// 是否需要3D显示效果
- /// </summary>
- private bool bShow3DStyle = false;
- /// <summary>
- /// 居中的子物体
- /// </summary>
- public Transform mCenterTranform;
- /// <summary>
- /// 子物体的depath
- /// </summary>
- private UIPanel mTempUIPanel;
- /// <summary>
- /// ScrollView 的UIPanel depath。
- /// </summary>
- private int mUIPanelDepth = 1;
-
- private int m_Index = 0;
- private int m_maxShowNum = 0;
-
- public void Init<T>(List<T> 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<CBaseComponent>;
- DynamicComponentTran = dyTransorm;
- mTotalCount = totalNumber;
- movement = moveMent;
- mPanelFinalClipRegion = (mUIPanel ?? (mUIPanel = gameObject.GetComponent<UIPanel>())).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;
- }
- }
- else if (movement == Movement.Vertical)
- {
- mBorderValue = (temptran.localPosition.y + transform.localPosition.y + DynamicComponentTran.localPosition.y + Mathf.Abs(mPanelFinalClipRegion.y));
- 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();
- }
- }
-
-
- }
【小松教你手游开发】【系统模块开发】ngui做聊天系统
标签:
原文地址:http://www.cnblogs.com/chrisfxs/p/5737800.html