惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threat Research - Cisco Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Register - Security
The Register - Security
A
About on SuperTechFans
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
L
LangChain Blog
N
Netflix TechBlog - Medium
量子位
博客园 - 三生石上(FineUI控件)
宝玉的分享
宝玉的分享
H
Help Net Security
D
Docker
D
DataBreaches.Net
T
Tailwind CSS Blog
阮一峰的网络日志
阮一峰的网络日志
B
Blog
博客园 - 聂微东
Apple Machine Learning Research
Apple Machine Learning Research
Google DeepMind News
Google DeepMind News
The Cloudflare Blog
F
Full Disclosure
GbyAI
GbyAI
F
Fortinet All Blogs
Last Week in AI
Last Week in AI
Y
Y Combinator Blog
人人都是产品经理
人人都是产品经理
Recent Announcements
Recent Announcements
博客园 - Franky
MongoDB | Blog
MongoDB | Blog
有赞技术团队
有赞技术团队
博客园 - 叶小钗
小众软件
小众软件
V
Visual Studio Blog
月光博客
月光博客
Stack Overflow Blog
Stack Overflow Blog
The GitHub Blog
The GitHub Blog
Recorded Future
Recorded Future
J
Java Code Geeks
雷峰网
雷峰网
P
Privacy & Cybersecurity Law Blog
C
Cisco Blogs
C
Cyber Attacks, Cyber Crime and Cyber Security
AWS News Blog
AWS News Blog
Webroot Blog
Webroot Blog
美团技术团队
N
News | PayPal Newsroom
G
Google Developers Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
博客园_首页
V
Vulnerabilities – Threatpost

元视角

