中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

建立網(wǎng)站站點的基本過程什么關鍵詞可以搜到那種

建立網(wǎng)站站點的基本過程,什么關鍵詞可以搜到那種,wordpress字體更改,山東華邦建設集團網(wǎng)站大家好,我是阿趙。 一、滾動復用的介紹 在制作游戲的過程中,經(jīng)常會遇到一些需要顯示數(shù)量比較大的數(shù)據(jù)的情況。比如說,一個排行榜,需要展示當前服務器前一千個玩家的排名。或者游戲的背包容量特別大,可以有幾千個格子。…

??大家好,我是阿趙。

一、滾動復用的介紹

??在制作游戲的過程中,經(jīng)常會遇到一些需要顯示數(shù)量比較大的數(shù)據(jù)的情況。比如說,一個排行榜,需要展示當前服務器前一千個玩家的排名?;蛘哂螒虻谋嘲萘刻貏e大,可以有幾千個格子。
??在早期的游戲里面,這種情況一般會采取分頁的做法,比如一頁只顯示幾十條信息,通過翻頁和跳轉(zhuǎn)頁,逐頁瀏覽信息。但現(xiàn)在的游戲很少采取分頁的做法,而是采用滾動列表的方式,玩家可以上下滑動在同一頁里面看完所有的信息。
??以Unity引擎為例,通過Scroll View組件,就能輕松的實現(xiàn)上下滑動的效果。
在這里插入圖片描述

??ScrollView的基本用法很簡單,把需要展示的Item,都放在Content節(jié)點下,然后在Content上掛自動布局的組件和自動適配大小的組件,列表就可以滾動起來了。
在這里插入圖片描述

??回到最開始的例子,假如需要展示的內(nèi)容非常多,比如有1萬個,那我們是不是就要生成1萬個item放在Content下面呢?這樣做顯然是不行的。如果我們同時生成1萬個item,而且item很復雜,那么生成的時候會很卡,也會很占內(nèi)存。雖然實際顯示的數(shù)量可能只有幾個,但剩下的九千多個item還是需要通過Mask計算裁剪范圍。
??實際的情況是,我們需要同時看到的item,可能只有幾個,所以我們沒有必要生成這么大數(shù)量的item,而只是生成觀察范圍內(nèi)的有限幾個item就可以了,通過上下滑動,把移除出范圍的item移動到新進入范圍的位置,并且把數(shù)據(jù)刷新成剛進入范圍的數(shù)據(jù)顯示就可以了。我習慣上把這種做法叫做滾動復用。

Unity引擎UI滾動復用1

??從上面的視頻可以看到,我這里真的有1萬個數(shù)據(jù),而且可以任意的滑動,甚至任意的跳動到某個為止,從視覺上是完全看不出來有什么破綻。然后從Unity的Hierarchy窗口可以看出,實際上在Content節(jié)點下面的item數(shù)量就只有11個而已。
在這里插入圖片描述

??為了方便觀察,我把同時顯示的數(shù)量減少一些,并且把Mask去掉

Unity引擎UI滾動復用6

??從視頻的Scene視圖可以看到,消失的Item會立刻移動到進入的位置,并且刷新顯示。

二、 滾動復用的實現(xiàn)分析

1、計算可以滾動的范圍

??滾動復用還是可以使用Unity自帶的Scroll View組件。只是在Content節(jié)點上面,不需要再掛自動布局和自動大小的組件了。
??首先需要明白的一點是,Scroll View組件可以滾動的范圍,是通過Content節(jié)點的大小來決定的
在這里插入圖片描述

??在不使用滾動復用技術的時候,我們需要加自動布局和自動大小的組件,就是為了自動的計算出這個Content里面的內(nèi)容總共需要多大的范圍來顯示,從而決定滾動的實際范圍。
既然我們現(xiàn)在不需要自動大小了,所以我們可以通過計算,得出Content的大小。舉個例子:
??假如我現(xiàn)在是一個豎向滾動的列表,每個item的寬度是200,高度是60,需要同時顯示1000個item,item中間沒有空隙。那么要剛好放下這1000個item,Content需要的大小就是寬度200,高度是60x1000=60000。
??假如在item中間需要有5個像素的間隙,那么Content的大小,寬度還是200,高度會變成了60x1000+5x(1000-1) = 64995。
??是不是很簡單?只要這樣算一下,把Content的大小算出來,并設置。這時候列表已經(jīng)可以滾動起來了。雖然上面一個item也沒有,但實際上它滾動的范圍就是1000個item的高度。

