您的位置:首页 > 移动开发 > Unity3D

Unity NGUI之ScrollView扩展-2

2016-02-26 15:59 585 查看
大伙在使用UIScrollView时,经常和UICenterOn脚本配合使用,但是随着需求的不断增加,会出现这个需求:第一个列表在拖动后不让它在最中间显示,还是保留在UIScrollView裁剪区域的其实部分,比如,一些非常多的列表,要求一条条显示,同时又不能出现半个,大伙第一个就能想到UICenterOn,但是拖着列表过程中,第一个列表就被固定在了中间,这样显示很难看。怎样解决这个问题呢?我在看UIScrollView代码的过成中看到了这个方法:

public bool RestrictWithinBounds (bool instant, bool horizontal, bool vertical)

这个方法的作用是让列表的显示限制在裁剪区域

那怎么判断这个列表超出了这个区域了呢(即列表的起始,末尾部分往中间显示)

我写了一个方法来判断,至于是什么原理,大伙通过看代码来研究了:

/// <summary>

/// 可以填充区域 但没有填充区域

/// </summary>

private bool IsOutOfBoundsPanel()

{

if (mPanel == null) mPanel = GetComponent<UIPanel>();

Vector4 clip = mPanel.finalClipRegion;

Bounds b = GetSpecialBounds(transform);

float hx = (clip.z == 0f) ? Screen.width : clip.z * 0.5f;

float hy = (clip.w == 0f) ? Screen.height : clip.w * 0.5f;

if (canMoveHorizontally)

{

if ((b.min.x > clip.x - hx) && (b.max.x > clip.x + hx)) return true;

if ((b.max.x < clip.x + hx) && (b.min.x < clip.x - hx)) return true;

}

if (canMoveVertically)

{

if ((b.min.y > clip.y - hy) && (b.max.y > clip.y + hy)) return true;

if ((b.max.y < clip.y + hy) && (b.min.y < clip.y - hy)) return true;

return true;

}

return false;

}

注意里面的GetSpecialBounds方法就是我在上一栏中写的方法,大伙也可以用UIScrollView 的bounds属性

最后在改动UIScrollView 的lateupdate方法(幸好lateupdate方法可以完全重写,否则要改动UIScrollView的脚本了):

我把改动的部分给粘上

// Restrict the contents to be within the scroll view's bounds

if (restrictWithinPanel && mPanel.clipping != UIDrawCall.Clipping.None)

{

if (NGUITools.GetActive(centerOnChild))

{

if (centerOnChild.nextPageThreshold != 0f)

{

mMomentum = Vector3.zero;

mScroll = 0f;

}

else

{

if (restrictWithinPanelIgnoreCenterOnChild && IsOutOfBoundsPanel())

{

RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);

}

else

{

centerOnChild.Recenter();

}

}

}

else

{

RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);

}

}

最后附上这个脚本的源码,供大家参考

using UnityEngine;

using System.Collections;

using System.Collections.Generic;

public class UIScrollViewForSpecialBounds : UIScrollView

