ugui scrollrect 多点触摸实现缩放

来源:互联网 发布:鼠标怎么编程 编辑:程序博客网 时间:2024/04/28 19:40

 这里的多点触摸实现方式具有通用性,在提供触摸事件调用和触摸点数据的情况下都可实现。首先,我们需要继承复写ScrollRect的OnDrag方法,让其在一个触摸点的情况下,使用原有拖拽功能,在两个点的情况下,滑动缩放。


private int touchNum = 0;public override void OnBeginDrag (PointerEventData eventData){if(Input.touchCount > 1) {return;}base.OnBeginDrag(eventData);}public override void OnDrag (PointerEventData eventData){if (Input.touchCount > 1){touchNum = Input.touchCount;return;}else if(Input.touchCount == 1 && touchNum > 1){touchNum = Input.touchCount;base.OnBeginDrag(eventData);return;}base.OnDrag(eventData);}


使用unity自己的触摸判断,Input.touchCount,在正常情况下调用SrollRect自己的方法处理。否则,执行自己的处理。OnDrag中touchCout从多个变回一个的时候,我们首先需要调用一下OnBeginDrag,然后下一帧在执行一个点的逻辑。在实测用,这是为了解决从多个点变回一个点,但这个点是后触摸的点,会造成跳动的问题。



多点滑动的逻辑是写在Update方法里面。经过测试,发现如果写在OnDrag方法里面。会出现放到最大继续快速滑动,或是最小在快速缩小,出现突然缩放的情况。而实际上应该不能继续放大或缩小。


private float preX;private float preY;private void Update(){   if (Input.touchCount == 2){Touch   t1   = Input.GetTouch(0);Touch   t2   = Input.GetTouch(1);  Vector3 p1   = t1.position;Vector3 p2   = t2.position;float   newX = Mathf.Abs(p1.x - p2.x);float   newY = Mathf.Abs(p1.y - p2.y);if (t1.phase == TouchPhase.Began || t2.phase == TouchPhase.Began){preX = newX;preY = newY;}else if (t1.phase == TouchPhase.Moved && t2.phase == TouchPhase.Moved){RectTransform rt    = base.content;float         scale = (newX + newY - preX - preY) / (rt.rect.width * 0.25f) + rt.localScale.x;if (scale > 1.0f && scale < 2.5f){float ratio   = scale / rt.localScale.x;rt.localScale = new Vector3(scale, scale, 0);float maxX    = base.content.rect.width  * scale / 2 - this.viewRect.rect.width  / 2;float minX    = -maxX;float maxY    = base.content.rect.height * scale / 2 - this.viewRect.rect.height / 2;float minY    = -maxY;Vector3 pos   = rt.position * ratio;if (pos.x > maxX){pos.x = maxX;}else if (pos.x < minX){pos.x = minX;}if (pos.y > maxY){pos.y = maxY;}else if (pos.y < minY){pos.y = minY;}rt.position = pos;}}preX = newX;preY = newY;}}


float newX = Mathf.Abs(p1.x - p2.x); 

float newY = Mathf.Abs(p1.y - p2.y);

这里我们计算的是两个触摸点坐标差值的绝对值。用来粗略的判断两个点的位置关系。


t1.phase == TouchPhase.Began || t2.phase == TouchPhase.Began

这个条件判断是为了,在移动条件达成时候,初始化前一个坐标点的数据。


float scale = (newX + newY - preX - preY) / (rt.rect.width * 0.25f) + rt.localScale.x;

这是一个粗略的判断算法。用新的xy差值减去上次的xy差值,这个结果反映了两个手指的距离变化。然后除以rt.rect.width,得到这个距离变化与缩放目标宽度的比例。0.25f是一个调整系数,用来控制scale的变化率。这里的数值就是根据手势得到的缩放率,然后加上原有的缩放数值,得到的scale就是最终需要缩放的数值。


scale > 1.0f && scale < 2.5f

这个条件约束了,最终的缩放的范围。


后面的算法,做了两个事情。

设置最终的缩放,然后计算边界的约束,让缩放后位置仍然在边界内。不然,我放大拖到边界,然后缩小就会越界的情况。

根据缩放的倍率,来设置新的位置。比如,原有位置不在00点,缩放了,那么位置也缩放同一个倍率,就能让缩放中心同步出现在手势操作位置上,而不是物体中心。


float ratio   = scale / rt.localScale.x;

这里新的缩放值除以原有缩放值,得到的就是缩放的倍率。


Vector3 pos = rt.position * ratio;

用原有的位置坐标乘以缩放倍率,得到新的位置。



float maxX = base.content.rect.width * scale / 2 - this.viewRect.rect.width / 2; 

float minX = -maxX;

float maxY = base.content.rect.height * scale / 2 - this.viewRect.rect.height / 2; 

float minY = -maxY;

这里是计算位置的边界。



if (pos.x > maxX) {

      pos.x = maxX;

 } else if (pos.x < minX) { 

     pos.x = minX;

 } 


if (pos.y > maxY) { 

    pos.y = maxY;

 }  else if (pos.y < minY)  {

    pos.y = minY;

 }

 rt.position = pos;


根据边界计算新的位置坐标。




0 0
原创粉丝点击