【原创文章】转载请标记出处。-----拉婓Laughing----
制作滑动响应事件:
原型设计:我们来仔细想象在一款正常交互作品中,对滑动框的控制方式。当鼠标或者手指在滑动框上按下时,滑动框被激活;激活状态下,用户滑动鼠标,或拖动手指,即可让滑动框跟着滑动。
OK,功能需求都描绘出来了,接下来就要代码去实现吧!
private RectTransform rt; //需要控制的滑动窗体
private Vector3 dragDelta; //滑动数据量
public Camera renderCamera;//渲染滑动窗体的相机
private bool isMouseDown;
private bool isPointDown;
//主要逻辑在Update里面
private void Update()
{
//触摸
if (Input.touchCount > 0)
{
Touch[] touches = Input.touches;
int tCount = touches.Length;
for(int i = 0; i < tCount; i++)
{
//检测触摸及鼠标坐标是否在滑动窗口内
if (DetectedPosition(touches[i].position))
{
selectTouch = touches[i];
dragDelta = new Vector3(selectTouch.position.x, selectTouch.position.y, rt.anchoredPosition3D.z) - rt.anchoredPosition3D;
isPointDown = true;
break;
}
}
}
//鼠标
if(Input.GetMouseButtonDown(0))
{
//检测触摸及鼠标坐标是否在滑动窗口内
if (DetectedPosition(Input.mousePosition))
{
dragDelta = Input.mousePosition- rt.anchoredPosition3D;
Debug.Log("MY");
//增加一层与Icon之间的触摸阻隔
isMouseDown = true;
}
}
//这里开始实际控制滑动窗体的滑动
if (isMouseDown&&!isPointDown)
{
//这是笔者自己封装在框架里的为transform修改localPosition的方法,因为项目实际只需要能在X轴上进行滑动。
rt.SetLocalPos(Pos.x, Input.mousePosition.x - dragDelta.x);
}
else if (isPointDown&&!isMouseDown)
{
rt.SetLocalPos(Pos.x, selectTouch.position.x - dragDelta.x);
}
}
//检测触摸坐标是否在滑动窗体内
//注意这里要指定一下渲染的相机是哪一个(以防在不同项目中,canvas的RenderMode不同,导致Rect失效)
private bool DetectedPosition(Vector2 ScreenPosition)
{
if (RectTransformUtility.RectangleContainsScreenPoint
(rt, ScreenPosition, renderCamera))
{
return true;
}
else
{
return false;
}
}
···
1.1. 一直到上一步,已经基本可以控制滑动窗口进行水平滑动了,接下来我们需要对窗口的显示画面
c_icon_group 附上刚刚的脚本,子物体都是滑动窗体实际的装载内容。
将渲染相机,赋给RenderCamera
2. 下一步,我们要让整个窗体的长度和起始位置,在编辑器运行时,能够自动适配装载内容的数量和内容。(数学问题,不过多解释原理,无非就是按照装载内容的位置坐标对窗体长度进行匹配计算。)
void Start(){
rt = transform.GetComponent();
oldPos = rt.anchoredPosition3D;
//设置content的宽高和位置
int width =(int)(transform.GetChild(transform.childCount - 1).GetComponent().anchoredPosition3D.x+ transform.GetChild(transform.childCount - 1).GetComponent().sizeDelta.x);
//这里笔者根据实际的项目分辨率,对宽度的上限与下限进行控制
if (width <=1920)
{
width = 1920;
}
rt.sizeDelta = new Vector2(width, rt.sizeDelta.y);
rt.SetLocalPos(Pos.x,width * 0.5f - Screen.width * 0.5f);
}
整体代码如下:
/***
* Copyright(C) by #Laughing#
* All rights reserved.
* FileName: #ScrollView_Custom#
* Author: #Laughing#
* Version: #v1.0#
* Date: #20190527_1200#
* Description: ##
* History: ##
***/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RDFW;
using System.Linq;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using System;
using DG.Tweening;
namespace RDFW
{
public class RDScrollRect : MonoBehaviour
{
private bool isMouseDown;
private bool isPointDown;
private float endX;
private float startX;
public float endReserved;
public Camera renderCamera;
private GameObject mask;
private Vector3 dragDelta=Vector3.zero;
private RectTransform rt;
private Vector3 oldPos;
private Touch selectTouch;
//补间动画对象
private Tweener tweener;
//窗体弹性
[Range(0,1)]
public float sensitive;
private void Start()
{
rt = transform.GetComponent();
rt.anchoredPosition3D = new Vector3(startX, rt.anchoredPosition3D.y, rt.anchoredPosition3D.z);
oldPos = rt.anchoredPosition3D;
//设置content的宽高和位置
int width =(int)(transform.GetChild(transform.childCount - 1).GetComponent().anchoredPosition3D.x+ transform.GetChild(transform.childCount - 1).GetComponent().sizeDelta.x);
if (width <=1920)
{
width = 1920;
}
rt.sizeDelta = new Vector2(width, rt.sizeDelta.y);
rt.SetLocalPos(Pos.x,width * 0.5f - Screen.width * 0.5f);
startX = width * 0.5f - Screen.width * 0.5f;
endX = ((width - Screen.width)*0.5f+endReserved)*-1;
if (width == 1920)
{
endX = 0;
}
}
private void Update()
{
//触摸
if (Input.touchCount > 0)
{
Touch[] touches = Input.touches;
int tCount = touches.Length;
for(int i = 0; i < tCount; i++)
{
if (DetectedPosition(touches[i].position))
{
selectTouch = touches[i];
dragDelta = new Vector3(selectTouch.position.x, selectTouch.position.y, rt.anchoredPosition3D.z) - rt.anchoredPosition3D;
isPointDown = true;
break;
}
}
}
if(Input.GetMouseButtonDown(0))
{
if (DetectedPosition(Input.mousePosition))
{
dragDelta = Input.mousePosition- rt.anchoredPosition3D;
Debug.Log("MY");
//增加一层与Icon之间的触摸阻隔
isMouseDown = true;
}
}
if (Input.GetMouseButtonUp(0))
{
isMouseDown = false;
isPointDown = false;
if (rt.anchoredPosition3D.x < endX)
{
tweener?.Kill();
tweener=rt.DOLocalMoveX(endX,1- sensitive);
}
else if(rt.anchoredPosition3D.x > startX)
{
tweener?.Kill();
tweener =rt.DOLocalMoveX(startX,1- sensitive);
}
}
if (isMouseDown&&!isPointDown)
{
tweener?.Kill();
rt.SetLocalPos(Pos.x, Input.mousePosition.x - dragDelta.x);
}
else if (isPointDown&&!isMouseDown)
{
tweener?.Kill();
rt.SetLocalPos(Pos.x, selectTouch.position.x - dragDelta.x);
}
}
private bool DetectedPosition(Vector2 ScreenPosition)
{
if (RectTransformUtility.RectangleContainsScreenPoint(transform.GetComponent(), ScreenPosition, renderCamera))
{
return true;
}
else
{
return false;
}
}
}
}
实现这个需求其实很简单,只要在为装载内容,即Icon按钮注册点击事件时,对鼠标滑动和触摸滑动事件做过滤即可,即当鼠标滑动,触摸滑动时,不触发按钮注册事件。
private void AddIcon(PointerEventData eventData)
{
if (!eventData.dragging && !eventData.IsPointerMoving())
{
//这里做按钮按下,你想要做的事
}
}
最终效果如下:
【原创文章】转载请标记出处。-----拉婓Laughing----