Unity中关于ScrollRect组件完整解决方案(ScrollRect中元素自动排版+ScrollRect中元素自动定位到Viewport可见范围内)

一、元素自动排版功能

1、首先要往我们的unity项目中导入两个脚本文件,脚本文件名称分别是UIScrollEventListener和CZScrollRect,这两个脚本文件代码如下所示。

1-1、介绍UIScrollEventListener脚本写法。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;public class UIScrollEventListener : MonoBehaviour, IBeginDragHandler, IEndDragHandler , IPointerUpHandler, IPointerDownHandler , IDragHandler
{public delegate void VoidDelegate(PointerEventData pdata);public VoidDelegate onBeginDrag;public VoidDelegate onEndDrag;public VoidDelegate onUp;public VoidDelegate onDown;public VoidDelegate onDrag;bool isDrag = false;List<Image> registers = new List<Image>();public static UIScrollEventListener Get(GameObject go){UIScrollEventListener listener = go.GetComponent<UIScrollEventListener>();if (listener == null) listener = go.AddComponent<UIScrollEventListener>();return listener;}public void OnBeginDrag(PointerEventData eventData){isDrag = true;if (onBeginDrag != null) onBeginDrag(eventData);}public void OnEndDrag(PointerEventData eventData){isDrag = false;if (onEndDrag != null) onEndDrag(eventData);}public void OnPointerUp(PointerEventData eventData){if (!isDrag) {SetRegisterEvent(true);PraseObject(eventData);SetRegisterEvent(false);}if (onUp != null) onUp(eventData);}public void OnPointerDown(PointerEventData eventData){if (onDown != null) onDown(eventData);}public void OnDrag(PointerEventData eventData) {if (onDrag != null) onDrag(eventData);}public void RegisterButton(GameObject go){Image img = go.GetComponent<Image>();if (img != null){img.raycastTarget = false;registers.Add(img);}}void SetRegisterEvent(bool b) {if (registers.Count > 0){for (int i = 0; i < registers.Count; ++i){registers[i].raycastTarget = b;}}}void PraseObject(PointerEventData eventData) {if (registers.Count > 0){for (int i = 0; i < registers.Count; ++i){if (EventSystem.current != null){List<RaycastResult> result = new List<RaycastResult>();EventSystem.current.RaycastAll(eventData, result);foreach (RaycastResult r in result){//Debug.Log(r.gameObject.name);foreach (Image img in registers){if (img.gameObject.Equals(r.gameObject)){InputField inputfield = img.gameObject.GetComponent<InputField>();if (inputfield != null) inputfield.ActivateInputField();}}}}}}}}
1-2、介绍CZScrollRect脚本写法。
using System;
using UnityEngine;
using UnityEngine.UI;public class ScrollObj
{public GameObject obj;public int dex;
}public class CZScrollRect
{public enum TipType{UNDO_REFRESH = 0,PULL_REFRESH = 1,UNDO_APPEND = 2,PULL_AAPEND = 3,NODATA = 4,NONE = 5}const int OPEAT_HEIGHT = 100;//高度差判断操作类型const int INIT_NUM_LIMIT = 8;//列表实例化个数public delegate void OperatDelegate();public delegate void OperatObjDelegate(GameObject obj , int index);public delegate void OperatTextObjDelegate(GameObject obj, TipType t);public OperatDelegate onRefresh;//下拉刷新时回调public OperatDelegate onAppend;//需要加载更多时回调public OperatObjDelegate onScrollObj;//需刷新时回调public OperatTextObjDelegate onUpdateTextObj;//需刷新文本状态时回调public ScrollRect scrollRect;//ScrollRectprivate RectTransform scrollRectContent;//RectTransformpublic GameObject prefab;//实例化的对象public GameObject text_up;//下拉刷新文本public GameObject text_down;//上拉加载更多文本TipType textup_status;int opeartLen = 0;//记录总长度public int layoutwidth = 1242;//填写item的长度public int limitNum = 8;//列表实例化个数public float interval = 200;//每个item的高度public float spacing = 5;//每个tiem的间隔ScrollObj[] list;//用于管理生成的对象int opeartType;int pageindex;//页码bool bHasMore;//是否能加载更多int halfWidth;//public GameObject batchContent;public CZScrollRect(){opeartType = -1;hasMore = false;}/// <summary>/// 用于控制scrollrect是否能够滑动/// (用于等待网络请求等业务)/// </summary>public bool vertical{get{return scrollRect.vertical;}set{scrollRect.vertical = value;}}/// <summary>/// 是否存在更多/// </summary>public bool hasMore{get{return bHasMore;}set{bHasMore = value;}}/// <summary>/// 获取对象所在的索引/// </summary>/// <param name="obj"></param>/// <returns></returns>public int GetObjIndex(GameObject obj) {for(int i = 0; i < list.Length; ++i){if (obj.Equals(list[i].obj)){return list[i].dex;}}return -1;}/// <summary>/// 初始化参数/// </summary>public void Init() {list = new ScrollObj[Mathf.Max(limitNum, INIT_NUM_LIMIT)];scrollRectContent = scrollRect.content;halfWidth = layoutwidth / 2;//此处监听drag事件UIScrollEventListener.Get(scrollRect.gameObject).onDrag = (data) =>{float recty = -scrollRectContent.rect.y - scrollRect.GetComponent<RectTransform>().sizeDelta.y;//Log.Debug($"{scrollRectContent.anchoredPosition.y} , {recty} , {-scrollRectContent.rect.y}");if (scrollRectContent.anchoredPosition.y >= recty + OPEAT_HEIGHT){if (bHasMore){//松开可以加载更多if (textup_status != TipType.UNDO_APPEND) {textup_status = TipType.UNDO_APPEND;if (onUpdateTextObj != null) onUpdateTextObj(text_down, TipType.UNDO_APPEND);}}else{//没有更多数据了if (textup_status != TipType.NODATA){textup_status = TipType.NODATA;if (onUpdateTextObj != null) onUpdateTextObj(text_down, TipType.NODATA);}}opeartType = 1;}else if (scrollRectContent.anchoredPosition.y > recty){if (bHasMore){//上拉可以加载更多if (textup_status != TipType.PULL_AAPEND){textup_status = TipType.PULL_AAPEND;if (onUpdateTextObj != null) onUpdateTextObj(text_down, TipType.PULL_AAPEND);}}else{//没有更多数据了if (textup_status != TipType.NODATA){textup_status = TipType.NODATA;if (onUpdateTextObj != null) onUpdateTextObj(text_down, TipType.NODATA);}}opeartType = -1;}else if (scrollRectContent.anchoredPosition.y <= -OPEAT_HEIGHT){//松开可以刷新if (textup_status != TipType.UNDO_REFRESH){textup_status = TipType.UNDO_REFRESH;if (onUpdateTextObj != null) onUpdateTextObj(text_up, TipType.UNDO_REFRESH);}opeartType = 0;}else if (scrollRectContent.anchoredPosition.y < 0){//下拉可以刷新if (textup_status != TipType.PULL_REFRESH){textup_status = TipType.PULL_REFRESH;if (onUpdateTextObj != null) onUpdateTextObj(text_up, TipType.PULL_REFRESH);}opeartType = -1;}else{opeartType = -1;}UpdateUiInfo();};//此处是监听鼠标点击事件  UIScrollEventListener.Get(scrollRect.gameObject).onUp = (data) =>{if (opeartType == 0){if (onRefresh != null){scrollRect.vertical = false;onRefresh();}}else if (opeartType == 1){if (bHasMore && onRefresh != null){scrollRect.vertical = false;onAppend();}}};scrollRect.onValueChanged.RemoveAllListeners();scrollRect.onValueChanged.AddListener(OnScrollChange);}void OnScrollChange(Vector2 v) {//TOP TO BUTTOM  计算页码int curIndex = Mathf.Min(Mathf.Max(Mathf.FloorToInt(scrollRectContent.anchoredPosition.y / (interval + spacing)) - 1, 0), opeartLen - limitNum);UpdatePageIndex(curIndex);}/// <summary>/// 刷新页面 (重置长度)/// </summary>/// <param name="len"></param>public void Refresh(int len){//Debug.Log($"Refresh len = {len}");if (len < 0)return;int count = 0;for (int i = 0; i < list.Length; ++i) {if (list[i] == null) list[i] = new ScrollObj();if (i < len) {if (list[i].obj == null){list[i].obj = GetNewObject();}list[i].dex = i;list[i].obj.SetActive(true);SetPosition(list[i].obj, list[i].dex);if (onScrollObj != null) onScrollObj(list[i].obj, list[i].dex);count++;}else{if(list[i].obj != null) list[i].obj.SetActive(false);}}opeartLen = len;UpdatePageIndex(0);//重置页码scrollRectContent.localPosition = Vector3.zero;scrollRect.verticalScrollbar.value = 1;UpdateUiInfo();scrollRect.vertical = true;}/// <summary>/// 追加长度/// </summary>/// <param name="len"></param>public void Append(int len){//Debug.Log($"Append len = {len}");if (len < 0) return;if(len == 0){if (onUpdateTextObj != null) {onUpdateTextObj(text_up, TipType.NONE);onUpdateTextObj(text_down, TipType.NONE);}}if (opeartLen < list.Length) {int showlen = Mathf.Min(list.Length - opeartLen , len);//Debug.Log($"showlen = {showlen}");for (int i = 0; i < showlen; ++i) {int dex = opeartLen + i;//Debug.Log(dex);if (list[dex] == null) list[dex] = new ScrollObj();if (list[dex].obj == null){list[dex].obj = GetNewObject();}list[dex].dex = dex;list[dex].obj.SetActive(true);SetPosition(list[i].obj, list[i].dex);if (onScrollObj != null) onScrollObj(list[dex].obj, list[dex].dex);}}opeartLen += len;UpdateUiInfo();scrollRect.vertical = true;}/// <summary>/// 实时刷新页面/// </summary>/// <param name="pdex"></param>void UpdatePageIndex(int pdex) {if (opeartLen <= list.Length || pageindex == pdex) return;//Debug.Log($"pdex = {pdex}");int x = Mathf.FloorToInt(pdex / limitNum);int y = pdex % limitNum;for (int i = 0; i < limitNum; ++i){int d = 0;if (i < y){d = (x + 1) * limitNum + i;}else{d = Mathf.Max(x, 0) * limitNum + i;}if (list[i].dex != d) {list[i].dex = d;if (list[i].obj != null) {SetPosition(list[i].obj, list[i].dex);if (onScrollObj != null) onScrollObj(list[i].obj, list[i].dex);}}}pageindex = pdex;}/// <summary>/// 刷新content的高度/// </summary>void UpdateUiInfo() {//Debug.Log($"opeartLen = {opeartLen} {opeartLen * (interval + spacing)} - {scrollRect.GetComponent<RectTransform>().sizeDelta.y}");scrollRectContent.sizeDelta = new Vector2(0, Math.Max(opeartLen * (interval + spacing), scrollRect.GetComponent<RectTransform>().sizeDelta.y));if(text_up != null) text_up.transform.localPosition = new Vector3(text_up.transform.localPosition.x, OPEAT_HEIGHT - 50, 0);if (text_down != null) text_down.transform.localPosition = new Vector3(text_down.transform.localPosition.x, -scrollRectContent.sizeDelta.y - OPEAT_HEIGHT + 50, 0);}void SetPosition(GameObject obj , int dex) {//obj.transform.localPosition = new Vector3(0, -dex * (interval + spacing) - interval / 2, 0);float y = -dex * (interval + spacing) - interval;obj.transform.GetComponent<RectTransform>().offsetMin = new Vector2(0 , y);obj.transform.GetComponent<RectTransform>().offsetMax = new Vector2(0, y + interval);}GameObject GetNewObject() {return GameObject.Instantiate(prefab, scrollRectContent);}public void Dispose(){scrollRect.onValueChanged.RemoveAllListeners();scrollRect = null;scrollRectContent = null;prefab = null;text_up = null;text_down = null;list = null;onAppend = null;onRefresh = null;onScrollObj = null;}
}

二、测试ScrollRect中元素自动排版案例

1、首先要在我们的场景中搭建好测试的游戏物体,我这个场景中游戏物体的锚点是随便设置的,你们可以根据需要进行对应不同的测试。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2、新增一个TestScrollView脚本用于测试ScrollRect中元素自动排版,TestScrollView脚本完整代码如下。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class TestScrollView : MonoBehaviour
{CZScrollRect scrollcomponent;GameObject item;ScrollRect m_ScrollRect;List<string> str_list = new List<string>{"元素1","元素2","元素3","元素4","元素5","元素6","元素7","元素8","元素9","元素10","元素11","元素12"};private void Awake(){item = transform.Find("Viewport/Item").gameObject;m_ScrollRect = gameObject.GetComponent<ScrollRect>();scrollcomponent = new CZScrollRect();scrollcomponent.prefab = item;scrollcomponent.scrollRect = m_ScrollRect;scrollcomponent.onScrollObj = OnScrollObj;scrollcomponent.interval = 30;scrollcomponent.limitNum = 10000;scrollcomponent.Init();}private void Start(){if (str_list.Count == 0){scrollcomponent.Refresh(0);}else{scrollcomponent.Refresh(str_list.Count);}}void OnScrollObj(GameObject obj, int index){Debug.Log("obj name:" + obj.name + "       index:" + index);obj.transform.Find("Text").GetComponent<Text>().text = str_list[index];}
}

3、ScrollRect中元素自动排版效果展示。

在这里插入图片描述
在这里插入图片描述

二、ScrollRect中元素自动定位到Viewport可见范围内

1、在做之前,需要在项目中导入DOTween插件。

在这里插入图片描述

2、首先要往我们的unity项目中导入一个脚本文件,脚本文件名称是UIScrollRect,这个脚本文件代码如下所示。

using DG.Tweening;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;public class UIScrollRect : ScrollRect
{[SerializeField]private UnityEvent _BeginDragEvent;[SerializeField]private UnityEvent _DragEvent;[SerializeField]private UnityEvent _EndDragEvent;public bool LeftOrUpMove { get; private set; }private Vector3 _BeginDragPosition;private bool _IsDragEnd = false;private bool _UseMoveCenter = false;public bool UseMoveCenter { set { _UseMoveCenter = value; } }private bool _AutoMoveCenter = false;private bool AutoMoveCenter { set { _AutoMoveCenter = value; } }private bool _SkipAnimation = false;private bool _SkipDragDirection = false;private Vector3 _ContentPosition = Vector3.zero;private TweenerCore<Vector3, Vector3, VectorOptions> _DOTweenTo;public UnityEvent BeginDragEvent{set { this._BeginDragEvent = value; }get { return this.BeginDragEvent; }}public UnityEvent DragEvent{set { this._DragEvent = value; }get { return this.DragEvent; }}public UnityEvent EndDragEvent{set { this.EndDragEvent = value; }get { return this._EndDragEvent; }}public override void OnBeginDrag(PointerEventData point){base.OnBeginDrag(point);if (this._DOTweenTo != null)this._DOTweenTo.Pause();this._BeginDragPosition = this.content.localPosition;this._BeginDragEvent?.Invoke();}public override void OnDrag(PointerEventData point){base.OnDrag(point);if (this._DOTweenTo != null){this._DOTweenTo.Pause();this._DOTweenTo = null;}this._DragEvent?.Invoke();}public override void OnEndDrag(PointerEventData point){base.OnEndDrag(point);this._IsDragEnd = true;this._ContentPosition = this.content.localPosition;this.LeftOrUpMove = this.horizontal ? this._BeginDragPosition.x > this._ContentPosition.x : this._BeginDragPosition.y < this._ContentPosition.y;this._EndDragEvent?.Invoke();}protected override void LateUpdate(){base.LateUpdate();if (this._UseMoveCenter && this._IsDragEnd){Vector3 pos = this.content.localPosition;Vector3 offetset = pos - this._ContentPosition;if (Mathf.Abs(this.horizontal ? offetset.x : offetset.y) < 0.2f){this._IsDragEnd = false;if (this._AutoMoveCenter)this.OnItemMoveCenter(null, this._SkipAnimation, this._SkipDragDirection);}this._ContentPosition = pos;}}/// <summary>///	设置中心滑动参数/// </summmary>/// <param name="auto">滑动结束后自动调用OnItemMoveCenter</param>/// <param name="skipAnimation">跳过动画直接设置中心位置</param>/// <parm name"skipDragDirection">忽略滑动方向,查找距离中心位置最近的item滑动</param>public void UseMoveMoveCenter(bool auto = true, bool skipAnimation = false, bool skipDragDirection = false){this._UseMoveCenter = true;this._AutoMoveCenter = auto;this._SkipAnimation = skipAnimation;this._SkipDragDirection = skipDragDirection;_ContentPosition = Vector3.zero;}/// <summary>/// 将target滑动到中文位置,为null时选择距离中心点最近的item滑动/// </summary>/// <param name="target">目标item</param>/// <param name="skipAnimation">跳过动画直接设置中心位置</param>/// <param name="skipDragDirection">忽略滑动方向,查找距离中心位置最近的item滑动</param>public void OnItemMoveCenter(Transform target = null, bool skipAnimation = false, bool skipDragDirection = false){int minIndex = 0;float distance = float.MaxValue;int count = this.content.childCount;if (count == 0)return;RectTransform scrollRectTrans = this.GetComponent<RectTransform>();Vector3 pos = scrollRectTrans.localPosition;//目标存在直接计算到中心位置的距离if (target != null){RectTransform item = target.GetComponent<RectTransform>();// 使用Transform转换方法InverseTransformPoint,将item的世界坐标转化为Transform的局部坐标pos = scrollRectTrans.InverseTransformPoint(item.position);// 需要注意的事是item的锚点不同带来的偏差,这里锚点的标准值为(0.5f, 0.5f)即锚点在中心位置, 若不是标准值就要去除width和heigth的值Vector2 pivot = item.pivot;//滑动方向优先计算水平滑动,verticaldistance = this.horizontal ? (0.5f - pivot.x) * item.rect.width - pos.x : (pivot.y - 0.5f) * item.rect.height - pos.y;}else{// 遍历计算,距离中心点最近的距离以及对应的索引值for (int i = 0; i < count; i++){RectTransform item = this.content.GetComponent<RectTransform>();// 使用Transform转换方法InverseTransformPoint,将item的世界坐标转化为Transform的局部坐标pos = scrollRectTrans.InverseTransformPoint(item.position);// 需要注意的事是item的锚点不同带来的偏差,这里锚点的标准值为(0.5f, 0.5f)即锚点在中心位置, 若不是标准值就要去除width和heigth的值Vector2 pivot = item.pivot;//滑动方向优先计算水平滑动,verticalfloat dis = this.horizontal ? (0.5f - pivot.x) * item.rect.width - pos.x : (pivot.y - 0.5f) * item.rect.height - pos.y;if (Mathf.Abs(distance) > Mathf.Abs(dis)){distance = dis;minIndex = i;}}}bool dragDirection = !skipDragDirection && target == null;distance = this.horizontal ? this.CalculateHorizontalDistance(distance, minIndex, count, dragDirection) : this.CalculateVerticalDistance(distance, minIndex, count, dragDirection);pos = this.content.localPosition;if (this.horizontal)pos.x = distance;elsepos.y = distance;// 跳过动画,直接设置坐标if (skipAnimation){this.content.localPosition = pos;return;}//使用dotween动画移动, elasticity滑到头回弹的时间_DOTweenTo = (TweenerCore<Vector3, Vector3, VectorOptions>)this.content.DOLocalMove(pos, this.elasticity).OnComplete(() =>{this._DOTweenTo = null;});}/// <summary>/// 计算水平方向到中心点位置距离/// </summary>private float CalculateHorizontalDistance(float distance, int minIndex, int count, bool dragDirection){RectTransform rect = this.GetComponent<RectTransform>();//防止回弹计算//当item为null时,查找距离中心点最近的item,并滑动到中心点,当鼠标拖拽滑动结束时,自动移动到中心点的方向可能与鼠标拖拽方向相反,因此需要计算,不要计算时将_SkipDragDirection 设置为trueif (dragDirection){int index = minIndex;float dis = distance;//使用while,是因为可能存在多列,相同列上的距离是一样的,需要多次查找拖拽方向上的itemwhile (index < count && index >= 0 && dis == distance){if (this.LeftOrUpMove){if (distance > 0)index++;}else if (distance < 0)index--;if (index == minIndex)break;RectTransform item = this.content.GetChild(index).GetComponent<RectTransform>();Vector2 pivot = item.pivot;Vector3 pos = rect.InverseTransformPoint(item.position);distance = (pivot.x - 0.5f) * item.rect.width - pos.x;}distance += this.content.localPosition.x;if (this.movementType != ScrollRect.MovementType.Unrestricted){if (distance >= 0)distance = 0;else{float dragMaxDistance = rect.rect.width - this.content.rect.width;if (distance < dragMaxDistance)distance = dragMaxDistance;}}}return distance;}/// <summary>/// 计算水平方向到中心点位置距离/// </summary>private float CalculateVerticalDistance(float distance, int minIndex, int count, bool dragDirection){RectTransform rect = this.GetComponent<RectTransform>();//防止回弹计算//当item为null时,查找距离中心点最近的item,并滑动到中心点,当鼠标拖拽滑动结束时,自动移动到中心点的方向可能与鼠标拖拽方向相反,因此需要计算,不要计算时将_SkipDragDirection 设置为trueif (dragDirection){float dis = distance;int index = minIndex;//使用while,是因为可能存在多行,相同列上的距离是一样的,需要多次查找拖拽方向上的itemwhile (index < count && index >= 0 && dis == distance){if (this.LeftOrUpMove){if (distance < 0)index++;}else if (distance > 0)index--;if (index == minIndex)break;RectTransform item = this.content.GetChild(index).GetComponent<RectTransform>();Vector2 pivot = item.pivot;Vector3 pos = rect.InverseTransformPoint(item.position);distance = (pivot.y - 0.5f) * item.rect.height - pos.y;}}distance += this.content.localPosition.y;//Unrestricted滑动到头没有回弹,有回弹的无法将最后或者最前的item移动到中心点位置if (this.movementType != ScrollRect.MovementType.Unrestricted){if (distance <= 0)distance = 0;else{float dragMaxDistance = this.content.rect.height - rect.rect.height;if (distance > dragMaxDistance)distance = dragMaxDistance;}}return distance;}
}

3、修改游戏场景中名为Scroll View游戏物体身上的ScrollRect组件,修改方式就是把ScrollRect组件替换成上述的UIScrollRect。

3-1、没修改前Scroll View游戏物体身上的ScrollRect组件效果如下所示。

在这里插入图片描述

3-2、修改后Scroll View游戏物体身上的ScrollRect组件效果如下所示。

在这里插入图片描述

4、修改TestScrollView脚本测试ScrollRect中元素自动定位到Viewport可见范围内是否可行,TestScrollView脚本完整代码如下。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class TestScrollView : MonoBehaviour
{CZScrollRect scrollcomponent;GameObject item;ScrollRect m_ScrollRect;UIScrollRect m_UIScrollRect;GameObject m_targetGo;   //需要定位到的元素物体List<string> str_list = new List<string>{"元素1","元素2","元素3","元素4","元素5","元素6","元素7","元素8","元素9","元素10","元素11","元素12","元素13","元素14","元素15","元素16","元素17","元素18","元素19","元素20"};private void Awake(){item = transform.Find("Viewport/Item").gameObject;m_ScrollRect = gameObject.GetComponent<ScrollRect>();m_UIScrollRect = gameObject.GetComponent<UIScrollRect>();scrollcomponent = new CZScrollRect();scrollcomponent.prefab = item;scrollcomponent.scrollRect = m_ScrollRect;scrollcomponent.onScrollObj = OnScrollObj;scrollcomponent.interval = 30;scrollcomponent.limitNum = 10000;scrollcomponent.Init();}private void Start(){if (str_list.Count == 0){scrollcomponent.Refresh(0);}else{scrollcomponent.Refresh(str_list.Count);}Debug.Log("m_targetGo:" + m_targetGo);m_UIScrollRect.OnItemMoveCenter(m_targetGo.GetComponent<RectTransform>());}void OnScrollObj(GameObject obj, int index){//假设我们想要让元素10在Viewport可见范围内居中显示if (index == 9){m_targetGo = obj;obj.transform.Find("Text").GetComponent<Text>().text = "定位元素" + str_list[index];}else{obj.transform.Find("Text").GetComponent<Text>().text = str_list[index];}Debug.Log("obj name:" + obj.name + "       index:" + index);}
}

5、ScrollRect中元素自动定位到Viewport可见范围内效果展示,正是我们想要的让第10个元素在Viewport可见范围内居中显示。

在这里插入图片描述

三、注意事项

1、注意以下图中Scrollbar组件红框中元素的设置,最好和我的设置一样。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/258831.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

比特币突然大涨

作者&#xff1a;秦晋 2月9日&#xff0c;除夕夜&#xff0c;比特币突然大涨&#xff0c;最高涨至48219美元&#xff0c;涨幅超6%。据CNBC报道&#xff0c;本周比特币已经上涨10.76%&#xff0c;创下自12月8日以来的最佳的一周。本周ETH上涨8.46%&#xff0c;成为自1月12日以来…

SpringBoot+Tess4J实现本地与远程图片的文字识别

Spring Boot应用程序里集成Tess4J来实现OCR&#xff08;光学字符识别&#xff09;&#xff0c;以识别出本地和远程图片中的文字 一、添加依赖 <dependency><groupId>net.sourceforge.tess4j</groupId><artifactId>tess4j</artifactId><vers…

MongoDB数据库又被勒索攻击了

前言 朋友发来一张图片&#xff0c;说MongoDB数据库被勒索了&#xff0c;问我是哪个家族的...... &#xff08;上图来源于网络)&#xff0c;当笔者看到朋友发的图片之后&#xff0c;判断应该是黑客入侵了MongoDB数据库服务器&#xff0c;然后删除了数据库里面的数据&#xff0…

Sora 文生视频提示词实例集 2

Prompt: Historical footage of California during the gold rush. 加利福尼亚淘金热期间的历史影像。 Prompt: A close up view of a glass sphere that has a zen garden within it. There is a small dwarf in the sphere who is raking the zen garden and creating patter…

C#,二进制数的非0位数统计(Bits Count)的算法与源代码

计算一个十进制数的二进制表示有多少位1&#xff1f; 1 遍历法&#xff08;递归或非递归&#xff09; 使用循环按位统计1的个数。 2 哈希查表法 利用一个数组或哈希生成一张表&#xff0c;存储不同二进制编码对应的值为1的二进制位数&#xff0c;那么在使用时&#xff0c;只…

Stable Diffusion教程——使用TensorRT GPU加速提升Stable Diffusion出图速度

概述 Diffusion 模型在生成图像时最大的瓶颈是速度过慢的问题。为了解决这个问题&#xff0c;Stable Diffusion 采用了多种方式来加速图像生成&#xff0c;使得实时图像生成成为可能。最核心的加速是Stable Diffusion 使用了编码器将图像从原始的 3512512 大小转换为更小的 46…

美国突然致敬中本聪

作者&#xff1a;秦晋 有点看不懂美国的神操作。 2月16日&#xff0c;据《Bitcoin Magazine》报道&#xff0c;比特币的竞争对手、美国参议员伊丽莎白-沃伦对比特币的立场突然180度大转弯。由反对立场转为支持立场。让很多行业媒体出乎意料&#xff0c;甚至惊掉下巴。 报道称&a…

重塑高校评价体系,缓解内卷,培养有远见的研究者

重塑高校评价体系&#xff0c;缓解内卷&#xff0c;培养有远见的研究者 摘要&#xff1a;当前高等教育和科研环境中普遍存在的“非升即走”制度&#xff0c;尽管表面上看似激励科研人员努力工作&#xff0c;但实际上反映了学术界的内卷状况。这一制度的设置在人才供过于求的背景…

mac无法往硬盘里存东西 Mac硬盘读不出来怎么办 Mac硬盘格式 硬盘检测工具

mac有时候会出现一些问题&#xff0c;比如无法往硬盘里存东西&#xff0c;或者无法往硬盘上拷贝文件。这些问题会给用户带来很大的困扰&#xff0c;影响正常的工作和学习。那么&#xff0c;mac无法往硬盘里存东西&#xff0c;mac无法往硬盘上拷贝怎么办呢&#xff1f;软妹子将为…

小苯的数组切分 ---- 牛客月赛

题目描述 qionghuaqionghuaqionghua 给了小苯一个长度为 n 的数组 a&#xff0c;希望小苯将数组 aaa 分为恰好非空的三段。即&#xff1a;[1,l−1],[l,r],[r1,n]这三段&#xff0c;其中 1< l≤r<n。接着&#xff1a; ∙ 第一段的所有数字做 ⊕&#xff08;按位异或&…

模拟算法.

1.什么是模拟 在信息奥赛中,有一类问题是模拟一个游戏的对弈过程或者模拟一项任务的操作过程.比如乒乓球在比赛中模拟统计记分最终判断输赢的过程等等,这些问题通常很难通过建立数学模型用特定的算法来解决因为它没有一种固定的解法,需要深刻理解出题者对过程的解释一般只能采…

双指针算法+例题

1、性质 双指针算法&#xff0c;实质上是把朴素算法O&#xff08;n^2),发现一些性质&#xff0c;转换成 O&#xff08;N&#xff09;时间复杂度。 2、图解核心思想 3、代码模板 for(int i0,j0;i<n;i) {while(j<i && check(i,j)) j;//每道题目的具体逻辑 } 4…

【电路笔记】-LR串联电路

LR串联电路 文章目录 LR串联电路1、概述2、示例1所有线圈、电感器、扼流圈和变压器都会在其周围产生磁场,由电感与电阻串联组成,形成 LR 串联电路。 1、概述 在本节有关电感器的第一个文章中,我们简要介绍了电感器的时间常数,指出流过电感器的电流不会瞬时变化,而是会以恒…

相机图像质量研究(31)常见问题总结:图像处理对成像的影响--图像差

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

C++初阶(十一) list

一、list的介绍及使用 1.1 list的介绍 list的文档介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 2. list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点…

政安晨:在Jupyter中【示例演绎】Matplotlib的官方指南(二){Image tutorial}·{Python语言}

咱们接着上一篇&#xff0c;这次咱们讲使用Matplotlib绘制图像的简短尝试。 我的这个系列的上一篇文章在这里&#xff1a; 政安晨&#xff1a;在Jupyter中【示例演绎】Matplotlib的官方指南&#xff08;一&#xff09;{Pyplot tutorial}https://blog.csdn.net/snowdenkeke/ar…

Flex布局简介及微信小程序视图层View详解

目录 一、Flex布局简介 什么是flex布局&#xff1f; flex属性 基本语法和常用属性 Flex 布局技巧 二、视图层View View简介 微信小程序View视图层 WXML 数据绑定 列表渲染 条件渲染 模板 WXSS 样式导入 内联样式 选择器 全局样式与局部样式 WXS 示例 注意事项…

深入理解lambda表达式

深入理解ASP.NET Core中的中间件和Lambda表达式 var builder WebApplication.CreateBuilder(args); var app builder.Build(); app.Use(async (context, next) > { // Add code before request. await next(context);// Add code after request.}); 这段C#代码是用于设…

论文阅读:GamutMLP A Lightweight MLP for Color Loss Recovery

这篇文章是关于色彩恢复的一项工作&#xff0c;发表在 CVPR2023&#xff0c;其中之一的作者是 Michael S. Brown&#xff0c;这个老师是加拿大 York 大学的&#xff0c;也是 ISP 领域的大牛&#xff0c;现在好像也在三星研究院担任兼职&#xff0c;这个老师做了很多这种类似的工…

C++数据结构与算法——双指针法

C第二阶段——数据结构和算法&#xff0c;之前学过一点点数据结构&#xff0c;当时是基于Python来学习的&#xff0c;现在基于C查漏补缺&#xff0c;尤其是树的部分。这一部分计划一个月&#xff0c;主要利用代码随想录来学习&#xff0c;刷题使用力扣网站&#xff0c;不定时更…