.NET 生态下的 Agent 框架选型:从 ReAct 到原生推理 - 元视角 从「能用」到「好用」:LLM 流式响应实现方式的探索之路 - 元视角 当我用 2000 条聊天记录,让 AI 为我画一幅自画像 - 元视角 基于 Supabase 的 AI 应用开发探索 - 元视角 微博 × MCP:社交媒体新玩法解锁 - 元视角 四点钟海棠花未眠 - 元视角 Semantic Kernel × MCP:智能体的上下文增强探索 - 元视角 基于 K-Means 聚类分析实现人脸照片的快速分类 - 元视角 容器技术驱动下的代码沙箱实践与思考 - 元视角 温故而知新:后端通用查询方案的再思考 - 元视角 浅议 CancellationToken 在前后端协同取消场景中的应用 - 元视角 Semantic Kernel 视角下的 Text2SQL 实践与思考 - 元视角 关于 ChatGPT 的流式传输,你需要知道的一切 - 元视角 RAG 的是与非、Rewrite 和 Rerank - 元视角 使用 EFCore 和 PostgreSQL 实现向量存储及检索 - 元视角 基于 LLaMA 和 LangChain 实践本地 AI 知识库 - 元视角 使用 llama.cpp 在本地部署 AI 大模型的一次尝试 - 元视角 如何为 Git 配置多个 SSH Key - 元视角 C# 使用 LibUsbDotNet 实现 USB 设备检测 - 元视角 基于 C# 实现样式与数据分离的打印方案 - 元视角 基于 SVG 的图形交互方案实践 - 元视角 前端视频播放技术概览 - 元视角 温故而知新,再话 Python 动态导入 - 元视角 后 GPT 时代,NLP 不存在了? - 元视角 视频是不能 P 的系列:使用 Milvus 实现海量人脸快速检索 - 元视角 GDI+下字体大小自适应方案初探 - 元视角 小爱音箱集成 ChatGPT 的不完全教程 - 元视角 程序员视角下的三体世界随想 - 元视角 关于 Docker 容器配置信息的渐进式思考 - 元视角 在 Docker 容器内集成 Crontab 定时任务 - 元视角 为你的服务器集成 LDAP 认证 - 元视角 似花还似非花 - 元视角 视频是不能 P 的系列:使用 Dlib 实现人脸识别 - 元视角 浅议分布式链路追踪与日志的整合 - 元视角 关于 Git 大文件上传这件小事 - 元视角 .NET 进程内队列 Channel 的入门与应用 - 元视角 使用 Fody 实现 .NET 的静态编织 - 元视角 .NET Core + ELK 搭建可视化日志分析平台(下) - 元视角 聊一聊前端图片懒加载背后的故事 - 元视角 支持外部链接跳转的 Vue Router 扩展实现 - 元视角 视频是不能 P 的系列:OpenCV 和 Dlib 实现表情包 - 元视角 不得不说的 ASP.NET Core 集成测试 - 元视角 再议 DDD 视角下的 EFCore 与 领域事件 - 元视角 Vue.js 前端项目容器化部署实践极简教程 - 元视角 再见,人间四月天 - 元视角 Python 图像风格化迁移助力画家梦想 - 元视角 利用 ASP.NET Core 中的标头传播实现分布式链路追踪 - 元视角 利用 gRPC 实现文件的上传与下载 - 元视角 七种武器:延迟队列的原理和实现总结 - 元视角 gRPC 流式传输极简入门指南 - 元视角 Envoy 集成 Jaeger 实现分布式链路追踪 - 元视角 浅议非典型 Web 应用场景下的身份认证 - 元视角 gRPC 借助 Any 类型实现接口的泛化调用 - 元视角 分布式丛林探险系列之 Redis 集群模式 - 元视角 分布式丛林探险系列之 Redis 主从复制模式 - 元视角 通过 Python 预测 2021 年双十一交易额 - 元视角 gRPC 搭配 Swagger 实现微服务文档化 - 元视角 SSL/TLS 加密传输与数字证书的前世今生 - 元视角 使用 Python 自动识别防疫健康码 - 元视角 你不可不知的容器编排进阶技巧 - 元视角 ASP.NET Core 搭载 Envoy 实现 gRPC 服务代理 - 元视角 再话 AOP,从简化缓存操作说起 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务身份认证(JWT) - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的监控预警 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的反向代理 - 元视角 ASP.NET Core gRPC 打通前端世界的尝试 - 元视角 EFCore 实体命名约定库:EFCore.NamingConventions - 元视角 ASP.NET Core gRPC 集成 Polly 实现优雅重试 - 元视角 ASP.NET Core gRPC 健康检查的探索与实现 - 元视角 ASP.NET Core gRPC 拦截器的使用技巧分享 - 元视角 SnowNLP 使用自定义语料进行模型训练 - 元视角 使用 HttpMessageHandler 实现 HttpClient 请求管道自定义 - 元视角 ABP vNext 的实体与服务扩展技巧分享 - 元视角 ABP vNext 对接 Ant Design Vue 实现分页查询 - 元视角 源代码探案系列之 .NET Core 跨域中间件 CORS - 元视角 源代码探案系列之 .NET Core 限流中间件 AspNetCoreRateLimit - 元视角 源代码探案系列之 .NET Core 并发限制中间件 ConcurrencyLimiter - 元视角 通过 EmbededFileProvider 实现 Blazor 的静态文件访问 - 元视角 低代码,想说爱你不容易 - 元视角 记一次失败的 ThoughtWorks 面试经历 - 元视角 从 C# 1.0 到 C# 9.0,历代 C# 语言特性一览 - 元视角 通过 Python 分析 2020 年全年微博热搜数据 - 元视角 基于 Python 和 Selenium 实现 CSDN 一键三连自动化 - 元视角 使用多线程为你的 Python 爬虫提速的 N 种姿势,你会几种? - 元视角 实现网页长截图的常见思路总结 - 元视角 温故而知新,由 ADO.NET 与 Dapper 所联想到的 - 元视角 视频是不能 P 的系列:OpenCV 人脸检测 - 元视角 作为技术宅的我,是这样追鬼滅の刃的 - 元视角 使用 Python 抽取《半泽直树》原著小说人物关系 - 元视角 厉害了!打工人用 Python 分析西安市职位信息 - 元视角 使用 dotTrace 对 .NET 应用进行性能分析与优化 - 元视角 一道 HashSet 面试题引发的蝴蝶效应 - 元视角 基于选项模式实现.NET Core 的配置热更新 - 元视角 Dapper.Contrib 在 Oracle 环境下引发 ORA-00928 异常问题的解决 - 元视角 .NET Core 中对象池(Object Pool)的使用 - 元视角 利用 MySQL 的 Binlog 实现数据同步与订阅(下):EventBus 篇 - 元视角 利用 MySQL 的 Binlog 实现数据同步与订阅(中):RabbitMQ 篇 - 元视角 利用 MySQL 的 Binlog 实现数据同步与订阅(上):基础篇 - 元视角 记一次从已损坏的 Git 仓库中找回代码的经历 - 元视角 .NET Core 原生 DI 扩展之属性注入实现 - 元视角
Unity3D 游戏开发之分页效果在 uGUI 中的实现 - 元视角
飞鸿踏雪 · 2015-11-11 · via 元视角

各位朋友大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是:http://qinyuanpei.com。今天想和大家分享的是 uGUI 中分页效果的实现,我们知道相对 NGUI 来说 uGUI 在功能覆盖上来讲,它并没有像 NGUI 那样提供较为丰富和炫酷的组件,可是因为 uGUI 有着较好的扩展性,因此我们可以通过编写脚本来扩展它的功能。虽然在移动开发时代以开发速度论成败,可是这并不是我们“不求甚解”的正当理由。每次看到 NGUI 各种"丰富"的组件在脑海中打转的时候,每次看到编译项目时弹出各种 Warming 的时候,我内心是如此地期望有这样一个简单高效的 UI 系统啊,直到有一天我遇上了 uGUI。

好了,博主这里并没有想要表达厚此薄彼的观点啦,博主真正想要表达的是我们在开发中应该摒弃“唯语言论”、“唯平台论”的狭隘观点,努力去掌握和语言无关、平台无关的“通用型技能”。这样,当我们面对全新的任务的时候我们可以更快地适应新的环境。言归正传,我们这里来接着说 uGUI 中的分页,分页通常是指将内容分散到不同的页面上来显示的一种手段,这种手段我们在传统的 Web 开发中可以经常看到。到了移动互联网以后分页被我们更为熟知的“下拉更新”所替代,这种方式我们就更为熟悉啦。好了,我们回到分页,为什么要要分页呢?这里有两个关键点:第一,内容在一页内无法展示完全;第二,对内容的数量无法进行估计。

例如,我们在 uGUI 中可以使用 ScrollRect 组件 + GridLayout 组件 + Mask 组件实现一个滚动列表,具体的案例可以参考:这里。这里我们可以注意到一件事情就是这个滚动列表,它可以滚动的范围是由 Mask 组件来决定的,因此这个滚动列表是无法无限滚动的,虽然我们知道在游戏设计中不会出现这种无限滚动的列表,可是我们这里是为了探讨这个问题,所以我们假设这个情况是允许发生的。那么面对这个问题,我们有什么好的解决方案呢?博主尝试过一种思路,即借鉴 Android 中的 ListView 控件,这个控件的特点是可以对列表中的项目进行回收。相信说到这里,大家都明白我想做什么了吧,大概的思路就是制作一个高度大于屏幕高度的列表,然后让所有的列表项在这个列表中循环显示。可是新的问题就来了,第一,频繁地生成和销毁物体是 Unity3D 大忌。虽然我们可以缓存池来解决这个问题,可是因为博主并没有具体这样实践过,所以这里目前是存疑的。**第二,GridLayout 这个组件内的元素排序是根据子元素添加的顺序来决定的,因此每次列表更新以后都需要将所有的子元素更新一遍。**曾经因为这样需求和策划发生过争执,最终妥协的一个结果就是采用分页来解决这个问题。分页首先解决了无限滚动的需求,因为它是一种“以不变应万变”的策略,不论列表内元素有多少它都可以显示出来。其次,在分页的过程是将数据模板化的过程,它改变是界面的外观和行为,UI 结构是相对稳定的,这样可以避免频繁地生成和销毁物体。

下面我们以一个简单的案例来探讨分页效果在 uGUI 中的实现,首先我们使用 GridLayoutGroup 来制作一个简单的网格布局,请用心感受下图中萌萌哒十二生肖:

请不要伤害一个程序员的艺术细胞,虽然我知道它比较难看 请不要伤害一个程序员的艺术细胞,虽然我知道它比较难看

这里我们不再对这个布局的制作方法进行详细的说明,因为我们今天的重点不在这里。我们注意到这里有 12 个元素,当我们每次对页面进行切换的时候,实际上这 12 个元素是基本不会发生变化的,真正变化的是这些元素的外观(如这里的精灵图片和名称)以及其对应的 UI 事件,在这个案例中我们利用匿名函数实现了一个简单的 Click 事件的监听。好了,前面我们说到分页的一个目的是可以解决列表内元素数目不确定的问题,因此我们这里利用一个 12 生肖的数组来随机生成元素数目不同的列表,代码实现如下:

	/// <summary>
    /// 初始化元素
    /// </summary>
    private void InitItems()
    {
        //准备一个存储着12生肖信息的数组
        GridItem[] items = new GridItem[]
        {
            new GridItem("鼠","Mouse"),
            new GridItem("牛","Ox"),
            new GridItem("虎","Tiger"),
            new GridItem("兔","Rabbit"),
            new GridItem("龙","Dragon"),
            new GridItem("蛇","Snake"),
            new GridItem("马","Horse"),
            new GridItem("羊","Goat"),
            new GridItem("猴","Monkey"),
            new GridItem("鸡","Rooster"),
            new GridItem("狗","Dog"),
            new GridItem("猪","Pig")
        };

        //利用12生肖数组来随机生成列表
        m_ItemsList = new List<GridItem>();
        for(int i = 0; i < Random.Range(1,1000); i++)
        {
            m_ItemsList.Add(items[Random.Range(0,items.Length)]);
        }

        //计算元素总个数
        m_ItemsCount = m_ItemsList.Count;
        //计算总页数
        m_PageCount = (m_ItemsCount % 12) == 0 ? m_ItemsCount / 12 : (m_ItemsCount / 12) + 1;

        BindPage(m_PageIndex);
        //更新界面页数
        m_PanelText.text = string.Format("{0}/{1}",
        m_PageIndex.ToString(),
        m_PageCount.ToString());
    }

在这段代码中,m_ItemList 表示我们要展示的元素列表,m_ItemsCount 表示元素列表中元素的个数,m_PageCount 表示这些元素可以分成的总页数,m_PageIndex 表示页数的索引默认从 1 开始。其中 GridItem 是一个简单的类,它有 ItemName 和 ItemSprite 两个属性,这里不再具体说明了。好了,现在我们来思考如何将这些元素和 UI 对应起来,因为列表中元素的数目不确定,因此我们可以分成两种情况来讨论:

  • 页面总数为 1,即 m_PageCount=1,此时列表内的元素个数的范围是 1~12,因此我们可以利用循环判断哪些元素是要展示的?哪些元素是不需要的?因为如果此时列表内的元素为 10,则意味着前面 10 个元素是要展示给用户,而剩下的 2 个元素是不需要的。在这里我们简单地使用 SetActive 来让这些元素隐藏起来。

  • 页面总数大于 1,即 m_PageCount>1,此时前面的 m_PageCount-1 个页面都是显示完全的,它相当于元素总个数中被 12 整除的部分。而第 m_PageCount 个页面此时的情况和页数总数为 1 的情况类似,我们可以采取和页面总数为 1 类似的方法来处理。

好了,下面我们来看这部分代码的具体实现:

    /// <summary>
    /// 绑定指定索引处的页面元素
    /// </summary>
    /// <param name="index">页面索引</param>
    private void BindPage(int index)
    {
        //列表处理
        if (m_ItemsList == null || m_ItemsCount <= 0)
            return;

        //索引处理
        if (index < 0 || index > m_ItemsCount)
            return;

        //按照元素个数可以分为1页和1页以上两种情况
        if (m_PageCount == 1)
        {
            int canDisplay = 0;
            for (int i = 12; i > 0; i--)
            {
                if (canDisplay < 12){
                    BindGridItem(transform.GetChild(canDisplay), m_ItemsList[12 - i]);
                    transform.GetChild(canDisplay).gameObject.SetActive(true);
                } else {
                    //对超过canDispaly的物体实施隐藏
                    transform.GetChild(canDisplay).gameObject.SetActive(false);
                }
                canDisplay += 1;
            }
        }
        else if (m_PageCount > 1) {
            //1页以上需要特别处理的是最后1页
            //和1页时的情况类似判断最后一页剩下的元素数目
            //第1页时显然剩下的为12所以不用处理
            if(index == m_PageCount){
                int canDisplay = 0;
                for(int i = 12; i > 0; i--)
                {
                    //最后一页剩下的元素数目为 m_ItemsCount - 12 * (index-1)
                    if (canDisplay < m_ItemsCount - 12 * (index-1)){
                        BindGridItem(transform.GetChild(canDisplay), m_ItemsList[12 * index-i]);
                        transform.GetChild(canDisplay).gameObject.SetActive(true);
                    } else {
                        //对超过canDispaly的物体实施隐藏
                        transform.GetChild(canDisplay).gameObject.SetActive(false);
                    }
                    canDisplay += 1;
                }
            }
            else {
                for (int i = 12; i > 0; i--)
                {
                    BindGridItem(transform.GetChild(12 - i), m_ItemsList[12 * index - i]);
                    transform.GetChild(12 - i).gameObject.SetActive(true);
                }
            }
        }
    }

好了,在这里完成 BindPage 方法的定义以后,我们就可以指定程序显示对应页面的元素,此时上一页和下一页的工作基本上就是改变索引的一个过程了。这部分我们不再说了,大家可以去看最终给出的完整代码,我们这里来看看实际的效果吧!

简单的分页效果展示 简单的分页效果展示

其实这里核心的内容是分页的处理,在处理里只有 1 页时的元素个数和超过 1 页的最后 1 页时我们可以采取两个循环处理的方法,即先从 0 循环到 m_ItemsCount - 12 * (index-1))设置要显示的元素,然后再从 m_ItemsCount - 12 * (index-1))循环到 12 设置要隐藏的元素,可是这样的方式我不太喜欢,所以在文章中就没有采取这样的方式。这篇文章是根据一个项目当时的经历写的,因为时间过得比较久,所以如果文章中不当之处希望大家指出并批评。现在这个方案感觉还可以在特效上进行改进,因为现在感觉切换的时候画面比较突兀,这一点请大家注意。好了,下面给出完整的代码和场景布局截图。再次强调:请在看懂文章的基础上“抄”代码,每次看到别人问我把 XXX 脚本挂到场景中不起作用这类的问题,我就觉得整个世界充满了深深地罪恶感。别人愿意分享技术文章,更多的是希望可以和别人交流学习相互促进,如果你只是希望拿到一个随便抄来就能用地代码,抱歉!这违背了我的初衷所以我很难做到!

/*
 * 一个基于uGUI的分页功能的实现
 * 作者:秦元培
 * 时间:2015年11月11日
 * 博客:http://qinyuanpei.com
 */

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;

public class PaginationPanel : MonoBehaviour
{
    /// <summary>
    /// 当前页面索引
    /// </summary>
    private int m_PageIndex = 1;

    /// <summary>
    /// 总页数
    /// </summary>
    private int m_PageCount = 0;

    /// <summary>
    /// 元素总个数
    /// </summary>
    private int m_ItemsCount = 0;

    /// <summary>
    /// 元素列表
    /// </summary>
    private List<GridItem> m_ItemsList;

    /// <summary>
    /// 上一页
    /// </summary>
    private Button m_BtnPrevious;

    /// <summary>
    /// 下一页
    /// </summary>
    private Button m_BtnNext;

