市面上有很多这种无限拖拽的插件 但是功能细化的太严重了 改的话有些耗时 如果没有太多严苛的需求没必要改工程量比较大的插件 完全可以自己写一个

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ItemRect
{public Rect mRect;//格子的索引 因为是用来关联位置的 所以不存在删除或修改操作public readonly int itemIndex;//如果这个位置上存在显示的UI那么将格子的isUse属性设置为truepublic bool isUse = false;public ItemRect(float x,float y,float width,float height,int itemIndex){mRect = new Rect(x,y,width,height);this.itemIndex = itemIndex;}}public interface IItemExecute {//刷新数据void Execute_FinshData();//绑定UIvoid BindUgui();
}//抽象任何地方出每一个滑动单元的公共方法
public class ItemPropoty : MonoBehaviour, IItemExecute
{//储存的数据public object Data;public object DataKey;public ItemRect mDRect;public delegate void FreshFunc(int index);//在初始化的时候给到刷新数据的方法 public FreshFunc onUpdata;public virtual void Execute_FinshData() {BindUgui();if (onUpdata != null)onUpdata(mDRect.itemIndex);}public void Execute_PlacePos(){(transform as RectTransform).sizeDelta = mDRect.mRect.size;(transform as RectTransform).localPosition = mDRect.mRect.position;BindUgui();}/// <summary>/// 绑定UGUI 用名称查询的方式绑定UI类索引/// </summary>public virtual void BindUgui() {}}/// <summary>
/// 定制滑动单元
/// </summary>

  这个用来给定格子位置  在初始化的时候就确认所有格子的位置 这样不用动态的计算