2、 規(guī)定數(shù)據(jù)來源

??對于一個滾動顯示的列表來說,它必須是有一個輸入的數(shù)據(jù)源,并且是以一維數(shù)組的形式表現(xiàn)的。
??我這個例子里面,只是簡單的輸入了一個字符串的數(shù)組,而數(shù)組的內(nèi)容就是“內(nèi)容{序號}”。在實際的使用中,數(shù)據(jù)的來源會更復雜,比如是某個數(shù)據(jù)結(jié)構(gòu)體的數(shù)組,結(jié)構(gòu)體里面可以包含很多數(shù)據(jù),需要在item上面顯示很多內(nèi)容。
??不過數(shù)據(jù)是否復雜其實并不影響滾動復用的實現(xiàn),我這里只是為了說明原理。所以我準備了一個字符串數(shù)組,每一個數(shù)據(jù)對應數(shù)組里面的一個Index。在接下來的實現(xiàn)里面,每一個數(shù)據(jù)其實就是對應一個顯示的item了。item的UI預設是預先做好的,對應需要顯示的數(shù)據(jù)內(nèi)容。

3、 計算每個item的范圍

??在計算item范圍之前,先要定一個對齊方式。比如我們都以左上角作為對齊
在這里插入圖片描述

??然后item也是左上角對齊,并且Pivot的x是0,y是1。
在這里插入圖片描述

??這樣設置的好處是,當posX和posY都是0的時候,item剛好對齊了Content的左上角。然后隨著posX增大item會一直往右移動,隨著posY的一直減少(因為畫布的Y軸是向上的,所以負數(shù)才是向下),item會一直往下移動。
??假如現(xiàn)在所有item已經(jīng)按照正確的位置排列好了,那么每個item應該有一個相對于Content的坐標。這里需要記錄item的左上角和右下角的坐標:
在這里插入圖片描述

??如果用Vector4來表示這個item的最大最小值坐標,x和y就是左上角開始點的xy坐標。而z和w,就是右下角結(jié)束點的xy坐標。這種記錄方法還是看個人習慣的,有些人喜歡記錄開始點的xy坐標,還有記錄item的寬高,也都是可以的,畢竟結(jié)束點的坐標其實就是開始點坐標加上寬度和高度而已。
??不過我為了下面的步驟能快速的得到起點和終點的實際坐標來計算item是否在范圍內(nèi),所以記錄了結(jié)束點坐標而沒有記錄寬高。
??這里需要注意一點,雖然Unity的Y軸是朝向上的,也就是說數(shù)據(jù)越往下就越小。但我們計算的時候,其實不需要硬要這樣算的,我們就正常的算越往后的item坐標越大就行了,包括下面的計算范圍也是,把計算的Y軸朝下,計算起來的思維就方便很多。只要在最后給item的坐標賦值的時候,把Y坐標取個負數(shù)就行。

4、 計算每個item是否在可以顯示的范圍內(nèi)

??假設下圖的黑框就是現(xiàn)在Content的實際范圍,然后紅框就是現(xiàn)在ScrollView的遮罩顯示范圍:
在這里插入圖片描述

??由于Content的y坐標為0的時候,是剛好和遮罩的左上角重合的,所以可以認為,現(xiàn)在黑色的框往上移動的距離,也就是紅框的頂部坐標,其實就是Content的posY坐標。然后紅框的底部坐標,其實就是頂部坐標加上遮罩的高度。
??得到了當前需要顯示范圍(也就是紅框)的頂部和底部坐標之后,通過之前初始化的時候已經(jīng)計算好的每個item的開始坐標和結(jié)束坐標,就能很簡單的對比出item是否在紅框的顯示范圍呢了。

5、 刷新顯示

