`

NGUI所见即所得之UIAnchor & UIStretch

 
阅读更多

       NGUI所见即所得之UIAnchor & UIStretch

       NGUI的Example/Scenes/Example1介绍的主要就是UIRoot,UIAnchor和UIStretch这三个脚本,当然UIRoot是每个UI都会有的(挂在根节点),之前D.S.Qiu也写过博客介绍过UIRoot(猛点查看)。一直都对NGUI把Unity的单位和像素的转换和统一都很有疑惑,因之手游项目要做UI的自适应,就觉得很有必要把UIAnchor和UIStretch深入的研究下。

        UIRoot在D.S.Qiu的第一篇NGUI的文章中介绍了(猛点查看),UIRoot其实就做了一件事情:根据Screen.height和UIRoot.activeHeight的比例来调整UIRoot的loaclScal,从而保证UIWidget(UISprite,UILabel)可以按照其本身的大小进行设置,而不用经过复杂的换算过程。

         UIAnchor和UIStretch处理上的细节很相似,都是先计算参照对象(这个参照对象由Insprector的Container指定,如果没有选择,就是Camera)的大小Rect,然后根据参数UIAnchor(Side,relativeOffset,pixelOffset),UIStretch(Style,relativeSize,initialSize,borderPadding)进行调整,最后设置对应的属性,只不过UIAnchor设置的是transform.position,UIStretch设置的是(width,height)或clipRange等。

 

UIAnchor

        先看下UIAnchor的Inspector界面,感觉很简单,不会像UIPanel那么复杂:

        Container:指定Anchor的参照点,如果没有选择,则以Camera的pixelRect的区域为参照面

        Side:Anchor的定位方式

        Relative Offset:相对于Camera,或Container的百分比偏移

        Pixel Offset:像素的偏移

        /// <summary>
	/// Relative offset value, if any. For example "0.25" with 'side' set to Left, means 25% from the left side.
	/// </summary>
	public Vector2 relativeOffset = Vector2.zero;
	
	/// <summary>
	/// Pixel offset value if any. For example "10" in x will move the widget 10 pixels to the right 
	/// while "-10" in x is 10 pixels to the left based on the pixel values set in UIRoot.
	/// </summary>
	public Vector2 pixelOffset = Vector2.zero;

 Update函数

       UIAnchor的主要功能实现都在Update函数:

void Update ()
	{
		if (mAnim != null && mAnim.enabled && mAnim.isPlaying) return;
		bool useCamera = false;
		UIWidget wc = (container == null) ? null : container.GetComponent<UIWidget>();
		UIPanel pc = (container == null && wc == null) ? null : container.GetComponent<UIPanel>();
		if (wc != null)
		{
			Bounds b = wc.CalculateBounds(container.transform.parent);

			mRect.x = b.min.x;
			mRect.y = b.min.y;

			mRect.width = b.size.x;
			mRect.height = b.size.y;
		}
		else if (pc != null)
		{
			if (pc.clipping == UIDrawCall.Clipping.None)
			{
				// Panel has no clipping -- just use the screen's dimensions
				float ratio = (mRoot != null) ? (float)mRoot.activeHeight / Screen.height * 0.5f : 0.5f;
				mRect.xMin = -Screen.width * ratio;
				mRect.yMin = -Screen.height * ratio;
				mRect.xMax = -mRect.xMin;
				mRect.yMax = -mRect.yMin;
			}
			else
			{
				// Panel has clipping -- use it as the mRect
				Vector4 pos = pc.clipRange;
				mRect.x = pos.x - (pos.z * 0.5f);
				mRect.y = pos.y - (pos.w * 0.5f);
				mRect.width = pos.z;
				mRect.height = pos.w;
			}
		}
		else if (container != null)
		{
			Transform root = container.transform.parent;
			Bounds b = (root != null) ? NGUIMath.CalculateRelativeWidgetBounds(root, container.transform) :
				NGUIMath.CalculateRelativeWidgetBounds(container.transform);

			mRect.x = b.min.x;
			mRect.y = b.min.y;

			mRect.width = b.size.x;
			mRect.height = b.size.y;
		}
		else if (uiCamera != null)
		{
			useCamera = true;
			mRect = uiCamera.pixelRect;
		}
		else return;

		float cx = (mRect.xMin + mRect.xMax) * 0.5f;
		float cy = (mRect.yMin + mRect.yMax) * 0.5f;
		Vector3 v = new Vector3(cx, cy, 0f);

		if (side != Side.Center)
		{
			if (side == Side.Right || side == Side.TopRight || side == Side.BottomRight) v.x = mRect.xMax;
			else if (side == Side.Top || side == Side.Center || side == Side.Bottom) v.x = cx;
			else v.x = mRect.xMin;

			if (side == Side.Top || side == Side.TopRight || side == Side.TopLeft) v.y = mRect.yMax;
			else if (side == Side.Left || side == Side.Center || side == Side.Right) v.y = cy;
			else v.y = mRect.yMin;
		}

		float width = mRect.width;
		float height = mRect.height;

		v.x += pixelOffset.x + relativeOffset.x * width;
		v.y += pixelOffset.y + relativeOffset.y * height;

		if (useCamera)
		{
			if (uiCamera.orthographic)
			{
				v.x = Mathf.Round(v.x);
				v.y = Mathf.Round(v.y);

				if (halfPixelOffset && mNeedsHalfPixelOffset)
				{
					v.x -= 0.5f;
					v.y += 0.5f;
				}
			}

			v.z = uiCamera.WorldToScreenPoint(mTrans.position).z;
			v = uiCamera.ScreenToWorldPoint(v);
		}
		else
		{
			v.x = Mathf.Round(v.x);
			v.y = Mathf.Round(v.y);

			if (pc != null)
			{
				v = pc.cachedTransform.TransformPoint(v);
			}
			else if (container != null)
			{
				Transform t = container.transform.parent;
				if (t != null) v = t.TransformPoint(v);
			}
			v.z = mTrans.position.z;
		}

		// Wrapped in an 'if' so the scene doesn't get marked as 'edited' every frame
		if (mTrans.position != v) mTrans.position = v;
		if (runOnlyOnce && Application.isPlaying) Destroy(this);
	}

       Update的原理很简单,梳理归纳为4部分:

                 1)获取Anchor参照对象的大小Rect以及计算中心点Vector3 v;

                 2)根据Side类型调整v的x,y,z值;

                 3)将v转换成世界坐标

                 4)将v赋给mTrans.position。

        这里对1)再多说几句,主要是涉及参照对象的选取问题,用if - else if来筛选的次序是 UIWidget wc , UIPanel pc , GameObject container, Camera uiCamera,如果前者部位null这取前者的大小后面的就不予考虑。

                UIWidget wc = (container == null) ? null : container.GetComponent<UIWidget>();
		UIPanel pc = (container == null && wc == null) ? null : container.GetComponent<UIPanel>();

 

像素与Unity单位

        之前项目中使用的NGUI版本还是2.6.3,那个版本还没有pixelOffset,然后为了实现一个相对便宜就在挂载Anchor的对象下面挂载一个子对象,通过设置子对象的loaclPosition来设置相对偏移:

      这样用transform.find去查找某一个子对象的时候就会觉得很蛋疼,所以当看到pixelOffset的就觉得没有必要用offset这层节点了,这可以说是NGUI埋下隐形的坑(很多没有“爱参考”不思考的开发者,就喜欢照搬别人的东西),之前的项目就是这样的,看了一堆Offset,完全没有必要。然后果断测试就会有以下不同的情况。

      测试之前首先将上面Bottom/Offset的localPosition置0,并修改稿Bottom的UIAnchor的pixelOffset改为(0,40)

1)当参照对象是Camera时,即Container=null:

但当编辑器的分辨率等于某个值时,又回恢复正常情况:


 

2)把Bottom的父对象UIPanel拖给UIAnchor的Container:

这种情况是没有问题的:


 

       回过头看下Update函数中对pixelOffset的使用:

		v.x += pixelOffset.x + relativeOffset.x * width;
		v.y += pixelOffset.y + relativeOffset.y * height;

        经过反复的思考,觉得一定是pixelOffset和子对象Offset的localPosition数值的参考系是不一样的,但最终都是通过mRect来处理的,所以把UIAnchor Rect mRect设置成public,查看mRect的值,上面三个情况对应mRect值分别如下:



      这说明,当mRect.y大于等于800的时候,使用UIAnchor的pixelOffset和使用子对象Offset的localPosition的表现是一致的。但为什么指定Container为UIPanel都不会出现异常情况,只有Camera会出现。再回到Update看下获取mRect的方法,指定Container时,mRect实际是UIPanel,或UIWideget的像素大小,其实是UIWidget的(width,height),而没有指定Container情况下,mRect = camera.pixelRect。

      在UIRoot文中,就说过camera.pixelRect其实就是Screen的(width,height),也就是说,camera.pixelRect是会根据显示器的分辨率动态改变的,而指定Container时,mRect是不会改变的(在介绍UIRoot文中有介绍)。

       在看下pixelOffset的使用(真的是最后一次了):

		v.x += pixelOffset.x + relativeOffset.x * width;
		v.y += pixelOffset.y + relativeOffset.y * height;

       虽然pixelOffset的值一直没有变化,但是当mRect = camera.pixelCamera时,mRect是随着分辨率的变化而变化的,那样的话pixelOffset占的权重就会改变了,所以才会出现上面的偏移异常。

       

解决策略

       在UIAnchor中设置一个参数unitOffset来代替子对象Offset的功能:

    public Vector2 unitOffset = Vector2.zero;

       然后把设置的值在Update函数的最后加个 mTrans.localPosition += new Vector3(unitOffset.x,unitOffset.y,0);

	void Update()
        {	
                //省略前面的处理。。。
                // Wrapped in an 'if' so the scene doesn't get marked as 'edited' every frame
		if (mTrans.position != v) mTrans.position = v;
        mTrans.localPosition += new Vector3(unitOffset.x,unitOffset.y,0);
		if (runOnlyOnce && Application.isPlaying) Destroy(this);
        }

        这样就可以轻松取得GameObject树中Offset一层,之前项目中就有这个一层,我看着就来火,终于干掉了哈……

 

        还有一个问题:为什么当camera.pixelRect.y等于800时,就会恢复正常,这个先看下UIRoot的设置(对UIRoot原理不了解请猛击):

        Manual Height设置为800,Scaling Style设置为FixedSize,可以知道UI的放缩参考高度就是 800,即实际UI布局高度就是800,这里有点难理解,总之就是当屏幕分辨率高度等于800时,pixelOffset和子对象Offset的localPostion参考点就一致了,实际效果就一样了。也可以这么解释:当mRect = camera.pixelRect 时,pixeloffset的值是相对于camera.pixelRect而言的,在屏幕的呈现是会对着屏蔽的分辨率不同而改变的;而使用子对象Offset的localPosition的参照和UI组件是一致的,所以相对于Contaner的位置是不会改变的。

        回到文中开头抛出的一个问题——Unity中transfrom的单位和像素的关系,上张图片,可以知道UI的高度实际高度是800,然后看下Anchor - Top 和Anchor - Bottom的transform的localPostion.y分别是400.5006和-399.4994(图片如下),发现两者区间刚好是800,这就说明NGUI的架构中像素坐标和Unity的单位是一致的,对等的,即一个Unity单位等于一个像素。

UIStretch

       看下NGUI Example1 的Anchor - Stretch的Inspector面板,发现UIStretch只比UIAnchor多了一个参数,不过从这张图UISprite的Dimension(红框标出)的长度始终都是800,不管屏幕如何改变大小,都是800个像素,填充的Tiled图片个数也是一样的,这也更加说明了上面提到的一个结论:NGUI中Unity的单位和像素是同一的。

 Update

       UIStretch的Update函数的前面部分跟UIAnchor的Update的前面部分原理是一样的都是获取mRect,所以只看后一部分的实现(理解 relativeSize 和 initialSize 的含义和作用):

void Update()
{
                        //.......省略上面的处理
			float rectWidth = mRect.width;
			float rectHeight = mRect.height;

			if (adjustment != 1f && rectHeight > 1f)
			{
				float scale = mRoot.activeHeight / rectHeight;
				rectWidth *= scale;
				rectHeight *= scale;
			}

			Vector3 size = (mWidget != null) ? new Vector3(mWidget.width, mWidget.height) : mTrans.localScale;

			if (style == Style.BasedOnHeight)
			{
				size.x = relativeSize.x * rectHeight;
				size.y = relativeSize.y * rectHeight;
			}
			else if (style == Style.FillKeepingRatio)
			{
				// Contributed by Dylan Ryan
				float screenRatio = rectWidth / rectHeight;
				float imageRatio = initialSize.x / initialSize.y;

				if (imageRatio < screenRatio)
				{
					// Fit horizontally
					float scale = rectWidth / initialSize.x;
					size.x = rectWidth;
					size.y = initialSize.y * scale;
				}
				else
				{
					// Fit vertically
					float scale = rectHeight / initialSize.y;
					size.x = initialSize.x * scale;
					size.y = rectHeight;
				}
			}
			else if (style == Style.FitInternalKeepingRatio)
			{
				// Contributed by Dylan Ryan
				float screenRatio = rectWidth / rectHeight;
				float imageRatio = initialSize.x / initialSize.y;

				if (imageRatio > screenRatio)
				{
					// Fit horizontally
					float scale = rectWidth / initialSize.x;
					size.x = rectWidth;
					size.y = initialSize.y * scale;
				}
				else
				{
					// Fit vertically
					float scale = rectHeight / initialSize.y;
					size.x = initialSize.x * scale;
					size.y = rectHeight;
				}
			}
			else
			{
				if (style != Style.Vertical)
					size.x = relativeSize.x * rectWidth;

				if (style != Style.Horizontal)
					size.y = relativeSize.y * rectHeight;
			}

			if (mSprite != null)
			{
				float multiplier = (mSprite.atlas != null) ? mSprite.atlas.pixelSize : 1f;
				size.x -= borderPadding.x * multiplier;
				size.y -= borderPadding.y * multiplier;

				if (style != Style.Vertical)
					mSprite.width = Mathf.RoundToInt(size.x);

				if (style != Style.Horizontal)
					mSprite.height = Mathf.RoundToInt(size.y);

				size = Vector3.one;
			}
			else if (mWidget != null)
			{
				if (style != Style.Vertical)
					mWidget.width = Mathf.RoundToInt(size.x - borderPadding.x);

				if (style != Style.Horizontal)
					mWidget.height = Mathf.RoundToInt(size.y - borderPadding.y);

				size = Vector3.one;
			}
			else if (mPanel != null)
			{
				Vector4 cr = mPanel.clipRange;

				if (style != Style.Vertical)
					cr.z = size.x - borderPadding.x;
				
				if (style != Style.Horizontal)
					cr.w = size.y - borderPadding.y;
				
				mPanel.clipRange = cr;
				size = Vector3.one;
			}
			else
			{
				if (style != Style.Vertical)
					size.x -= borderPadding.x;
				
				if (style != Style.Horizontal)
					size.y -= borderPadding.y;
			}
			
			if (mTrans.localScale != size)
				mTrans.localScale = size;

			if (runOnlyOnce && Application.isPlaying) Destroy(this);
}

 整体放缩

     分析了 UIStretch 的 Update ,可以知道当 UIStretch 挂载的GameObject,有UIWidget,UISprite,UIPanel 这个几个脚本是,是不会放缩这个GameObject的子GameObject的,如果要整体放缩的话,就得通过倒数第二行: 

mTrans.localScale = size;  

       如果 Style 选择为 Both ,并且没有指定Container 且GameObject 上没有挂载UIWidget,UISprite,UIPanel ,抽出主要的执行代码:

void Update()
{
                        //省略前面的代码
                       else if (uiCamera != null)
			{
				mRect = uiCamera.pixelRect;
				if (mRoot != null) adjustment = mRoot.pixelSizeAdjustment;
			}
			else return;

			float rectWidth = mRect.width;
			float rectHeight = mRect.height;

			if (adjustment != 1f && rectHeight > 1f)
			{
				float scale = mRoot.activeHeight / rectHeight;
				rectWidth *= scale;
				rectHeight *= scale;
			}

                        //省略 代码
                        else
			{
				if (style != Style.Vertical)
					size.x = relativeSize.x * rectWidth;

				if (style != Style.Horizontal)
					size.y = relativeSize.y * rectHeight;
			}
                        //省略 代码
                        if (mTrans.localScale != size)
				mTrans.localScale = size;
}

       整理下: mTrans.localScale.x = relativeSize.x * rectWidth * mRoot.activeHeight / rectHeight

mTrans.localScale.y = relativeSize.y * rectHeight * mRoot.activeHeight / rectHeight = relativeSize.y * mRoot .activeHeight

       因为 UIRoot 是基于高度调整 localScale 的 来做放缩的,所以宽度的放缩UIRoot 已经做了,所以只需要将 relativeSize.y 设置为 1 / mRoot.activeHeight 使 mTrans.localScale.y = 1恒成立。UIRoot 会是高度始终满屏(UIRoot Style 为 FixedSize ),但宽度的放缩总是按照高度的放缩比例在放的,所以会出现宽度没有全部显示出来,或者左右两边有黑边。

      其实要想做到满屏(高度和宽度)缩放的效果,其实可以在UIRoot中增加一个 manualWidth 来调整 UIRoot 的localSize.x 的值。

      另外一种做法就是使用UIStretch ,我们只需要通过设置 relativeSize.x = 1 / manualWidth ;relativeSize.y = 1 / mRoot.activeHeight 就能满屏缩放了,哈哈,搞定了。等等,这样是满屏了,但是其他图片或文字会被拉伸变形,也就是说 UIStretch 只能做到某个单一的组件按比例缩放。

      总之,实际屏幕显示的宽度 = (Screen.Height / mRoot.acriveHeight * manualHeight > Screen.Width ) ?  Screen.Width :Screen.Height / mRoot.acriveHeight * manualHeight ,就是去两者中的更小的。所以要做宽度放缩,只要针对实际显示宽度 和 屏幕宽度(Screen.Width) 来调整 localScale.x 值就行了。 

 

                                                                                                                                                                                         增补于 2013/11/26 19:45

 

      

       

 

                     

 

 

小结:

       本来昨天晚上就想写的,但是由于心情不好,也还要一些要点没有相同,所以才拖到现在完成,今天上了半天班(虽然一直都是在NBA的,今天的詹姆斯太牛逼了,看到我心情都好了,18投14中,罚球11中10,39分),有点小不敬业,吃完中饭之后,就开始组织些了,一直写到现在(花了5个小时),截了好些图,这篇应该是D.S.Qiu这么多篇中写得最畅快最爽的一次,解决之前的疑问。

       和UIRoot一样,UIAnchor和UIStretch很简单,但是却很重要,虽然就几个参数,但是要完全明白和理解还是需要花点时间的,所以我才写出来跟大家分享的,NGUI的文章页写了几篇了(点击查看),转载注明出处,尊重原创。

 

        如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.qiu@gmail.com)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。

        转载请在文首注明出处:http://dsqiu.iteye.com/blog/1975972

更多精彩请关注D.S.Qiu的博客和微博(ID:静水逐风) 

       
 

 

        

  • 大小: 17.6 KB
  • 大小: 15.6 KB
  • 大小: 20.6 KB
  • 大小: 13 KB
  • 大小: 62.4 KB
  • 大小: 18.4 KB
  • 大小: 60.4 KB
  • 大小: 61.8 KB
  • 大小: 17.6 KB
  • 大小: 19.4 KB
  • 大小: 36.1 KB
  • 大小: 19.8 KB
  • 大小: 20.2 KB
  • 大小: 25.3 KB
  • 大小: 29.2 KB
  • 大小: 30 KB
  • 大小: 38.1 KB
  • 大小: 16.9 KB
1
0
分享到:
评论
11 楼 DSJie 2014-02-25  
我觉得LZ再把NGUITools研究一下会更好。虽然不是很复杂,但是工具的实用性确实挺大的,免得又去重写重复的方法。
10 楼 DSJie 2014-02-25  
我觉得LZ再把NGUITools研究一下会更好。
static public AudioSource PlaySound (AudioClip clip, float volume, float pitch)
{
volume *= soundVolume;

if (clip != null && volume > 0.01f)
{
if (mListener == null || !NGUITools.GetActive(mListener))
{
mListener = GameObject.FindObjectOfType(typeof(AudioListener)) as AudioListener;

if (mListener == null)
{
Camera cam = Camera.main;
if (cam == null) cam = GameObject.FindObjectOfType(typeof(Camera)) as Camera;
if (cam != null) mListener = cam.gameObject.AddComponent<AudioListener>();
}
}

if (mListener != null && mListener.enabled && NGUITools.GetActive(mListener.gameObject))
{
AudioSource source = mListener.audio;
if (source == null) source = mListener.gameObject.AddComponent<AudioSource>();
source.pitch = pitch;
source.PlayOneShot(clip, volume);
return source;
}
}
return null;
}
9 楼 lzqlawrence 2013-11-19  
DSQiu 写道
lzqlawrence 写道
恩,但z轴无关应该是在camera的orthgraphic size的前提吧?现在我的camera的size设置成跟背景大小是一样的,例如是800,这样如果你uipanel的z轴还是0的话,uipanel应该因为太小看不到吧?所以我在想的是,这种自适应屏幕的方法是不是不应该应用在ngui3.0.x上,而是更适合用在ngui2.x上?

嗯,虽然我之前看过那个连接,但是没有用,我觉得不用“camera的size设置成跟背景大小是一样的”,要不UIRoot就不需要了,你可以看下我写的UIRoot那篇文章http://dsqiu.iteye.com/blog/1964679,然后如果还想用你现在的方法,我觉得可以看下哪里最终修改了Z轴,然后修改下代码就可以了……

恩,项目从2.x更新到3.0.x后想针对新版有新的做法,这样以后更新版本就不需要这么麻烦了。
8 楼 DSQiu 2013-11-19  
lzqlawrence 写道
恩,但z轴无关应该是在camera的orthgraphic size的前提吧?现在我的camera的size设置成跟背景大小是一样的,例如是800,这样如果你uipanel的z轴还是0的话,uipanel应该因为太小看不到吧?所以我在想的是,这种自适应屏幕的方法是不是不应该应用在ngui3.0.x上,而是更适合用在ngui2.x上?

嗯,虽然我之前看过那个连接,但是没有用,我觉得不用“camera的size设置成跟背景大小是一样的”,要不UIRoot就不需要了,你可以看下我写的UIRoot那篇文章http://dsqiu.iteye.com/blog/1964679,然后如果还想用你现在的方法,我觉得可以看下哪里最终修改了Z轴,然后修改下代码就可以了……
7 楼 lzqlawrence 2013-11-19  
恩,但z轴无关应该是在camera的orthgraphic size的前提吧?现在我的camera的size设置成跟背景大小是一样的,例如是800,这样如果你uipanel的z轴还是0的话,uipanel应该因为太小看不到吧?所以我在想的是,这种自适应屏幕的方法是不是不应该应用在ngui3.0.x上,而是更适合用在ngui2.x上?
6 楼 DSQiu 2013-11-19  
lzqlawrence 写道
DSQiu 写道

不知道你的NGUI版本是多少?我用的是NGUI3.0.X,现在最自适应会很方便,也可以做很多种尝试——设置UIRoot的localScale,就是你发的链接的方法,也可以使用UIStretch放缩背景,然后使用UIAnchor,相对于背景图片来定位……

我用的也是ngui3.0.x,如果你用的是我发的链接的方法,那你没遇到有问题吗?
    
else if(style == Style.BasedOnWidth)  
    {  
        localScale.x = relativeSize.x * screenWidth;  
        localScale.y = relativeSize.y * screenWidth;  
        localScale.z = localScale.x;  
    }  

UIStretch的update()里面
size = Vector3.one;
会把scale都变成1的

如果是NGUI3.0.X的话,z轴为0,是没有问题的,因为新版本的NGUI使用的depth来调节深度显示的,就是完全不考虑z轴了,然后再说z轴为0,哪里设置transform.position没有设置z轴吧,可以看下具体的代码实现……
5 楼 lzqlawrence 2013-11-19  
DSQiu 写道

不知道你的NGUI版本是多少?我用的是NGUI3.0.X,现在最自适应会很方便,也可以做很多种尝试——设置UIRoot的localScale,就是你发的链接的方法,也可以使用UIStretch放缩背景,然后使用UIAnchor,相对于背景图片来定位……

我用的也是ngui3.0.x,如果你用的是我发的链接的方法,那你没遇到有问题吗?
    
else if(style == Style.BasedOnWidth)  
    {  
        localScale.x = relativeSize.x * screenWidth;  
        localScale.y = relativeSize.y * screenWidth;  
        localScale.z = localScale.x;  
    }  

UIStretch的update()里面
size = Vector3.one;
会把scale都变成1的
4 楼 DSQiu 2013-11-19  
DSQiu 写道
lzqlawrence 写道
else if (mPanel != null)  
            {  
                Vector4 cr = mPanel.clipRange;  
  
                if (style != Style.Vertical)  
                    cr.z = size.x - borderPadding.x;  
                  
                if (style != Style.Horizontal)  
                    cr.w = size.y - borderPadding.y;  
                  
                mPanel.clipRange = cr;  
                size = Vector3.one;  
            }  

博主,这里代码写得是否有问题?如果我的panel的clipping选择的是none,这个代码应该是不对的吧?是不是应该再加个
Panel.clipping != UIDrawCall.Clipping.None

嗯,看得出你很严谨,应该也是研究过NGUI的,虽然是欠考虑,但是不会影响,因为在UIPanel中中有做这个判断:
    void UpdateDrawcalls ()
{
Vector4 range = Vector4.zero;

if (mClipping != UIDrawCall.Clipping.None)
{
range = new Vector4(mClipRange.x, mClipRange.y, mClipRange.z * 0.5f, mClipRange.w * 0.5f);
}
             //......
         }

不知道你的NGUI版本是多少?我用的是NGUI3.0.X,现在最自适应会很方便,也可以做很多种尝试——设置UIRoot的localScale,就是你发的链接的方法,也可以使用UIStretch放缩背景,然后使用UIAnchor,相对于背景图片来定位……
3 楼 lzqlawrence 2013-11-19  
DSQiu 写道
lzqlawrence 写道
else if (mPanel != null)  
            {  
                Vector4 cr = mPanel.clipRange;  
  
                if (style != Style.Vertical)  
                    cr.z = size.x - borderPadding.x;  
                  
                if (style != Style.Horizontal)  
                    cr.w = size.y - borderPadding.y;  
                  
                mPanel.clipRange = cr;  
                size = Vector3.one;  
            }  

博主,这里代码写得是否有问题?如果我的panel的clipping选择的是none,这个代码应该是不对的吧?是不是应该再加个
Panel.clipping != UIDrawCall.Clipping.None

嗯,看得出你很严谨,应该也是研究过NGUI的,虽然是欠考虑,但是不会影响,因为在UIPanel中中有做这个判断:
    void UpdateDrawcalls ()
{
Vector4 range = Vector4.zero;

if (mClipping != UIDrawCall.Clipping.None)
{
range = new Vector4(mClipRange.x, mClipRange.y, mClipRange.z * 0.5f, mClipRange.w * 0.5f);
}
             //......
         }

不知道博主你是怎么做自适应屏幕的,http://blog.csdn.net/daiguangda/article/details/7888942,我是按照这种方法做的自适应屏幕,所以如果
Panel.clipping != UIDrawCall.Clipping.None
不加上的话,z轴就变成0了。。
2 楼 DSQiu 2013-11-18  
lzqlawrence 写道
else if (mPanel != null)  
            {  
                Vector4 cr = mPanel.clipRange;  
  
                if (style != Style.Vertical)  
                    cr.z = size.x - borderPadding.x;  
                  
                if (style != Style.Horizontal)  
                    cr.w = size.y - borderPadding.y;  
                  
                mPanel.clipRange = cr;  
                size = Vector3.one;  
            }  

博主,这里代码写得是否有问题?如果我的panel的clipping选择的是none,这个代码应该是不对的吧?是不是应该再加个
Panel.clipping != UIDrawCall.Clipping.None

嗯,看得出你很严谨,应该也是研究过NGUI的,虽然是欠考虑,但是不会影响,因为在UIPanel中中有做这个判断:
    void UpdateDrawcalls ()
{
Vector4 range = Vector4.zero;

if (mClipping != UIDrawCall.Clipping.None)
{
range = new Vector4(mClipRange.x, mClipRange.y, mClipRange.z * 0.5f, mClipRange.w * 0.5f);
}
             //......
         }
1 楼 lzqlawrence 2013-11-18  
else if (mPanel != null)  
            {  
                Vector4 cr = mPanel.clipRange;  
  
                if (style != Style.Vertical)  
                    cr.z = size.x - borderPadding.x;  
                  
                if (style != Style.Horizontal)  
                    cr.w = size.y - borderPadding.y;  
                  
                mPanel.clipRange = cr;  
                size = Vector3.one;  
            }  

博主,这里代码写得是否有问题?如果我的panel的clipping选择的是none,这个代码应该是不对的吧?是不是应该再加个
Panel.clipping != UIDrawCall.Clipping.None

相关推荐

    NGUI Tutorial Create a Button & Download

    NGUI Tutorial Create a Button

    NGUI插件3.11.2版本

    在场景视图中看到的就是在游戏视图中得到的(所见即所得)。 基于组件的、模块化的特性:要让你的界面控件做什么,只需为其附加相应的行为,而不需要编码。 全面支持iOS/Android和Flash。 灵活的事件系统。 可以让...

    NGUI_3.11.3.unitypackage

    在场景视图中看到的就是在游戏视图中得到的(所见即所得)。 基于组件的、模块化的特性:要让你的界面控件做什么,只需为其附加相应的行为,而不需要编码。 全面支持iOS/Android和Flash。 灵活的事件系统。 可以让...

    NGUI3.11.4

    在场景视图中看到的就是在游戏视图中得到的(所见即所得)。 基于组件的、模块化的特性:要让你的界面控件做什么,只需为其附加相应的行为,而不需要编码。 全面支持iOS/Android和Flash。 灵活的事件系统。 可以让...

    NGUI Next-Gen UI 2020.1.5

    - 编辑器集成,所见即所得 - 本地化、数据绑定、委托、事件 - 支持所有平台 - 制作进行 1 次绘制调用的 UI - 随附完整的 C# 源代码 - 已广泛优化 - 专门团队支持 2020.1.5 - NEW: You can now specify per-symbol ...

    NGUI插件大全

    在场景视图中看到的就是在游戏视图中得到的(所见即所得)。 基于组件的、模块化的特性:要让你的界面控件做什么,只需为其附加相应的行为,而不需要编码。 全面支持iOS/Android和Flash。 灵活的事件系统。 可以让...

    CustomGUI.unitypackage

    使用unity原生GUI封装,来达到UGUI,NGUI所见即所得的效果和部分功能,目的是由此来了解高级UI的原理。

    NGUI 3.5.9

    在场景视图中看到的就是在游戏视图中得到的(所见即所得)。  基于组件的、模块化的特性:要让你的界面控件做什么,只需为其附加相应的行为,而不需要编码。  全面支持iOS/Android和Flash。  灵活的事件系统。...

    最新版本的NGUI插件NGUI Next-Gen UI 覆盖unity多个版本

    NGUI Next-Gen UI是一款功能强大、灵活性高的UI插件,是当前最新版本的NGUI插件。它可以覆盖Unity的多个版本,包括Unity 5、Unity 2017和Unity 2018等。与其他UI插件相比,NGUI Next-Gen UI具有高效的性能和优秀的...

    NGUI 2020.1.5.unitypackage

    NGUI 是一款非常强大的 UI 系统和事件通知框架。...- 编辑器集成,所见即所得 - 本地化、数据绑定、委托、事件 - 支持所有平台 - 制作进行 1 次绘制调用的 UI - 随附完整的 C# 源代码 - 已广泛优化 - 专门团队支持

    NGUI3.5.9 Unity3d UI开发神器

    在场景视图中看到的就是在游戏视图中得到的(所见即所得)。  基于组件的、模块化的特性:要让你的界面控件做什么,只需为其附加相应的行为,而不需要编码。  全面支持iOS/Android和Flash。  灵活的事件系统。...

    NGUI 2019_3_0.unitypackage.zip

    NGUI是一个非常强大的UI系统和事件通知框架。 特征 -编辑器集成,所见即所得 -本地化,数据绑定,委托,事件 -支持所有平台 -进行1次抽签的UI -随附完整的C#源代码 -广泛优化 -专用支持

    Unity插件 NGUI各种版本合集

    本包中共有六个版本的NGUI,大家可以自己选择版本。 NGUI Next-Gen UI 3.6.0.unitypackage NGUI Next-Gen UI 3.12.1(u5.6.5).unitypackage NGUI Next-Gen UI 2019.3.0.unitypackage NGUI Next-Gen UI v2018.3.0....

    HTML Engine for NGUI & Unity GUI

    HTML Engine for NGUI & Unity GUI

    NGUI3.6.4 最新版本NGUI ngui

    大名鼎鼎的U3D插件NGUI,移动开发做界面都用它.最新官方版本,包含API文档.

    NGUI Next-Gen UI v3.6.0

    最新版unity3d扩展插件:NGUI Next-Gen UI3.6.0 运行Unity3D,解压后此压缩包,在菜单Assets中选择自定义导入。 如果无法导入时,请检查导入目录中是否存在中文字符。...所见即所得的集成编辑器,支持所有平台。

    NGUI v3.11.2

    NGUI v3.11.2,适合Unity2017 NGUI 是一款非常强大的...- 编辑器集成,所见即所得 - 本地化、数据绑定、委托、事件 - 支持所有平台 - 制作进行 1 次绘制调用的 UI - 随附完整的 C# 源代码 - 已广泛优化 - 专门团队支持

    NGUI离线文档

    NGUI离线文档 基于3.7.5

    NGUI Next-Gen UI v3.5.8(unity3d插件最新版).rar

    软件介绍: NGUI Next-Gen UI v3.5.8最新完整版,本版本需要Unity 3.5.7或者更高版本。NGUI是一款功能强大的UI系统和事件通知框架。所见即所得的集成编辑器,支持所有平台。本资源来源于网络仅供测试。

Global site tag (gtag.js) - Google Analytics