  这里我把那个UI的绑定设计为 尽量使用名字去查询UI 在bindUgui中去查询和添加按钮还有一些其他的回调

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class ItemUnit_1 : ItemPropoty
{Button btn;Text txt;public override void BindUgui(){btn = transform.GetComponentInChildren<Button>();txt = transform.GetComponentInChildren<Text>();txt.text = mDRect.itemIndex.ToString();btn.onClick.AddListener(() => {txt.text = mDRect.itemIndex + " : " + mDRect.itemIndex;});}public void AddImage() {}public void ChangeImage() {}
}

  

把ItemPropoty放在拖拽的单元上面
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
public class CustomScroll : MonoBehaviour
{//用于显示的单元public GameObject itemUnit;private RectTransform item;//这个用来存储UI显示的实例private List<Transform> itemList;//记录所有ui应该显示的位置private Dictionary<int, ItemRect> itemRectDic;//显示的画布public RectTransform mDisplayRect;//上拉是否还有显示单位private bool? isHavePrevious = null;public bool? IsHavePrevious { get => isHavePrevious; }//下拉是否还有显示单位private bool? isHaveSubsequent = null;public bool? IsHaveSubsequent { get => isHaveSubsequent; }private ScrollRect scrollRect;//显示的行数  需要计算private int scrollRow;public int ScrollRow { get => scrollRow; }[Header("行间隙")]public float interval_Veritical;public float Interval_Veritical { get => interval_Veritical + item.rect.height; }//显示的列数private int scrollColumn;public int ScrollColumn { get => scrollColumn; }[Header("列间隙")]public float interval_Horizontal;public float Interval_Horizontal { get => interval_Horizontal + item.rect.width;}void Start(){IntializeScroll();IntializeDisplayCount(2, 30);//TODO FIX 测试用isLoad = true;}//做一些初始化的任务private void IntializeScroll(){itemList = new List<Transform>();waitChangeList = new List<ItemPropoty>();//GetComponentInParent<ScrollRect>().movementType = ScrollRect.MovementType.Clamped;scrollRect = GetComponentInParent<ScrollRect>();itemRectDic = new Dictionary<int, ItemRect>();item = itemUnit.transform as RectTransform;//初始化位置记录previousPagePos = transform.position.y;}/// <summary>/// 先计算出显示的行列/// </summary>public void IntializeDisplayCount(int columnCount, int itemCount) {SetContentSizeDelta(columnCount, itemCount);IntializeDisplayCount(scrollRow, scrollColumn, itemCount);}private void SetContentSizeDelta(int columnCount, int itemCount) {//若乱设置0或复负数直接按1处理scrollColumn = Mathf.Max(1, columnCount);//计算出显示的最大行数  item的长度scrollRow = itemCount / scrollColumn + 1;//设置显示画布的大小(transform as RectTransform).sizeDelta = new Vector2(scrollColumn * Interval_Horizontal,(scrollRow - 1) * Interval_Veritical);}//public void IntializeDisplayCount(int rowCount,int columnCount, int itemCount){//先初始化好格子的位置 在初始化位置的同时设置好显示内容的尺寸AddItemPosition(itemCount);//计算当前显示的数量 存在一个占半格子的问题 暂时未处理 可以使用rect.Overlaps 查看是否相交 根据相交的位置判断加的排数var pageSize = (transform.parent.parent as RectTransform).sizeDelta;//因为间距的问题没处理所以临时加2var pageArea = (int)(pageSize.x / Interval_Horizontal)* (int)(pageSize.y / Interval_Veritical);//TODO FIXint maxDsiplayNum = (int)pageArea + scrollColumn+2;//Debug.Log("当前最大的显示数量 : "+maxDsiplayNum);for (int i = 0; i < scrollRow && i< maxDsiplayNum; i++){Transform tmpItem = GameObject.Instantiate(itemUnit).transform;itemList.Add(tmpItem);tmpItem.localScale = Vector3.one;tmpItem.SetParent(transform, false);//tmpItem.gameObject.AddComponent<ItemUnit_1>();//tmpItem.gameObject.layer = mDisplayRect.gameObject.layer;tmpItem.gameObject.SetActive(false);tmpItem.name = i.ToString();}BenginDisplay();}/// <summary>/// 开始显示UI单元/// </summary>public void BenginDisplay() {//标记显示头for (int i = 0; i < itemRectDic.Count; i++){if (i == itemList.Count)break;//得到物体身上的属性var tmp = itemList[i].GetComponent<ItemPropoty>();//拿到对应的值itemRectDic.TryValueGet(i,out tmp.mDRect);//给定位置tmp.Execute_PlacePos();//将他设置为可见itemList[i].gameObject.SetActive(true);tmp.mDRect.isUse = true;}}private int allItemCount = 0;public int AllItemCount { get => allItemCount; }[Header("x,y轴的初始边距")]public int distance_x = 100;public int distance_y = -50;/// <summary>/// 判断元数是否为追加/// </summary>/// <param name="isSuperaddition"></param>public void AddItemPosition(int nxtCount) {int curRow,curColumn;int tmp = itemRectDic.Count;allItemCount += nxtCount;SetContentSizeDelta(scrollColumn,allItemCount);for (int i = tmp; i < tmp + nxtCount; i++){curRow = i / scrollColumn;curColumn = i % scrollColumn;var itemPos = new ItemRect(curColumn*Interval_Horizontal + distance_x,-curRow*Interval_Veritical + distance_y,item.rect.width,item.rect.height,i);itemRectDic.Add(i,itemPos);}}/// <summary>/// 查询所有排位置的最值元素 /// 做个优化 查询每一排的第一个元素就行了  这样换排的时候 如果是上一排就用index-1 下一排就是 index+scrollColumn(列数)/// </summary>/// <param name="isMax"></param>/// <returns></returns>public Transform GetBestValueItem(bool isMax){if (itemList == null){return null;}Transform bestTmp = itemList[0];for (int i = 0; i < itemList.Count; i += scrollColumn){bool result = isMax ? bestTmp.position.y < itemList[i].position.y : bestTmp.position.y > itemList[i].position.y;if (result){bestTmp = itemList[i];}}// Debug.Log(bestTmp.name);return bestTmp;}/// <summary>/// 查询最值同时把index传出去/// </summary>/// <param name="isMax"></param>/// <param name="index"></param>/// <returns></returns>public Transform GetBestValueItem(bool isMax,out int index){var tmp = GetBestValueItem(isMax);index = tmp.GetComponent<ItemPropoty>().mDRect.itemIndex;return tmp;}private List<ItemPropoty> waitChangeList;/// <summary>/// 查找到元素Y轴位置最小的元素/// </summary>/// <param name="item"></param>private void ExecuteChangeLocation(Transform item,bool isDown){Vector3 minItemPosition = GetBestValueItem(!isDown).position;//开始收集同排的元素位置for (int i = 0; i < itemList.Count; i++){if (itemList[i].Comparer_Position_Y(item.position)) {waitChangeList.SortAdd(itemList[i].GetComponent<ItemPropoty>());}}ChangeLineLocation(isDown);}/// <summary>/// 根据刷新方式做出更改位置操作/// </summary>/// <param name="isDown"></param>private void ChangeLineLocation(bool isDown) {if (waitChangeList == null || waitChangeList.Count == 0) {Debug.LogError("翻车了: ChangeLineLocation 查询失败");return;}//拿到当前最低/高位置的格子var bestValue = GetBestValueItem(!isDown).GetComponent<ItemPropoty>();#region/*int listIndex,itemIndex;for (int i = 0; i < waitChangeList.Count; i++) {if (isDown){itemIndex = bestValue.mDRect.itemIndex + i + scrollColumn;listIndex = i;}else{itemIndex = bestValue.mDRect.itemIndex - (waitChangeList.Count - 1);listIndex = scrollColumn - (waitChangeList.Count - i);}if (itemRectDic.ContainsKey(itemIndex)){//当往下显示的时候将上边隐藏部位的格子释放掉waitChangeList[listIndex].mDRect.isUse = false;//查询到左下角的首元素加上列数个单位之后 正好是下一行的位置waitChangeList[listIndex].mDRect = itemRectDic[itemIndex];waitChangeList[listIndex].Execute_PlacePos();//标记新的占用位置waitChangeList[listIndex].mDRect.isUse = true;}}*/#endregionif (isDown){//Debug.Log("发现最底面的格子 : "+bestValue.name);for (int i = 0; i < waitChangeList.Count; i++){//当再次刷新出现越界的时候    就是画布底面已经没有位置了不需要UI再往下刷新了 跳出去if (itemRectDic.ContainsKey(bestValue.mDRect.itemIndex + i + scrollColumn)){//当往下显示的时候将上边隐藏部位的格子释放掉waitChangeList[i].mDRect.isUse = false;//查询到左下角的首元素加上列数个单位之后 正好是下一行的位置waitChangeList[i].mDRect = itemRectDic[bestValue.mDRect.itemIndex + i + scrollColumn];waitChangeList[i].Execute_PlacePos();//标记新的占用位置waitChangeList[i].mDRect.isUse = true;}}}else{                                                                     for (int i = scrollColumn; i > 0 ; i--){//Debug.Log("获取的值"+(bestValue.mDRect.itemIndex - i));//当再次刷新出现越界的时候    就是画布底面已经没有位置了不需要UI再往下刷新了 跳出去if (itemRectDic.ContainsKey(bestValue.mDRect.itemIndex - i)){//Debug.Log("拾取格子"+(bestValue.mDRect.itemIndex - i));//当往下显示的时候将上边隐藏部位的格子释放掉waitChangeList[scrollColumn -i].mDRect.isUse = false;//查询到左下角的首元素加上列数个单位之后 正好是下一行的位置waitChangeList[scrollColumn - i].mDRect = itemRectDic[bestValue.mDRect.itemIndex -i];waitChangeList[scrollColumn - i].Execute_PlacePos();//标记新的占用位置waitChangeList[scrollColumn - i].mDRect.isUse = true;}}}//改完格子清理表waitChangeList.Clear();}//TODO fix/// <summary>/// 检测元素是否越界 目前的策略 用每排第一个元素进行Y轴判断移动位置/// 所有的元素位置都保存在字典里 找出越界的位置的刷新那一排的位置/// 判断元素向上越界还是向下越界/// </summary>/// <returns></returns>private Transform CheckCrossTheBorder(bool isDown){//Debug.Log("我传入的值 : " + isDown);var tmpMaxItem = GetBestValueItem(isDown);//Debug.Log(tmpMaxItem.position.y+"     " + mDisplayRect.position.y);if(isDown)return tmpMaxItem.position.y > mDisplayRect.position.y ? tmpMaxItem : null;float pageBottom = mDisplayRect.position.y - mDisplayRect.sizeDelta.y;//Debug.Log("查询最小的位置 : "+pageBottom +"                     "+ mDisplayRect.position.y);return tmpMaxItem.position.y < pageBottom ? tmpMaxItem : null;}//查看当前的滑动方向private float previousPagePos;private bool? isSlideDown;// 当isSlideDown为空是表明当前无操作public bool? IsSlideDown { get => isSlideDown;}/// <summary>/// 查看当前滑动的方向 如果页面向上滑动那么Y轴是增加的 反之下滑  如果为空那么就是未参与滑动操作/// </summary>/// <returns></returns>private void CheckCurDirection() {if (transform.position.y == previousPagePos) {isSlideDown = null;return;}isSlideDown = transform.position.y < previousPagePos;previousPagePos = transform.position.y;}private void Update(){CheckCurDirection();if (isSlideDown == null)return;bool isTrue = (bool)isSlideDown;var changeItem = CheckCrossTheBorder(!isTrue);if (changeItem != null)ExecuteChangeLocation(changeItem, !isTrue);//TODO FIX 这里需要严重优化 暂时没考虑好具体方法if (!isTrue) {//Debug.Log("内容框底部点 : "+(transform.position.y-(transform as RectTransform).sizeDelta.y));//Debug.Log("显示框底部点 : "+(mDisplayRect.position.y-(mDisplayRect as RectTransform).sizeDelta.y));var contentPos = (transform.position.y - (transform as RectTransform).sizeDelta.y);var displayPos = (mDisplayRect.position.y - (mDisplayRect as RectTransform).sizeDelta.y);//TODO FIX 临时测试代码if (contentPos - displayPos > 80) {if (isLoad) {transform.parent.parent.GetChild(1).GetComponent<loadState>().SetLoadBar(true);StartCoroutine(LoadItem(20));isLoad = false;}}}}//-----------------------------------------加载模块拓展----------------------------------------private bool isLoad =true;//是否结束异步等待public bool isAsyncWait = true;private IEnumerator LoadItem(int count){while (isAsyncWait){yield return new WaitForSeconds(0.3f);}//TODO FIX 测试用AddItemPosition(count);if (allItemCount > 80)isLoad = false;isAsyncWait = true;}//TODO FIX 测试用}internal static class ExetenceMethod_YC
{//允许三个单位的误差public static bool Comparer_Position_Y(this Transform my,Vector3 other){if (my.position.y > other.y - 3 && my.position.y < other.y + 3)return true;return false;}public static void TryValueGet<TKey,TValue>(this Dictionary<TKey, TValue> my, TKey key, out TValue value) {if (!my.ContainsKey(key)) {Debug.LogError("键为空检测触发处 : Key = "+key);value = default(TValue);return;}my.TryGetValue(key,out value);}public static void SortAdd<T>(this IList<T> list,T TObj,bool isDescending = false) {if (typeof(T) == typeof(ItemPropoty)) {if (list.Count == 0){list.Add(TObj);return;}int insertIndex = isDescending ? 0 : list.Count;if ((TObj as ItemPropoty).mDRect.itemIndex < (list[0] as ItemPropoty).mDRect.itemIndex){list.Insert(list.Count - insertIndex, TObj);}else {list.Insert(insertIndex, TObj);}}}//关于处理间距的问题 计算时存再行列的数量误差 去掉最后一排的间距再进行计算 /*----------------------------------------问题清单------------------------------------------------1,快速拖拽会发生丢失UI现象2,计算行列自动布局显示半个UI的优化3,拓展加载模块功能4,优化下拉判断选项*/
}

