一、精确定位
功能1:点击scrollview里面的item,检测如果item被遮挡自动滚动scrollview使当前item显示出来;
功能2:点击scrollview里面的item,自动滚动scrollview使当前item居中;
//
//NewBehaviourScript.cs
//
// Created by [JiangXinhou]
//
// Copyright jiangxinhou@outlook.com (<a target=_blank href="http://blog.csdn.net/cordova">http://blog.csdn.net/cordova</a>)
using UnityEngine;
using System.Collections;
/* NGUI ScrollView
* 功能1:点击scrollview里面的item,检测如果item被遮挡自动滚动scrollview使当前item显示出来
* 功能2:点击scrollview里面的item,自动滚动scrollview使当前item居中
*
* 首先要统一使用世界坐标系,其中scrollview的clipoffset值设置时要将世界坐标里的单位转化成像素单位
* 每次移动要改变两个值,一个是clipoffset的值,另一个是scrollview所在panel缓存的transform的position
*/
public class ScrollviewItemFit : MonoBehaviour
{
//所在的scrollview
public UIScrollView ScrollView;
//水平方向边界:
private float leftX;
private float rightX;
//竖直方向边界:
private float topY;
private float bottomY;
//偏移值
float offsetX = 0;
float offsetY = 0;
//滚动值手动矫正,一般要多滚动一些保证item完全显示
private float delta = 0.5f;
//当前物体宽度
private float itemW;
//当前物体高度
private float itemH;
//panel中心
Vector3 center;
//panel缓存的transform
Transform panelTrans;
//目标位置与目标offset
Vector3 targetPos;
Vector2 tartgetOffset;
/// <summary>
/// 初始化
/// </summary>
void Start()
{
// 1.获取scrollview
ScrollView = GetComponentInParent<UIScrollView>();
// 2.获取物体世界坐标尺寸
itemW = GetComponent<BoxCollider>().bounds.size.x + delta;
itemH = GetComponent<BoxCollider>().bounds.size.y + delta;
// 3.设置上下左右边界(使用世界坐标)
//panel四个角坐标
Vector3[] corners = ScrollView.panel.worldCorners;
leftX = corners[0].x + itemW / 2;
bottomY = corners[0].y + itemH / 2;
rightX = corners[2].x - itemW / 2;
topY = corners[2].y - itemH / 2;
//中心
center = (corners[0] + corners[2]) / 2;
}
/// <summary>
/// 延迟帧刷新周期
/// </summary>
void LateUpdate()
{
//插值平滑移动
if (offsetX != 0 || offsetY != 0)
{
panelTrans.position = Vector3.Lerp(panelTrans.position, targetPos, 5 * Time.deltaTime);
ScrollView.panel.clipOffset = Vector2.Lerp(ScrollView.panel.clipOffset, tartgetOffset, 5 * Time.deltaTime);
//当基本到位时将offset清空
if ((targetPos - panelTrans.position).sqrMagnitude < 0.01f)
{
offsetX = 0;
offsetY = 0;
}
}
}
/// <summary>
/// 点击事件
/// </summary>
void OnClick()
{
if (ScrollView != null && ScrollView.panel != null)
{
//缓存的transform
panelTrans = ScrollView.panel.cachedTransform;
/**** 如果当前item被mask遮挡则scrollview滚动遮挡的宽度使其显示 ****/
// 1.水平scrollview的情况
if (ScrollView.canMoveHorizontally)
{
//左侧超出:
if (transform.position.x < leftX)
{
offsetX = leftX - transform.position.x;
}
//右侧超出:
else if (transform.position.x > rightX)
{
offsetX = rightX - transform.position.x;
}
else
{
return;
}
targetPos = panelTrans.position + new Vector3(offsetX, 0, 0);
//这个360应该是GNUI坐标单位与世界坐标单位的一个缩放比例,具体搞不清楚,我在另一个环境这个值成了540,肯定有地方可以设置
tartgetOffset = ScrollView.panel.clipOffset - new Vector2(360 * offsetX, 0);
}
// 2.垂直scrollview的情况
if (ScrollView.canMoveVertically)
{
//底部超出:
if (transform.position.y < bottomY)
{
offsetY = bottomY - transform.position.y;
}
//顶部超出:
else if (transform.position.y > topY)
{
offsetY = topY - transform.position.y;
}
else
{
return;
}
// 将panel弹到计算的位置
targetPos = panelTrans.position + new Vector3(0, offsetY, 0);
tartgetOffset = ScrollView.panel.clipOffset - new Vector2(0, 360 * offsetY);
}
/*** 将当前item置于panel中间 ****/
/*
//比较计算当前物体与panel中心的坐标差
Vector3 localOffset = transform.position - center;
// 根据滚动方向屏蔽掉不需要的滚动偏移
if (!ScrollView.canMoveHorizontally) localOffset.x = 0f;
if (!ScrollView.canMoveVertically) localOffset.y = 0f;
localOffset.z = 0f;
// 将panel弹到计算的位置
targetPos = panelTrans.position - localOffset;
tartgetOffset = ScrollView.panel.clipOffset;
tartgetOffset.x += localOffset.x*360;
tartgetOffset.y += localOffset.y*360;
//开始移动(使offsetX或者offsetY不为零)
offsetX = 1;
* */
}
}
}
二、还有一种方法是使用NGUI的ScroolView的Scroll函数,但是看了原定义也没搞清楚它的参数到底啥意思,不好精确控制,只能暴露一个手动调节的值:
//
//NewBehaviourScript.cs
//
// Created by [JiangXinhou]
//
// Copyright jiangxinhou@outlook.com (<a target=_blank href="http://blog.csdn.net/cordova">http://blog.csdn.net/cordova</a>)
using UnityEngine;
using System.Collections;
/* NGUI ScrollView
* 功能:点击scrollview里面的item,检测如果item被遮挡自动滚动scrollview使当前item显示出来
*/
public class ScrollviewItemFit1 : MonoBehaviour
{
//所在的scrollview
public UIScrollView ScrollView;
//滚动值
public float delta = -0.5f;
//可手动调节的item宽度或者高度的一半
public float height = 400f;
/// <summary>
/// 初始化
/// </summary>
void Start()
{
// 获取scrollview
ScrollView = GetComponentInParent<UIScrollView>();
}
/// <summary>
/// 点击事件
/// </summary>
void OnClick()
{
//panel的裁剪区域
Vector4 region = ScrollView.panel.finalClipRegion;
//item在scrollview坐标系下的位置
var localPos = ScrollView.transform.InverseTransformPoint(transform.position);
//打印位置
Debug.Log("聚焦项的位置:" + transform.position);
//1.纵向滚动的情况
if (this.ScrollView.canMoveVertically)
{
if (localPos.y < region.y - region.w + height)
{
//排除scrollWheelFactor对灵敏度的影响
this.ScrollView.Scroll(delta / this.ScrollView.scrollWheelFactor);
}
if (localPos.y > region.y + region.w - height)
{
this.ScrollView.Scroll(-delta / this.ScrollView.scrollWheelFactor);
}
}
//2.横向滚动的情况
if (ScrollView.canMoveHorizontally)
{
if (localPos.x < region.x - region.z + height)
{
//排除scrollWheelFactor对灵敏度的影响
this.ScrollView.Scroll(delta / this.ScrollView.scrollWheelFactor);
}
if (localPos.x > region.x + region.z - height)
{
this.ScrollView.Scroll(-delta / this.ScrollView.scrollWheelFactor);
}
}
}
}
三、如何判断scrollview是否可以移动
这个取决于panel内容的尺寸是否超出scrollview可见区域的边界bounds,UIScrollView类内有个shouldMoveHorizontally和shouldMoveVertically的函数变量,官方给出了计算判断方法,取该变量即可判断scrollview是是否fit可以移动:
/// <summary>
/// Whether the scroll view should be able to move horizontally (contents don't fit).
/// </summary>
public virtual bool shouldMoveHorizontally
{
get
{
float size = bounds.size.x;//scrollview边界的宽度
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip) size += mPanel.clipSoftness.x * 2f;
return Mathf.RoundToInt(size - mPanel.width) > 0;
}
}
/// <summary>
/// Whether the scroll view should be able to move vertically (contents don't fit).
/// </summary>
public virtual bool shouldMoveVertically
{
get
{
float size = bounds.size.y;//scrollview边界的高度
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip) size += mPanel.clipSoftness.y * 2f;
return Mathf.RoundToInt(size - mPanel.height) > 0;
}
}
orz......有问题吐槽请留言,帮到您烦请帮顶一下,谢谢^_^