Scroll View是一个组合UI,创建后有以下内容
——Viewport:显示的区域,一般配合Mask一起使用
——Scrollbar Horizontal:水平滑动条
——Scrollbar Vertical:竖直滑动条
Scroll View上最重要的就是Scroll Rect组件:
——Content:所有要显示的内容(可滑动的区域)
——Horizontal:是否可以水平滑动
——Vertical:是否可以竖直滑动
——Movement Type:滑动的类型(不受限制随意滑动,到边界出现弹性,到边界没有弹性)
——Elasticity:弹性数值
——Inertia:是否用惯性
——Deceleration Rate:惯性的加速度
——Viewport:可视区域,一般配合Mask一起使用
获取content的宽和高:
//获取content的宽和高(content矩形的width和height)
print("size " + content.rect.size);
print("width " + content.rect.width);
print("height " + content.rect.height);
print("width " + content.rect.size.x);
print("height " + content.rect.size.y);
//以下方法本质上并不是获取content的宽和高,而是获取content矩形的四个角的位置
print("width " + content.rect.xMax);
print("width " + content.rect.xmin);
print("height " + content.rect.ymax);
print("height " + content.rect.ymin);
//设置content的大小——content.sizeDelta
print("相对位置 "+content.sizeDelta);
//——content.sizeDelta是一个相对大小,直接设置位置即可,不需要累加上之前content的数值
//——content.rect.size是结构体类型,不能改数值
——Grid Layout Group
Padding:Content下所有物体对于Content整体的上下左右偏移量
Cell Size:Content下所有物体的大小(持有Grid Layout Group组件下所有Image的RectTransfrom大小设置都被锁上,只能通过此属性设置Image大小)
Spacing:Content下所有物体的行与列的间隔
Start Corner:填充的起始点
Start Axis:填充的轴向
Child Alignment:所有子物体的对齐方式
Constraint:限制Content内容的行数和列数
——Vertical Layout Group和Horizontal Layout Group
Padding:Content下所有物体对于Content整体的上下左右偏移量
Spacing:Content下所有物体的行或列的间隔
Child Alignment:所有子物体的对齐方式
Control Child Size:是否控制子物体的大小(勾选后将不能控制其大小)
Use Child Scale:是否使用子物体的缩放
Child Force Expand:子物体自动伸展(Width和Height一般都不勾选)
——Content Size Fitter(此组件还可以制作提示文本框随着文字的数量增多而变大)
Horizontal Fit:水平的自动调节(通常选择Preferred Size)
Vertical Fit:竖直的自动调节(通常选择Preferred Size)
content.sizeDelta = (n-1)*(Spacing X+CellSize X)
——通过horizontalNormalizedPosition实现(推荐使用)
using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.UI;
public class ExtensionScrollView : MonoBehaviour, IBeginDragHandler, IEndDragHandler
{
[Header("能否移动多页")]
public bool canMoveMult; //能否移动多页
private ScrollRect _scrollRect; //ScrollRect组件
private RectTransform content; //ScrollRect组件的Content
//==========ScrollRect的Content的一些参数
private float cellsizeX; //格子的长度X
private float spacingX; //间隔X
private int totalPage; //总页数
private int pageIndex; //当前页的下标
private float[] pagelNormalizedPositon; //每页的NormalizedPositon的值
private float targetNormalizedPosition; //目标的NormalizedPositon的值
private float beginMousePosX; //鼠标开始按下的位置X
private float endMousePosX; //鼠标结束按下的位置X
private bool isDrag; //是否在拖拽
[Header("缓动到目标页的时间")]
public float time; //平滑时间
private float factor; //比例因数
[FormerlySerializedAs("moveOnePageDis")]
[Header("移动一页的距离")]
[Header("==========")]
public float moveOnePageDis; //移动一页的距离
[FormerlySerializedAs("moveMultPageDis")]
[Header("移动多页的距离")]
public float moveMultPageDis; //移动多页的距离
private void Awake()
{
_scrollRect = GetComponent();
content = _scrollRect.content;
totalPage = content.transform.childCount;
cellsizeX = content.GetComponent().cellSize.x;
spacingX = content.GetComponent().spacing.x;
//动态设置Content的大小:sizeDelta = (n-1)*(spacingX+cellsizeX)
_scrollRect.content.sizeDelta = new Vector2((totalPage - 1) * (spacingX + cellsizeX), content.rect.height);
//根据总页数计算每页的NormalizedPosition数值并存储进数组
float tempNormalizedPositon = 0;
pagelNormalizedPositon = new float[totalPage];
int length = pagelNormalizedPositon.Length;
for (int i = 0; i < length; i++)
{
pagelNormalizedPositon[i] = tempNormalizedPositon;
tempNormalizedPositon += 1f / (totalPage - 1);
}
}
private void Update()
{
//缓动到目标页
if (isDrag == false)
{
//Time秒到达目标的NormalizedPosition数值
factor += Time.deltaTime / time;
_scrollRect.horizontalNormalizedPosition = Mathf.Lerp(_scrollRect.horizontalNormalizedPosition, targetNormalizedPosition, factor);
}
}
public void OnBeginDrag(PointerEventData eventData)
{
isDrag = true;
beginMousePosX = Input.mousePosition.x;
}
public void OnEndDrag(PointerEventData eventData)
{
factor = 0;
isDrag = false;
endMousePosX = Input.mousePosition.x;
float offsetX = beginMousePosX - endMousePosX;
if (canMoveMult)
{
//单页移动
if (Mathf.Abs(offsetX) >= moveOnePageDis && Mathf.Abs(offsetX) < moveMultPageDis)
{
//寻找距离当前拖拽结束位置最近的页
float tempHorizontalNormailzed = _scrollRect.horizontalNormalizedPosition;
float minOffset = Mathf.Abs(pagelNormalizedPositon[0] - tempHorizontalNormailzed);
int length = pagelNormalizedPositon.Length;
for (int i = 0; i < length; i++)
{
float tempOffset = Mathf.Abs(pagelNormalizedPositon[i] - tempHorizontalNormailzed);
if (tempOffset <= minOffset)
{
minOffset = tempOffset;
pageIndex = i;
}
}
}
//多页移动
else if (Mathf.Abs(offsetX) >= moveMultPageDis)
{
if (offsetX > 0)
{
pageIndex = totalPage - 1;
}
else if (offsetX < 0)
{
pageIndex = 0;
}
}
//滑动的距离过小
else
{ }
}
else
{
//单页移动
if (Mathf.Abs(offsetX) >= moveOnePageDis)
{
//寻找距离当前拖拽结束位置最近的页
float tempHorizontalNormailzed = _scrollRect.horizontalNormalizedPosition;
float minOffset = Mathf.Abs(pagelNormalizedPositon[0] - tempHorizontalNormailzed);
int length = pagelNormalizedPositon.Length;
for (int i = 0; i < length; i++)
{
float tempOffset = Mathf.Abs(pagelNormalizedPositon[i] - tempHorizontalNormailzed);
if (tempOffset <= minOffset)
{
minOffset = tempOffset;
pageIndex = i;
}
}
} //滑动的距离过小
else
{ }
}
targetNormalizedPosition = pagelNormalizedPositon[pageIndex];
}
}
——通过改变ScrollView下Content的局部位置
using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.UI;
public class ExtensionScrollView : MonoBehaviour, IBeginDragHandler, IEndDragHandler
{
private ScrollRect _scrollRect; //ScrollRect组件
private RectTransform content; //ScrollRect组件的Content
//==========ScrollRect的Content的一些参数
private float cellsizeX; //格子的长度X
private float spacingX; //间隔X
private float onePageDis; //一页的距离
private int totalPage; //总页数
private int currentPage = 1; //当前页
private float targetContentPos; //Content的目标位置X
private float beginMousePosX; //鼠标开始按下的位置X
private float endMousePosX; //鼠标结束按下的位置X
private bool isDrag; //是否在拖拽
[Header("缓动到目标页的时间")]
public float time; //平滑时间
private float factor; //比例因数
[FormerlySerializedAs("moveOnePageDis")]
[Header("移动一页的距离")]
[Header("==========")]
public float moveOnePageDis; //移动一页的距离
[FormerlySerializedAs("moveMultPageDis")]
[Header("移动多页的距离")]
public float moveMultPageDis; //移动多页的距离
private void Awake()
{
_scrollRect = GetComponent();
content = _scrollRect.content;
totalPage = content.transform.childCount;
cellsizeX = content.GetComponent().cellSize.x;
spacingX = content.GetComponent().spacing.x;
onePageDis = cellsizeX + spacingX;
//动态设置Content的大小:sizeDelta = (n-1)*(spacingX+cellsizeX)
_scrollRect.content.sizeDelta = new Vector2((totalPage - 1) * (spacingX + cellsizeX), content.rect.height);
}
private void Update()
{
//缓动到目标页
if (isDrag == false)
{
//Time秒到达targetContentPos的位置
factor += Time.deltaTime / time;
float tempX = Mathf.Lerp(content.localPosition.x, targetContentPos, factor);
content.localPosition = new Vector3(tempX, content.localPosition.y);
}
}
public void OnBeginDrag(PointerEventData eventData)
{
isDrag = true;
beginMousePosX = Input.mousePosition.x;
}
public void OnEndDrag(PointerEventData eventData)
{
factor = 0;
isDrag = false;
endMousePosX = Input.mousePosition.x;
float offsetX = beginMousePosX - endMousePosX;
//单页移动
if (Mathf.Abs(offsetX) >= moveOnePageDis && Mathf.Abs(offsetX) < moveMultPageDis)
{
if (offsetX > 0)
{
if (currentPage + 1 > totalPage)
{
return;
}
currentPage += 1;
targetContentPos -= onePageDis;
}
else if (offsetX < 0)
{
if (currentPage - 1 < 1)
{
return;
}
currentPage -= 1;
targetContentPos += onePageDis;
}
}
//多页移动
else if (Mathf.Abs(offsetX) >= moveMultPageDis)
{
if (offsetX > 0)
{
targetContentPos -= (totalPage - currentPage) * onePageDis;
currentPage = totalPage;
}
else if (offsetX < 0)
{
targetContentPos += (totalPage - currentPage) * onePageDis;
currentPage = 1;
}
}
//滑动的距离过小
else
{ }
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyScrollView : MonoBehaviour {
[Header("======弹性设置=======")]
public bool canOver = false; //是否可以超出内容边界
public float overNum = 0.3f; //超出多少
public float overTime = 0.1f; //弹回时间
[Header("======滑动系数=======")]
public float sliderXStrength = 0.001f; //横向滑动系数
public float sliderYStrength = 0.001f; //纵向滑动系数
[Header("======滑动方向=======")]
public bool horizontal = true; //横向滑动
public bool vertical = true; //纵向滑动
private Transform content; //内容
private float minContentPosX; //内容横向开始位置
private float maxContentPosX; //内容横向结束位置
private float minContentPosY; //内容纵向开始位置
private float maxContentPosY; //内容纵向结束位置
private float mouseBeginPosX; //鼠标横向开始位置
private float mouseEndPosX; //鼠标横向结束位置
private float mouseBeginPosY; //鼠标纵向开始位置
private float mouseEndPosY; //鼠标纵向结束位置
private float valueX = 1.0f;
private float valueY = 1.0f;
private bool isDrag; //判断鼠标是否在滑
private float bounceFri; //SmoothDamp系数
private void Awake()
{
content = transform.Find("Content");
if (horizontal) {
minContentPosX = 540.0f; //内容滑到最左边的位置
maxContentPosX = -540.0f; //内容滑倒最右边的位置
}
if (vertical) {
minContentPosY = 213.0f; //内容滑到最下边的位置
maxContentPosY = -209.0f; //内容滑到最上边的位置
}
}
void Update () {
//鼠标按下,开始滑动,获取鼠标位置
if(Input.GetMouseButtonDown(0))
{
isDrag = true;
if (horizontal) {
mouseBeginPosX = Input.mousePosition.x;
mouseEndPosX = Input.mousePosition.x;
}
if (vertical)
{
mouseBeginPosY = Input.mousePosition.y;
mouseEndPosY = Input.mousePosition.y;
}
else {
return;
}
}
//鼠标抬起,滑动结束
if(Input.GetMouseButtonUp(0))
{
isDrag = false;
}
//滑动过程
if(isDrag)
{
if(Input.GetMouseButton(0))
{
//不断获取鼠标位置的差值,判断方向
mouseBeginPosX = mouseEndPosX;
mouseBeginPosY = mouseEndPosY;
if (horizontal) {
mouseEndPosX = Input.mousePosition.x;
float offsetX = mouseEndPosX - mouseBeginPosX;
valueX += offsetX * sliderXStrength;
if (canOver)
{
valueX = Mathf.Max(0 - overNum, valueX);
valueX = Mathf.Min(valueX, 1 + overNum);
}
else
{
valueX = Mathf.Max(0f, valueX);
valueX = Mathf.Min(valueX, 1f);
}
}
if (vertical) {
mouseEndPosY = Input.mousePosition.y;
float offsetY = mouseEndPosY - mouseBeginPosY;
valueY += offsetY * sliderYStrength;
if (canOver)
{
valueY = Mathf.Max(0 - overNum, valueY);
valueY = Mathf.Min(valueY, 1 + overNum);
}
else
{
valueY = Mathf.Max(0f, valueY);
valueY = Mathf.Min(valueY, 1f);
}
}
}
}
//弹回来的强度
if (horizontal) {
if (valueX > 1f && isDrag == false)
{
valueX = Mathf.SmoothDamp(valueX, 1f, ref bounceFri, overTime);
}
if (valueX < 0f && isDrag == false)
{
valueX = Mathf.SmoothDamp(valueX, 0f, ref bounceFri, overTime);
}
}
if (vertical) {
if (valueY > 1f && isDrag == false)
{
valueY = Mathf.SmoothDamp(valueY, 1f, ref bounceFri, overTime);
}
if (valueY < 0f && isDrag == false)
{
valueY = Mathf.SmoothDamp(valueY, 0f, ref bounceFri, overTime);
}
}
//把value值转换为pos值,赋值给内容的pos
float posX = valueX * (maxContentPosX - minContentPosX) + minContentPosX;
float posY = valueY * (maxContentPosY - minContentPosY) + minContentPosY;
content.localPosition = new Vector3(posX, posY, content.localPosition.z);
}
}