  这里还有一些存在的问题...   现在懒得动 以后改...      有哪位朋友使用的话可以联系我qq : 973407312

using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;public class loadState : MonoBehaviour
{public Text[] dot;public bool isLoading;public CustomScroll cs;private float nxtTime = 0;public void SetDot(){}public void SetLoadBar(bool isTrue){isLoading = isTrue;gameObject.SetActive(true);StartCoroutine(Recover());}public void BarFadeAway(){}private int index=0;public void whirl() {index++;index %= dot.Length;StartCoroutine(Bright());}private IEnumerator Bright() {dot[index].gameObject.SetActive(false);yield return new WaitForSeconds(0.18f);dot[index].gameObject.SetActive(true);}private IEnumerator Recover(){yield return new WaitForSeconds(2);cs.isAsyncWait = false;gameObject.SetActive(false);isLoading = false;}void Update(){if (isLoading){nxtTime += Time.deltaTime;if (nxtTime >= 0.2f) {whirl();nxtTime = 0;}}}
}

  可以像这样 制作一个加载提示条  这里弄的有些简陋  可以自己弄个Dotween做个渐入渐出 多给几条提示信息

  demo下载:链接:https://pan.baidu.com/s/1XS6wWAoaYWCA2GbgQUf4CQ

  提取码:ms5r

转载于:https://www.cnblogs.com/chenggg/p/10847581.html

制作一个简易的UGUI无限滑动框(Unity)相关推荐