??當知道了哪些index對應的item是在顯示范圍內(nèi)的,接下來就很好辦了,我們需要記錄一個當前正在顯示的index列表,然后和新計算出來的正要顯示的index列表做對比,就可以知道,有哪些index對應的item是需要隱藏,哪些index對應的item是新顯示出來的。對于沒有變化的index,我們不需要處理,只需要先把需要隱藏的item隱藏掉,再把新增的item顯示出來,然后通過index,得到他們的坐標和數(shù)據(jù),把item擺在正確的位置,并且根據(jù)數(shù)據(jù)顯示item的內(nèi)容就行了。
??這里我的做法是維護一個對象池。當item不需要顯示的時候,把它們存放到對象池里面,并且隱藏。當item需要新增的時候,從對象池里面取出來,并且顯示。

6、 根據(jù)滾動事件觸發(fā)刷新顯示

??知道了怎樣刷新顯示,但在什么時候需要刷新呢?在拖動列表的過程中,按道理我們就需要不停的去檢查item是否在顯示范圍內(nèi)。
??為了達到拖動的過程中觸發(fā)刷新,所以需要在Scroll View的OnValueChange回調(diào)里面注冊一個方法,當值變化的時候,我們就重新計算并刷新顯示。不過由于OnValueChange觸發(fā)得很頻繁,所以我們需要降低一下調(diào)用的頻率:

  1. OnValueChange回調(diào)會傳入一個Vector2參數(shù),代表當前滑動的方向。因為我們做的例子是上下滑動,所以參數(shù)的y坐標為0時,就說明沒有滑動,所以不需要刷新。
  2. 給一個調(diào)用的頻率間隔,當回調(diào)的頻率過快時也不需要立刻刷新。

7、 跳轉(zhuǎn)到某個item

??在使用滾動列表的需求里面,很多時候會有需要定位的情況。比如在顯示1000個玩家信息的排行榜里面,需要定位到自己所在的排名。
??所以在做這個滾動復用的時候,也需要加上一個定位的功能。

Unity引擎UI滾動復用2

??這個功能實現(xiàn)的思路很簡單,因為每個item的坐標之前都已經(jīng)記錄了,所以需要跳轉(zhuǎn)到某個item,其實直接去它的坐標,然后加上item的一半高度就可以了。
??不過這里有一種情況,假如index對應的item在最上面或者最下面的一段,而列表是會自動回彈的(比如第一個item不能低于顯示范圍左上角,如果把第一個item居中,列表就會回彈到左上角),那么就要計算一下,當出現(xiàn)會回彈的情況,直接把y坐標變成0,或者在最下面的就要用Content高度減去mask的高度。

三、 源碼