    /// <summary>
    /// 显示当前页数的标签
    /// </summary>
    private Text m_PanelText;

   

	void Start() 
    {
        InitGUI();
        InitItems();
	}

    /// <summary>
    /// 初始化GUI
    /// </summary>
    private void InitGUI()
    {
        m_BtnNext = GameObject.Find("Canvas/Panel/BtnNext").GetComponent<Button>();
        m_BtnPrevious = GameObject.Find("Canvas/Panel/BtnPrevious").GetComponent<Button>();
        m_PanelText = GameObject.Find("Canvas/Panel/Text").GetComponent<Text>();

        //为上一页和下一页添加事件
        m_BtnNext.onClick.AddListener(() => { Next(); });
        m_BtnPrevious.onClick.AddListener(() => { Previous(); });
    }

    /// <summary>
    /// 初始化元素
    /// </summary>
    private void InitItems()
    {
        //准备一个存储着12生肖信息的数组
        GridItem[] items = new GridItem[]
        {
            new GridItem("鼠","Mouse"),
            new GridItem("牛","Ox"),
            new GridItem("虎","Tiger"),
            new GridItem("兔","Rabbit"),
            new GridItem("龙","Dragon"),
            new GridItem("蛇","Snake"),
            new GridItem("马","Horse"),
            new GridItem("羊","Goat"),
            new GridItem("猴","Monkey"),
            new GridItem("鸡","Rooster"),
            new GridItem("狗","Dog"),
            new GridItem("猪","Pig")
        };

        //利用12生肖数组来随机生成列表
        m_ItemsList = new List<GridItem>();
        for (int i = 0; i < Random.Range(1,1000); i++)
        {
            m_ItemsList.Add(items[Random.Range(0,items.Length)]);
        }

        //计算元素总个数
        m_ItemsCount = m_ItemsList.Count;
        //计算总页数
        m_PageCount = (m_ItemsCount % 12) == 0 ? 
        m_ItemsCount / 12 : (m_ItemsCount / 12) + 1;

        BindPage(m_PageIndex);
        //更新界面页数
        m_PanelText.text = string.Format("{0}/{1}",
         m_PageIndex.ToString(),
         m_PageCount.ToString()
        );
    }

    /// <summary>
    /// 下一页
    /// </summary>
    public void Next()
    {
        if(m_PageCount <= 0)
            return;
        //最后一页禁止向后翻页
        if(m_PageIndex >= m_PageCount)
            return;

        m_PageIndex += 1;
        if (m_PageIndex >= m_PageCount)
            m_PageIndex = m_PageCount;

        BindPage(m_PageIndex);

        //更新界面页数
        m_PanelText.text = string.Format("{0}/{1}",
         m_PageIndex.ToString(), 
         m_PageCount.ToString());
    }

    /// <summary>
    /// 上一页
    /// </summary>
    public void Previous()
    {
        if (m_PageCount <= 0)
            return;
        //第一页时禁止向前翻页
        if (m_PageIndex <= 1)
            return;
        m_PageIndex -= 1;
        if (m_PageIndex < 1)
            m_PageIndex = 1;

        BindPage(m_PageIndex);

        //更新界面页数
        m_PanelText.text = string.Format("{0}/{1}",
         m_PageIndex.ToString(), 
         m_PageCount.ToString());
    }