  1. 制作一个简易的计算器

    这里写自定义目录标题 欢迎使用Markdown编辑器 新的改变 功能快捷键 合理的创建标题,有助于目录的生成 如何改变文本的样式 插入链接与图片 如何插入一段漂亮的代码片 生成一个适合你的列表 创建一 ...

  2. Flutter 制作一个具有酷炫液体滑动效果的酷炫入门页面

    本文主要介绍如何使用 Flutter 制作一个具有酷炫液体滑动效果的酷炫入门页面 我将向您展示如何使用 Flutter 制作一个具有酷炫液体滑动效果的酷炫入门页面,所以不用多说,让我们开始吧.在本课程 ...

  3. [html] 制作一个多选的下拉框

    [html] 制作一个多选的下拉框 定义盒子 a标签 绑定事件 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放弃很容易, 但坚持一定很酷.欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

  4. 使用Java制作一个简易的远控终端

    使用Java制作一个简易的远控终端 远控终端的本质 1.服务端(攻击者)传输消息 ----> socket连接 ----> 客户端(被攻击者)接收消息 2.客户端执行消息内容(即执行服务端 ...

  5. 利用CSS浮动制作一个简易导航栏

    初学CSS,利用CSS浮动和无序列表制作一个简易导航栏: <!DOCTYPE html> <html lang="en"> <head>< ...

  6. 使用 history 对象和 location 对象中的属性和方法制作一个简易的网页浏览工具

    查看本章节 查看作业目录 需求说明: 使用 history 对象和 location 对象中的属性和方法制作一个简易的网页浏览工具 实现思路: 使用history对象中的 forward() 方法和 ...

  7. 用Python制作一个简易的计时器

    前言 今天又带来个小玩意 - 用Python制作一个简易的计时器 这个其实也能自定义一些东西的 就比如名字 颜色啥的 自己看着改就行 有想法的朋友也能自己再写写改改出其他的小功能 效果展示 实现代码 ...

  8. 四节1.5V的5号电池、一个电容、一个12V的报警蜂鸣器、铜线和螺母,在螺母所栓的铜线触发接通电源后,缓慢放电10秒,制作一个简易震动报警器,需要用什么样的电容合适?...

    根据题目描述,需要制作一个简易震动报警器,使用四节1.5V的5号电池作为电源,一个电容,一个12V的报警蜂鸣器,铜线和螺母.在螺母所栓的铜线触发接通电源后,需要缓慢放电10秒. 在这种情况下,需要一个 ...

  9. 使用python制作一个简易的远控终端

    使用python制作一个简易的远控终端 远控终端的本质 1.服务端(攻击者)传输消息 ----> socket连接 ----> 客户端(被攻击者)接收消息 2.客户端执行消息内容(即执行服 ...

最新文章

  1. 【linux】Valgrind工具集详解(十二):DHAT:动态堆分析器
  2. Python:机器学习库 sklearn
  3. 【UML】如何记忆UML类图的画法
  4. Xcode 6 打包ipa文件
  5. Window open()使用方法
  6. 《数据结构与算法分析-C语言描述》习题2.6
  7. 关于tomcat5.5或6.0免安装版,点击startup.bat启动自动消失问题
  8. 闲谈IPv6-尴尬的IPv4
  9. 为什么谈设计总爱提老庄之道
  10. 一起学OCP:oracle-082题库及解析(1-20)
  11. 盖洛普 打破一切常规心得体会(汇集)
  12. PHP回纹判断_第四十八章 回纹考核
  13. 港科夜闻丨香港科大团队最新研究:双色发射AIEgen用于无标记特异性识别dsDNA和SNPs检测...
  14. Google Earth Engine APPS(GEE)—— Landsat 数据的时间序列分析来监测森林转化和退化 (CODED)整体框架(万字长文)
  15. 01-前端工程化概述
  16. 番茄钟App(Pomodoro Tracker)
  17. PAT/C++甲级题解——图
  18. 手把手教你搭建Nightingale夜莺监控系统
  19. E-office OA 任意文件下载漏洞复现
  20. 基于启发式搜索的一字棋

热门文章

  1. 公共供水管网漏损治理智能化管理系统解决方案
  2. 小米2019秋招笔试真题--厨艺大赛奖金
  3. 关于青春的电影有哪些
  4. 用Java实现一个简单的考试系统
  5. APICloud(柚子科技)是一家劣迹斑斑的公司,It is shit!
  6. 打开VT-x/VT-d功能
  7. 超详细!动画图解「合并 K 个排序链表」
  8. java setter和getter_Java Getter和Setter
  9. 论国产PLC产业化发展
  10. 海康设备网络SDK开发NET_DVR_GetDeviceConfig