??根據(jù)上面的思路,簡單寫了一個例子,是對應豎向滾動的。各位有興趣可以自己思考一下,怎樣改為橫向滾動,或者可以用參數(shù)切換橫豎向滾動。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class ScrollViewLoopCtrlBase : MonoBehaviour
{public ScrollRect scrollRect;public RectTransform content;protected float viewWidth;protected float viewHeight;private float itemWidth = 200;private float itemHeight = 60;protected float spaceTime = 0.02f;protected float lastTime = 0;protected List<string> dataList;protected float spacing = 0;protected List<int> currentShowIndexList;protected float contentHeight = 0;protected Dictionary<int, TestItem> showList;protected List<Vector4> itemPosList;protected Dictionary<int, List<TestItem>> poolDict;// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){}#region 公共方法/// <summary>/// 設置滾動復用的數(shù)據(jù)/// </summary>/// <param name="dataList">數(shù)據(jù)源</param>/// <param name="spacing">item之間的間隔</param>public void SetData(List<string> dataList, float spacing = 0){this.dataList = dataList;this.spacing = spacing;currentShowIndexList = new List<int>();RectTransform selfRect = GetComponent<RectTransform>();viewWidth = selfRect.rect.width;viewHeight = selfRect.rect.height;itemPosList = new List<Vector4>();InitData();UpdateView();}public void OnPosChange(Vector2 vec){if(vec.y == 0){return;}if (Time.time - lastTime < spaceTime){return;}lastTime = Time.time;UpdateView();}/// <summary>/// 停止?jié)L動/// </summary>public virtual void StopMove(){if (scrollRect){scrollRect.StopMovement();}}/// <summary>/// 設置列表停留在某個index的item居中/// </summary>/// <param name="ind"></param>public void SetIndexMiddle(int ind){StopMove();SetMiddleFun(ind);UpdateView();}#endregion/// <summary>/// 根據(jù)傳入的數(shù)據(jù)初始化滾動列表/// </summary>protected virtual void InitData(){int count = dataList.Count;for (int i = 0; i < count; i++){float startPos = i * itemHeight;if (i > 0){startPos += spacing * i;}itemPosList.Add(new Vector4(0, startPos, 0, startPos + itemHeight));}contentHeight = itemHeight * count;if (count > 1){contentHeight += spacing * (count - 1);}content.sizeDelta = new Vector2(viewWidth, contentHeight);}/// <summary>/// 設置index居中的具體實現(xiàn)/// </summary>/// <param name="ind"></param>protected virtual void SetMiddleFun(int ind){if (dataList == null || dataList.Count == 0){return;}if (ind < 0){ind = 0;}else if (ind >= dataList.Count){ind = dataList.Count - 1;}float halfScreenHeight = viewHeight / 2;float posY = itemPosList[ind].y - halfScreenHeight + (itemPosList[ind].w - itemPosList[ind].y) / 2;if (posY < 0){posY = 0;}else if (contentHeight - posY < viewHeight){posY = contentHeight - viewHeight;}content.anchoredPosition = new Vector2(0, posY);}/// <summary>/// 刷新列表顯示/// </summary>protected virtual void UpdateView(){List<int> newShowList = new List<int>();float contentStartY = content.anchoredPosition.y;float contentEndY = contentStartY + viewHeight;for (int i = 0; i < dataList.Count; i++){if (CheckItemIsInArea(contentStartY, contentEndY,i)){newShowList.Add(i);}}if (currentShowIndexList == null){AddItemsToShow(newShowList);currentShowIndexList = newShowList;return;}List<int> removeList = new List<int>();for (int i = 0; i < currentShowIndexList.Count; i++){if (newShowList.IndexOf(currentShowIndexList[i]) < 0){removeList.Add(currentShowIndexList[i]);}}if (removeList.Count > 0){RemoveItemsFromShowList(removeList);}List<int> newList = new List<int>();for (int i = 0; i < newShowList.Count; i++){if (currentShowIndexList.IndexOf(newShowList[i]) < 0){newList.Add(newShowList[i]);}}if (newList.Count > 0){AddItemsToShow(newList);}currentShowIndexList = newShowList;}/// <summary>/// 把對應index的item移除顯示/// </summary>/// <param name="indList"></param>protected void RemoveItemsFromShowList(List<int> indList){if (showList == null || showList.Count == 0){return;}for (int i = 0; i < indList.Count; i++){if (showList.ContainsKey(indList[i])){TestItem item = showList[indList[i]];showList.Remove(indList[i]);ReturnToPool(item);}}}/// <summary>/// 把對應index的item添加到顯示/// </summary>/// <param name="indList"></param>protected void AddItemsToShow(List<int> indList){if (showList == null){showList = new Dictionary<int, TestItem>();}for (int i = 0; i < indList.Count; i++){int id = indList[i];if (showList.ContainsKey(id) == false){TestItem item = GetFromPoolById(id);showList.Add(id, item);item.SetData(id, dataList[id]);item.rect.anchoredPosition = new Vector2(itemPosList[id].x, -itemPosList[id].y);}}}/// <summary>/// 檢查某個序號的item是否在顯示范圍內(nèi)/// </summary>/// <param name="contentStartY"></param>/// <param name="contentEndY"></param>/// <param name="itemIndex"></param>/// <returns></returns>protected bool CheckItemIsInArea(float contentStartY, float contentEndY, int itemIndex){Vector4 itemPos = itemPosList[itemIndex];if (itemPos.y <= contentStartY && itemPos.w >= contentStartY){return true;}if (itemPos.y >= contentStartY && itemPos.w <= contentEndY){return true;}if (itemPos.y <= contentEndY && itemPos.w >= contentEndY){return true;}return false;}#region 對象池/// <summary>/// 通過item類型從對象池獲取對象/// </summary>/// <param name="itemType"></param>/// <returns></returns>protected TestItem GetFromPool(int itemType){if (poolDict == null || poolDict.ContainsKey(itemType) == false || poolDict[itemType].Count == 0){string itemName = GetItemNameByItemType(itemType);Object obj = Resources.Load(itemName);GameObject go = (GameObject)GameObject.Instantiate(obj, content.transform);TestItem item = go.GetComponent<TestItem>();item.type = itemType;return item;}else{List<TestItem> poolList = poolDict[itemType];TestItem item = poolList[0];poolList.RemoveAt(0);item.gameObject.SetActive(true);return item;}}/// <summary>/// 這里是臨時測試資源,寫死了幾個item類型對應的item名字,用于加載/// </summary>/// <param name="itemType"></param>/// <returns></returns>private string GetItemNameByItemType(int itemType){string itemName = "";switch (itemType){case 1:itemName = "testItem";break;case 2:itemName = "testItem2";break;case 3:itemName = "testItem3";break;}return itemName;}/// <summary>/// 把Item回收到對象池/// </summary>/// <param name="item"></param>protected void ReturnToPool(TestItem item){item.gameObject.SetActive(false);if (poolDict == null){poolDict = new Dictionary<int, List<TestItem>>();}if (poolDict.ContainsKey(item.type) == false){poolDict.Add(item.type, new List<TestItem>());}List<TestItem> poolList = poolDict[item.type];if (poolList.IndexOf(item) < 0){poolList.Add(item);}}/// <summary>/// 正常的滾動復用可能會使用到不同的Item,這里定義一個通過id獲取item的方法,用于在不同需求下重寫/// </summary>/// <param name="id"></param>/// <returns></returns>protected virtual TestItem GetFromPoolById(int id){return GetFromPool(1);}#endregion}
http://www.risenshineclean.com/news/52934.html

相關文章:

  • 石橋鋪網(wǎng)站建設公司seo推廣怎么樣
  • 怎么做網(wǎng)上賭博的網(wǎng)站寧波網(wǎng)絡推廣平臺
  • 自己做免費手機網(wǎng)站成都網(wǎng)站快速優(yōu)化排名
  • 網(wǎng)站關聯(lián)詞搜索怎么做bt磁力搜索引擎在線
  • 做營銷型網(wǎng)站的教程打開百度搜索網(wǎng)站
  • 商務網(wǎng)站建設需要多少錢廈門seo關鍵詞優(yōu)化代運營
  • 公司網(wǎng)站怎么推廣在線域名解析ip地址
  • 網(wǎng)站建設排名公司哪家好網(wǎng)絡廣告公司排名
  • 織夢html5網(wǎng)站模板百度推廣廣告公司
  • 上海網(wǎng)站建設公司費用百度快速提交入口
  • 網(wǎng)站模板框架seo網(wǎng)站優(yōu)化培訓要多少錢
  • 住房建設廳官方網(wǎng)站成人短期技能培訓
  • 梁山專業(yè)網(wǎng)站建設網(wǎng)址檢測
  • 做網(wǎng)站開源框架簡述網(wǎng)絡推廣的方法
  • 網(wǎng)站域名更換是怎么做的網(wǎng)站是怎么做出來的
  • 可信網(wǎng)站值得做嗎seo推廣專員工作內(nèi)容
  • 河源今日新聞頭條火災優(yōu)化設計四年級上冊語文答案
  • 重慶涪陵網(wǎng)站建設南寧百度推廣seo
  • 網(wǎng)站推廣方案的構(gòu)成整站優(yōu)化服務
  • 模板網(wǎng)站音響案例數(shù)字營銷包括哪六種方式
  • 網(wǎng)站內(nèi)容管理系統(tǒng)建站企業(yè)網(wǎng)站
  • 內(nèi)蒙古網(wǎng)站建設價格輿情網(wǎng)站入口
  • 做視頻網(wǎng)站需要多大帶寬微網(wǎng)站建站平臺
  • 網(wǎng)站建設維護協(xié)議書北海百度seo
  • 品牌網(wǎng)站建設精湛磐石網(wǎng)絡百度登錄賬號首頁
  • 合作建站方案關鍵詞優(yōu)化和seo
  • 優(yōu)化是企業(yè)通過網(wǎng)站來做嗎怎么制作小程序
  • 幫忙做網(wǎng)站花西子網(wǎng)絡營銷案例分析
  • 怎么找做網(wǎng)站的人視頻號最新動作
  • 怎么做代理人金沙網(wǎng)站seo的內(nèi)容有哪些