    /// <summary>
    /// 绑定指定索引处的页面元素
    /// </summary>
    /// <param name="index">页面索引</param>
    private void BindPage(int index)
    {
        //列表处理
        if (m_ItemsList == null || m_ItemsCount <= 0)
            return;

        //索引处理
        if (index < 0 || index > m_ItemsCount)
            return;

        //按照元素个数可以分为1页和1页以上两种情况
        if (m_PageCount == 1)
        {
            int canDisplay = 0;
            for (int i = 12; i > 0; i--)
            {
                if(canDisplay < 12){
                    BindGridItem(transform.GetChild(canDisplay), m_ItemsList[12 - i]);
                    transform.GetChild(canDisplay).gameObject.SetActive(true);
                }else{
                    //对超过canDispaly的物体实施隐藏
                    transform.GetChild(canDisplay).gameObject.SetActive(false);
                }
                canDisplay += 1;
            }
        } else if (m_PageCount > 1){
            //1页以上需要特别处理的是最后1页
            //和1页时的情况类似判断最后一页剩下的元素数目
            //第1页时显然剩下的为12所以不用处理
            if (index == m_PageCount){
                int canDisplay = 0;
                for (int i = 12; i > 0; i--)
                {
                    //最后一页剩下的元素数目为 m_ItemsCount - 12 * (index-1)
                    if (canDisplay < m_ItemsCount - 12 * (index-1)){
                        BindGridItem(transform.GetChild(canDisplay),
                        m_ItemsList[12 * index-i]);
                        transform.GetChild(canDisplay).
                        gameObject.SetActive(true);
                    } else {
                        //对超过canDispaly的物体实施隐藏
                        transform.GetChild(canDisplay).
                        gameObject.SetActive(false);
                    }
                    canDisplay += 1;
                }
            }
            else {
                for (int i = 12; i > 0; i--)
                {
                    BindGridItem(transform.GetChild(12 - i), m_ItemsList[12 * index - i]);
                    transform.GetChild(12 - i).gameObject.SetActive(true);
                }
            }
        }
    }


    /// <summary>
    /// 加载一个Sprite
    /// </summary>
    /// <param name="assetName">资源名称</param>
    private Sprite LoadSprite(string assetName)
    {
        Texture texture = (Texture)Resources.Load(assetName);

        Sprite sprite = Sprite.Create((Texture2D)texture, 
        new Rect(0, 0, texture.width, texture.height), 
        new Vector2(0.5f, 0.5f));
        return sprite;
    }

    /// <summary>
    /// 将一个GridItem实例绑定到指定的Transform上
    /// </summary>
    /// <param name="trans"></param>
    /// <param name="gridItem"></param>
    private void BindGridItem(Transform trans,GridItem gridItem)
    {
        trans.GetComponent<Image>().sprite = LoadSprite(gridItem.ItemSprite);
        trans.Find("Item/Name").GetComponent<Text>().text = gridItem.ItemName;
        trans.GetComponent<Button>().onClick.AddListener(()=>
        {
            Debug.Log("当前点击的元素名称为:" + gridItem.ItemName);
        });
    }
}

好了,今天的内容就是这样啦,欢迎大家继续关注我的博客,谢谢大家!

2016 年 1 月 10 日更新: 经过博客中一位朋友指出,这篇文章中实现 BindPage 这个方法时可以在代码上再精简些,主要是考虑这个代码中有部分功能是重合的,因此这里对这个方法进行重写,分页从本质上来讲是编写这样一个函数:输入数据集合 data、每页显示的元素个数 pageSize 以及当前页数 page,然后返回一个新的数据集合。为了考虑扩展性我们这里编写一个分页的泛型方法,代码实现如下:

List<T> Pagination(List<T> data,int size,int page)
{
    //要返回的结果
    List<T> output = new List<T>();

    //计算最大页数
    int PageCount = (data.Count % size) == 0 ?
    (data.Count / size) : (data.Count / size) + 1;

    //判断输入页数的合法性
    if(page < 1 || page > PageCount)
        return null;

    //计算第page页第一个元素的索引
    int startIndex = (page - 1) * size;

    //除了尾页所有的页面中元素个数都是size个
    if(page < PageCount)
    {
        for (int i = 0; i < size; i++)
        {
            output.Add(data[startIndex + i]);
        }
    }
    else
    {
        for (int i = startIndex; i < data.Count; i++)
        {
            output.Add(data[i]);
        }
    }

    return output;
}

这里我们只需要考虑传入的页数是不是尾页即可,因为在所有的页面中除了尾页以外都有 size 个元素,所以我们只需要计算出第 page 页的第一个元素的索引,然后以此递增即可,而尾页显然是从 startIndex 到 data.Count-1 个。现在回过头来看,写个分页函数确实是简单至极,这篇博客显然是小题大做了。