{

/// <summary>

/// 限制区域填充的时候是否忽略UICenterOnChild脚本的作用

/// </summary>

public bool restrictWithinPanelIgnoreCenterOnChild=false;

/// <summary>

/// 针对改名字获取相应的bounds

/// </summary>

public string TargetWidgetBoundsName;

public override Bounds bounds

{

get

{

mCalculatedBounds = true;

mTrans = transform;

return GetSpecialBounds(transform);

}

}

void LateUpdate()

{

if (!Application.isPlaying) return;

float delta = RealTime.deltaTime;

// Fade the scroll bars if needed

if (showScrollBars != ShowCondition.Always && (verticalScrollBar || horizontalScrollBar))

{

bool vertical = false;

bool horizontal = false;

if (showScrollBars != ShowCondition.WhenDragging || mDragID != -10 || mMomentum.magnitude > 0.01f)

{

vertical = shouldMoveVertically;

horizontal = shouldMoveHorizontally;

}

if (verticalScrollBar)

{

float alpha = verticalScrollBar.alpha;

alpha += vertical ? delta * 6f : -delta * 3f;

alpha = Mathf.Clamp01(alpha);

if (verticalScrollBar.alpha != alpha) verticalScrollBar.alpha = alpha;

}

if (horizontalScrollBar)

{

float alpha = horizontalScrollBar.alpha;

alpha += horizontal ? delta * 6f : -delta * 3f;

alpha = Mathf.Clamp01(alpha);

if (horizontalScrollBar.alpha != alpha) horizontalScrollBar.alpha = alpha;

}

}

if (!mShouldMove) return;

// Apply momentum

if (!mPressed)

{

if (mMomentum.magnitude > 0.0001f || mScroll != 0f)

{

if (movement == Movement.Horizontal)

{

mMomentum -= mTrans.TransformDirection(new Vector3(mScroll * 0.05f, 0f, 0f));

}

else if (movement == Movement.Vertical)

{

mMomentum -= mTrans.TransformDirection(new Vector3(0f, mScroll * 0.05f, 0f));

}

else if (movement == Movement.Unrestricted)

{

mMomentum -= mTrans.TransformDirection(new Vector3(mScroll * 0.05f, mScroll * 0.05f, 0f));

}

else

{

mMomentum -= mTrans.TransformDirection(new Vector3(

mScroll * customMovement.x * 0.05f,

mScroll * customMovement.y * 0.05f, 0f));

}

mScroll = NGUIMath.SpringLerp(mScroll, 0f, 20f, delta);

// Move the scroll view

Vector3 offset = NGUIMath.SpringDampen(ref mMomentum, 9f, delta);

MoveAbsolute(offset);

// Restrict the contents to be within the scroll view's bounds

if (restrictWithinPanel && mPanel.clipping != UIDrawCall.Clipping.None)

{

if (NGUITools.GetActive(centerOnChild))

{

if (centerOnChild.nextPageThreshold != 0f)

{

mMomentum = Vector3.zero;

mScroll = 0f;

}

else

{

if (restrictWithinPanelIgnoreCenterOnChild && IsOutOfBoundsPanel())

{

RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);

}

else

{

centerOnChild.Recenter();

}

}

}

else

{

RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);

}

}

if (onMomentumMove != null)

onMomentumMove();

}

else

{

mScroll = 0f;

mMomentum = Vector3.zero;

SpringPanel sp = GetComponent<SpringPanel>();

if (sp != null && sp.enabled) return;

mShouldMove = false;

if (onStoppedMoving != null)

onStoppedMoving();

}

}

else

{

// Dampen the momentum

mScroll = 0f;

NGUIMath.SpringDampen(ref mMomentum, 9f, delta);

}

}

/// <summary>

/// 可以填充区域 但没有填充区域

/// </summary>

private bool IsOutOfBoundsPanel()

{

if (mPanel == null) mPanel = GetComponent<UIPanel>();

Vector4 clip = mPanel.finalClipRegion;

Bounds b = GetSpecialBounds(transform);

float hx = (clip.z == 0f) ? Screen.width : clip.z * 0.5f;

float hy = (clip.w == 0f) ? Screen.height : clip.w * 0.5f;

if (canMoveHorizontally)

{

if ((b.min.x > clip.x - hx) && (b.max.x > clip.x + hx)) return true;

if ((b.max.x < clip.x + hx) && (b.min.x < clip.x - hx)) return true;

}

if (canMoveVertically)

{

if ((b.min.y > clip.y - hy) && (b.max.y > clip.y + hy)) return true;

if ((b.max.y < clip.y + hy) && (b.min.y < clip.y - hy)) return true;

return true;

}

return false;

}

/// <summary>

/// 获取特定的Bounds 按照gameobject的名字进行过滤

/// </summary>

private Bounds GetSpecialBounds(Transform scrollView)

{

Matrix4x4 toLocal = scrollView.worldToLocalMatrix;

bool isSet = false;

Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);

Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);

if (!(scrollView == null || (!NGUITools.GetActive(scrollView.gameObject))))

{

Vector3[] corners = null;// p.worldCorners;

List<UIWidget> widigetList = new List<UIWidget>();

GetSpecialBoundsWidget(transform, TargetWidgetBoundsName, ref widigetList);

for (int i = 0; i < widigetList.Count; i++)

{

UIWidget w = widigetList[i];

corners = w.worldCorners;

for (int j = 0; j < 4; ++j)

{

Vector3 v = toLocal.MultiplyPoint3x4(corners[j]);

if (v.x > max.x) max.x = v.x;

if (v.y > max.y) max.y = v.y;

if (v.z > max.z) max.z = v.z;

if (v.x < min.x) min.x = v.x;

if (v.y < min.y) min.y = v.y;

if (v.z < min.z) min.z = v.z;

isSet = true;

}

}

}

if (isSet)

{

Bounds b = new Bounds(min, Vector3.zero);

b.Encapsulate(max);

return b;

}

return new Bounds(Vector3.zero,Vector3.zero);

}

private void GetSpecialBoundsWidget(Transform parent,string speciBoundsName,ref List<UIWidget> list)

{

if (parent == null)

return;

foreach(Transform child in parent)

{

GetSpecialBoundsWidget(child,speciBoundsName,ref list);

}

if(parent.name==speciBoundsName)

{

list.Add(parent.GetComponent<UIWidget>());

}

}

}

最后希望对大伙有所帮助。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: