Unity基礎(chǔ)(23)-UGUI

UGUI

控件是UGUI內(nèi)置的外傅,控件上面因因包含不同的組件而不同。

  • Image組件
    Image等價(jià)于NGUI的Sprite組件她君,用于顯示圖片腔丧。

    Panal控件就是包含Image組件的域仇, Image控件也是包含Image組件的刑然,Sprite 有圖集的概念,可以選擇整圖導(dǎo)入暇务,UNITY中使用SpriteEditor切割泼掠,也可以選擇導(dǎo)入后設(shè)置圖片的packageTag系統(tǒng)自動(dòng)打包圖集,圖片小的,重復(fù)性比較高的圖片最好打成圖集垦细,
    注意
    1择镇,一個(gè)圖集內(nèi)的圖片用UISprite,那么它就是一個(gè)DrawCall蝠检。但是如果你做了一個(gè)圖集是1024X1024的沐鼠。此時(shí)你的界面 上只用了圖集中的一張很小的圖,那么很抱歉1024X1024這張大圖都需要載入你的內(nèi)存里面叹谁,1024就是4M的內(nèi)存饲梭,如果你做了10個(gè)1024的圖集,你的界面上剛好都只用了每個(gè)圖集里面的一張小圖焰檩,那么再次抱歉你的內(nèi)存直接飆40M
    2.帶透明通道和不帶透明通道的憔涉,CreatMipMap和不Create 的,不能制作成同一圖集


    組件屬性
    Source Image(圖像源):紋理格式為Sprite(2D and UI)的圖片資源(導(dǎo)入圖片后選擇Texture Type為Sprite(2D and UI))析苫。
    Color(顏色):圖片疊加的顏色兜叨。
    Material(材質(zhì)):圖片疊加的材質(zhì),可以用來(lái)實(shí)現(xiàn)一些特殊效果衩侥,如凹凸感覺(jué)
    Raycast Target(射線投射目標(biāo)):是否作為射線投射目標(biāo)国旷,關(guān)閉之后忽略UGUI的射線檢測(cè)。
    Set Native Size:點(diǎn)擊此按鈕則 Image 組件的長(zhǎng)寬自動(dòng)與原圖片長(zhǎng)寬一致
    Image Type(圖片顯示類(lèi)型):
    Simple(基本的):圖片整張全顯示茫死,不裁切跪但,不疊加,根據(jù)邊框大小會(huì)有拉伸峦萎。
    Preserve Aspect(鎖定比例):針對(duì)Simple模式屡久,勾選之后忆首,無(wú)論圖片的外形放大還是縮小,都會(huì)一直保持初始的長(zhǎng)寬比例被环。


    Sliced(切片的):圖片切片顯示糙及,在Project頁(yè)面選中圖片,切換為Sprite(2D and UI)模式后筛欢,點(diǎn)擊Sprite Editor進(jìn)入圖片裁切模式浸锨,將圖片裁切為上圖的形狀,使用Sliced模式后悴能,根據(jù)圖片邊框拉伸揣钦,圖片的四個(gè)角會(huì)保持原狀,而1和4部分會(huì)隨著圖片的橫向拉伸而拉伸漠酿,2和3部分會(huì)隨著圖片的縱向拉伸而拉伸,圖片的中間部分會(huì)拉伸5進(jìn)行填充谎亩。
    Fill Center(填充中心):勾選后炒嘲,5顯示,反之匈庭,5不可見(jiàn)夫凸。


    Tiled(平鋪的):若圖片已經(jīng)過(guò)裁切,則使用Tiled模式后阱持,根據(jù)圖片邊框拉伸夭拌,圖片的四個(gè)角會(huì)保持原狀,而1和4部分會(huì)隨著圖片的橫向拉伸而拉伸衷咽,2和3部分會(huì)隨著圖片的縱向拉伸而拉伸鸽扁,圖片的中間部分會(huì)用5進(jìn)行平鋪填充。若圖片未裁切镶骗,則使用Tiled模式后桶现,根據(jù)圖片邊框拉伸,圖片保持原大小不做變化鼎姊,只是用自身平鋪填充骡和。
    Fill Center(填充中心):(已裁切的圖像源才有此選項(xiàng))勾選后,5顯示相寇,反之慰于,5不可見(jiàn)。


    Filled(填充的):根據(jù)填充方式唤衫、填充起點(diǎn)婆赠、填充比例決定圖片顯示哪一部分。
    Fill Method(填充方式):分為水平战授、垂直页藻、90度圓桨嫁、180度圓、360度圓份帐。
    Fill Origin(填充起點(diǎn)):根據(jù)填充方式不同有所變化璃吧。
    Fill Amount(填充比例):0是完全不顯示,1是完全顯示废境。

    我們將在學(xué)習(xí)button組件時(shí)進(jìn)行技能冷卻設(shè)置畜挨。
    3D場(chǎng)景使用
    1.單個(gè)Sprite 直接拖入場(chǎng)景中,系統(tǒng)自動(dòng)添加SpriteRanderder 組件噩凹,作為3D物體直接使用巴元,2. 多個(gè)Sprite直接拖入場(chǎng)景,可以直接制作幀動(dòng)畫(huà)驮宴,在2D中同樣也可以逮刨。

代碼使用:
using UnityEngine;
using UnityEngine.UI;
public class ImgTest : MonoBehaviour {
    public Image img;
    public Material ml;
    void Start () {
        img = GetComponent<Image>();
        // 通過(guò)資源加載進(jìn)行圖片的賦值
        img.sprite = Resources.Load<Sprite>("UI/background");
       
        img.color = Color.red;

        img.material = ml;

        img.raycastTarget = true;
        
        // 根據(jù)填充方式、填充起點(diǎn)堵泽、填充比例決定圖片顯示哪一部分
        img.type = Image.Type.Filled;
        // 圖片具備在水平方向的拉伸修己,縮小,
        // 根據(jù)下面的fillAmount數(shù)值進(jìn)行
        img.fillMethod = Image.FillMethod.Horizontal;
        // 設(shè)置圖片顯示為一半 
        img.fillAmount = 0.5f;    
    }
  • RayImage 組件

Textture 指定要顯示的圖片迎罗,注意:圖片類(lèi)型可以是任何類(lèi)型
Color 設(shè)置圖片的主色調(diào)
Material 設(shè)定Image控件的渲染材質(zhì)
Raycast Target 決定是否可接收射線碰撞事件檢測(cè)
UV Rect 可以讓圖片的一部分顯示在RawImage組件中

2D使用中(平面UI)
1.Texture用在Raw Image組件上睬愤,可以用來(lái)制作動(dòng)畫(huà)
2.Tuxture沒(méi)有圖集的概念,這樣內(nèi)存里只會(huì)占用你這一張圖的大小,內(nèi)存雖然小了但是DrawCall就上去了纹安。因?yàn)槊恳粡圲ITexture就是一次DrawCall尤辱。原畫(huà)或者背景圖建議直接使用UITexture。
3.可以通過(guò)UV 調(diào)節(jié)圖片顯示的偏移厢岂,和重復(fù)(可以用來(lái)制作多格子血條)
3D使用中(即直接拖動(dòng)此類(lèi)型的圖片到3D坐標(biāo)系統(tǒng))
1.無(wú)論單個(gè)光督、多個(gè),不可以直接拖入3D場(chǎng)景中咪笑!2D也不行
2.用于3D模型貼圖,(Shader代碼把貼圖和紋理坐標(biāo)映射),再由GPU把模型渲染出來(lái)MeshFiiter組件中模型網(wǎng)格可帽,存儲(chǔ)的紋理坐標(biāo)信息(Unity自己創(chuàng)建的Cube會(huì)自動(dòng)添加紋理坐標(biāo)所以創(chuàng)建后就能貼上紋理,3D建模時(shí)如果忽略 沒(méi)有給模型生成紋理坐標(biāo)窗怒,會(huì)導(dǎo)致模型貼上貼圖沒(méi)有效果)MesherRenderder 物體渲染組件

using UnityEngine;
using UnityEngine.UI;

public class ImgTest : MonoBehaviour {

    public RawImage img;
    public Material ml;
    void Start () {
        img = GetComponent<RawImage>();

        img.texture = Resources.Load<Texture2D>("UI/background");
       
        img.color = Color.red;

        img.material = ml;

        img.raycastTarget = true;

        img.uvRect = new Rect(new Vector2(0, 0), new Vector2(1,1));
        }
}

  • SpriteEditor (精靈)的切割和導(dǎo)出


1.無(wú)論是什么格式的圖片(最好直接使用PS直接導(dǎo)出的PSD格式)映跟,Unity都會(huì)自己搞一套格式,并且打包的時(shí)候也不會(huì)用你文件夾下圖片的格式扬虚,而是Unity自己的格式努隙。

2.都可以在導(dǎo)入時(shí)設(shè)置,圖片在發(fā)生拉伸變化時(shí)使用那種濾波模式辜昵,point 荸镊,Biliner,Trilinear,得到依次濾波效果提升的圖片,point 使用最鄰近濾波,采樣像素通常只有一個(gè)躬存,
圖像放大縮小后會(huì)有像素風(fēng)格张惹,在制作棋盤(pán)時(shí),不希望有模糊效果選擇這這種模式更好岭洲。Biliner使用線性濾波宛逗,找相鄰四個(gè)像素差值,放大縮小后會(huì)有模糊效果盾剩,
會(huì)被模糊雷激,Trilinear,幾乎和Biliner是一樣的,只是Triliner在多級(jí)紋理漸變中進(jìn)行了混合告私,如果一個(gè)紋理沒(méi)有使用該技術(shù)(Creat MitMap)幾乎是一樣效果屎暇。
Splite 可以直接選CreatMipMap,Texture需要把圖片設(shè)置為Advance后選擇是否使用多級(jí)紋理漸變技術(shù)(unity會(huì)根據(jù)相機(jī)距離對(duì)象距離,生成8個(gè)Mip驻粟,
該做法在3D場(chǎng)景UI是很好的做法根悼,如果UI都在平面就暴露出了它的弊端,因?yàn)槎荚谄矫娓裥幔圆粫?huì)有距離相機(jī)距離的變化番挺,勾選就行,不然會(huì)增加內(nèi)存屯掖,切記。)

3.Texture 在導(dǎo)入設(shè)置是Warp Mode 設(shè)置可以紋理在渲染超過(guò)紋理坐標(biāo)時(shí)襟衰,Climp只選擇重復(fù)紋理邊緣像素贴铜,還是repeat模式重復(fù)整個(gè)紋理的模式

4.MaxSize 該紋理的最大尺寸,如原圖尺寸為1024*568瀑晒,該項(xiàng)設(shè)置成4096绍坝,unity也只會(huì)使用它的原尺寸大小,改值的大小大于等于圖片原尺寸苔悦,如果小于該紋理質(zhì)量會(huì)有損失

5.Format 格式設(shè)置
Compressed 壓縮格式轩褐,如果紋理沒(méi)有透明通道,一般使用該項(xiàng)玖详,優(yōu)化內(nèi)存量把介,如果有透明通道,顯示原圖片有可能出現(xiàn)問(wèn)題蟋座。4位
    16bit 低質(zhì)量真彩格式拗踢。16位
    TrueColor 真彩模式。質(zhì)量最高向臀,是壓縮格式的8倍巢墅,但也更消耗內(nèi)存,32位
    Crunched 這種類(lèi)型將會(huì)根據(jù)顯卡的GPU來(lái)選擇合適的壓縮格式進(jìn)行壓縮然后會(huì)選用一種CPU上就能處理的壓縮格式再壓縮一遍。
           如果在制作供人下載的資源包的時(shí)候這種類(lèi)型非常的合適君纫。這個(gè)類(lèi)型的壓縮需要很長(zhǎng)時(shí)間驯遇,但在運(yùn)行時(shí)解壓是非常快的蓄髓。
    
 6.使用Advance 進(jìn)一步設(shè)置Sprite 或者Texture 
你的貼圖無(wú)論如何都必須是2的冪次方叉庐。因?yàn)橹挥?的冪次方圖片 并且沒(méi)有透明通道才會(huì)被壓縮,
IOS會(huì)壓縮成pvr格  式双吆,Android會(huì)壓縮成ETC格式眨唬,壓縮以后圖片會(huì)小很多的,好幾倍的小
如果原圖不是2的冪次方好乐,可以在advance設(shè)置Non Power of 2值匾竿,

ToNearest :轉(zhuǎn)換成距離該圖片最近的2的冪次方值。
    ToLarger : 轉(zhuǎn)換成比該圖片大的2的冪次方值蔚万。
    ToSmaller : 轉(zhuǎn)換成比該圖片小的2的冪次方值岭妖。

美工做了一張100100的邊框圖給你,這張圖有時(shí)以100100顯示反璃,有時(shí)以200100顯示昵慌,有時(shí)3000100顯示,放大會(huì)失真淮蜈,如何進(jìn)行斋攀?


看那個(gè)綠框,把邊界留出來(lái)



切割圖集:



  • Text

1梧田、Font:字體
2淳蔼、Font Style:
(1)Normal:正常
(2)Bold:粗體
(3)Italic:斜體
(4)Bold And Italic:粗體+斜體
3、Font Size:字體大小
4裁眯、Line Spacing:行間距(注:Text組件沒(méi)有提供修改字間距的屬性鹉梨,在前面寫(xiě)過(guò)修改字間距的腳本)
5、Rich Text:富文本
1穿稳、Alignment:
前面三個(gè)按鈕是水平方向(分別為左對(duì)齊存皂、居中、右對(duì)齊)逢艘,后面三個(gè)按鈕是垂直方向(分別為頂對(duì)齊旦袋,居中,底對(duì)齊)
2埋虹、Align By Geometry:
官方解釋?zhuān)?br> Use the extents of glyph geometry to perform horizontal alignment rather than glyph metrics.
This can result in better fitting left and right alignment, but may result in incorrect positioning when attempting to overlay multiple fonts (such as a specialized outline font) on top of each other.
使用區(qū)段的字形幾何執(zhí)行水平對(duì)齊,而不是字形指標(biāo)猜憎。
這可以導(dǎo)致更好的擬合左和右對(duì)齊,但可能會(huì)導(dǎo)致不正確的定位當(dāng)試圖覆蓋多個(gè)字體(如專(zhuān)業(yè)輪廓字體)上。
3搔课、Horizontal Overflow:水平溢出
(1)Wrap:文本將自動(dòng)換行胰柑,當(dāng)達(dá)到水平邊界
(2)Overflow:文本可以超出水平邊界截亦,繼續(xù)顯示
4、Vertical Overflow:垂直溢出
(1)Truncate:文本不顯示超出垂直邊界的部分
(2)Overflow:文本可以超出垂直邊界柬讨,繼續(xù)顯示
5崩瓤、Best Fit:勾選之后,編輯器發(fā)生變化踩官,顯示Min Size和Max Size
(1)Min Size:最小大小
(2)Max Size:最大大小
當(dāng)邊框很大時(shí)却桶,文字最大顯示Max Size字體大小蔗牡;當(dāng)邊框很小時(shí)颖系,文字最小顯示Min Size字體大小,邊框顯示不了MinSize字體大小就不再顯示文字了辩越。
Color:顏色
Material:材質(zhì)
Raycast Target:來(lái)自類(lèi)Graphic嘁扼,當(dāng)該項(xiàng)為false時(shí),消息會(huì)透?jìng)?/p>

富文本
你好黔攒,我是一<color = “red”>雷潮</color>asdjkl
修改顏色趁啸,發(fā)現(xiàn)雷潮并沒(méi)有改變顏色。這里面是HTML語(yǔ)法控制
  • InputField
using UnityEngine;
using UnityEngine.UI;

public class TestInputFiled : MonoBehaviour
{
    public InputField filed;
    void Start()
    {
        // InputField 有兩個(gè)空間督惰,一個(gè)是提示文本控件Placeholder不傅,一個(gè)是輸入文本控件Text     
        filed.placeholder.GetComponent<Text>().text = "請(qǐng)輸入賬號(hào)";
        // 修改輸入內(nèi)容框的內(nèi)容
        filed.text = "999";
        // 設(shè)置內(nèi)容類(lèi)型格式:密碼
        filed.contentType = InputField.ContentType.Password;
        // 設(shè)置輸入類(lèi)型格式:密碼
        filed.inputType = InputField.InputType.Password;
        // 超過(guò)邊界則換行
        filed.lineType = InputField.LineType.MultiLineSubmit;
        // 設(shè)置字?jǐn)?shù)限制,0表示不限制
        filed.characterLimit = 0;
        // 光標(biāo)閃爍速度
        filed.caretBlinkRate = 1.0f;
        // 在手機(jī)端隱藏輸入
        filed.shouldHideMobileInput = false; 
        #region 事件監(jiān)聽(tīng)
        // 添加輸入框的監(jiān)聽(tīng)事件
        filed.onValueChanged.AddListener(OnValueChange);
        filed.onEndEdit.AddListener(OnValueEdit);
        #endregion
    }
    // 當(dāng)值發(fā)生改變輸出
    void OnValueChange(string str)
    {
        Debug.Log(str);
    }
     // 當(dāng)輸入完成后回車(chē)后,輸出結(jié)果
    void OnValueEdit(string str)
    {
        Debug.Log("完成編輯后:"+ str);
    }


  • Button

Interactable:勾選赏胚,按鈕可用访娶,取消勾選,按鈕不可用觉阅。
Transition:按鈕在狀態(tài)改變時(shí)自身的過(guò)渡方式:
Color Tint(顏色改變) Sprite Swap(圖片切換) Animation(執(zhí)行動(dòng)畫(huà))
Normal Color(默認(rèn)顏色):初始狀態(tài)的顏色震肮。
Highlighted Color(高亮顏色):選中狀態(tài)或是鼠標(biāo)靠近會(huì)進(jìn)入高亮狀態(tài)。
Pressed Color(按下顏色):鼠標(biāo)點(diǎn)擊或是按鈕處于選中狀態(tài)時(shí)按下enter鍵留拾。
Disabled Color(禁用顏色):禁用時(shí)顏色。
Color Multiplier(顏色切換系數(shù)):顏色切換速度鲫尊,越大則顏色在幾種狀態(tài)間變化速度越快痴柔。
Fade Duration(衰落延時(shí)):顏色變化的延時(shí)時(shí)間,越大則變化越不明顯疫向。
當(dāng)選擇Sprite Swap咳蔚,出現(xiàn)的信息我們可這樣設(shè)置
Highlighted Sprite(高亮圖片):選中狀態(tài)或是鼠標(biāo)靠近會(huì)進(jìn)入高亮狀態(tài)。
Pressed Sprite(按下圖片):鼠標(biāo)點(diǎn)擊或是按鈕處于選中狀態(tài)時(shí)按下enter鍵搔驼。
Disabled Sprite(禁用圖片):禁用時(shí)圖片谈火。
最下面還有個(gè)Navigation是個(gè)導(dǎo)航鍵,實(shí)現(xiàn)兩個(gè)鍵之間的連接舌涨,可在上面條件腳本實(shí)現(xiàn)事件
選擇Animation糯耍,選中uto Generate Animatic會(huì)有提示我們保存文件我們保存好就行

關(guān)于按鈕的事件統(tǒng)一管理方法

 private Button[] btns;

    void Start()
    {
        btns = FindObjectsOfType<Button>();
        for (int i = 0; i < btns.Length; i++)
        {
            Button btn = btns[i];
            // 使用Lambda表達(dá)式添加偵聽(tīng)方法
            btn.onClick.AddListener(()=>BtnClick(btn));
        }
    }
/* 這里通過(guò)Button的名字進(jìn)行操作*/
 public void BtnClick(Button btn)
    {
        switch (btn.name)
        {
            case "Start":
                Debug.Log("Start");
                StartGame();
                break;
            case "Stop":
                Debug.Log("Stop");
                StopGame();
                break;
            case "Quit":
                Debug.Log("Quit");
                QuitGame();
                break;
        }
    }

    public void StartGame()
    {
        Debug.Log("Start");
       // 開(kāi)始游戲的一些邏輯 
    }

    public void StopGame()
    {
        Debug.Log("Stop");
        // 停止游戲的一些邏輯 
    }

    public void QuitGame()
    {
        Debug.Log("Quit");
        // 退出游戲的一些邏輯 
    }
案例操作說(shuō)明
  • Slider
    是一個(gè)主要用于形象的拖動(dòng)以改變目標(biāo)值的控件,他的最恰當(dāng)應(yīng)用是用來(lái)改變一個(gè)數(shù)值,最大值和最小值自定義温技,拖動(dòng)滑塊可在此之間改變革为,例如改變聲音大小。

Fill Rect(填充矩形):滑塊與最小值方向所構(gòu)成的填充區(qū)域所要使用的填充矩形舵鳞,如果滑動(dòng)條的作用只是用于改變指定值震檩,
那么此選項(xiàng)建議置空,這個(gè)相比于Scrollbar所多出來(lái)的屬性主要用于標(biāo)識(shí)從最小值變化到當(dāng)前值所經(jīng)過(guò)的變化區(qū)域蜓堕,
如果用做進(jìn)度條(顯示任務(wù)進(jìn)行進(jìn)度)的話抛虏,這個(gè)屬性是比Scrollbar多出來(lái)的一個(gè)優(yōu)勢(shì)。
Handle Rect(操作條矩形):當(dāng)前值處于最小值與最大值之間比例的顯示范圍套才,也就是整個(gè)滑條的最大可控制范圍迂猴。
Direction(方向):滑動(dòng)條的方向,從左至右霜旧,從上至下還是其他的错忱。
Min Value(最小值):滑動(dòng)條的可變化最小值。
Max Value(最大值):滑動(dòng)條的可變化最大值挂据。
Whole Numbers(變化值為整型):勾選此項(xiàng)以清,拖動(dòng)滑動(dòng)條將按整型數(shù)(最小為1)進(jìn)行改變指定值。
Value(值):當(dāng)前滑動(dòng)條對(duì)應(yīng)的值崎逃。
On Value Changed:值改變時(shí)觸發(fā)消息掷倔。
【注】:在On Value Change 事件被調(diào)用的時(shí)候
每當(dāng)滑塊的數(shù)值由于拖動(dòng)被改變時(shí)調(diào)用,float類(lèi)型的值會(huì)被傳遞無(wú)論WholeNumber屬性是否啟用个绍。

    public Slider sl;
    public GameObject cube;
    public float speed;
    private void Start()
    {
        sl = GetComponent<Slider>();
        // 一開(kāi)始賦值是確保物體按照設(shè)定值進(jìn)行勒葱,可以將值保存起來(lái)
        speed = sl.value;
    }

    private void Update()
    {
        cube.transform.Rotate(Vector3.up * Time.deltaTime * speed);
    }

    // 偵聽(tīng)我的Value值的改變
    public void MyValueChange(float value)
    {
        speed = value;
    }
}
  • Toggle
public class MyToggle : MonoBehaviour {

    public Toggle tg;
    public GameObject panel;
    void Start () {
        tg = GetComponent<Toggle>();
        // Toggle事件監(jiān)聽(tīng)
        //tg.onValueChanged.AddListener(MyIsOn);
        // 一開(kāi)始一定要判斷。不然會(huì)導(dǎo)致勾選了但是一開(kāi)始沒(méi)有效果巴柿。
        if (tg.isOn == true)
        {
            MyIsOn1(true);
            MyIsOn2(true);
        }
    }
    public void MyIsOn1(bool b)
    {
        Debug.Log(b + "1---");
        // 修改Panel
        panel.GetComponent<Image>().color = Color.red;
    }
    public void MyIsOn2(bool b)
    {
        Debug.Log(b + "2---");
        // 修改Panel
        panel.GetComponent<Image>().color = Color.green;
    }
}
  • Dropdown
    Lable和Arrow是用來(lái)顯示初始化的文字和勾選項(xiàng)的凛虽,Lable會(huì)根據(jù)首選項(xiàng)的內(nèi)容自動(dòng)更改

Caption Text和Caption Image是作為下拉列表首選項(xiàng)的文字和圖片顯示,也是我們每次選擇后的內(nèi)容广恢,因此可代碼調(diào)用獲取
Item Text作為下拉列表中每個(gè)item的文字顯示凯旋,
Item Image可以用來(lái)擴(kuò)展模板增加內(nèi)容Value值會(huì)隨著下拉列表選項(xiàng)的不同而變化,參考代碼部分
Options選項(xiàng)欄內(nèi):通過(guò)代碼可賦值給相應(yīng)的Item對(duì)象 Dropdown.OptionData

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


public class DropScripts : MonoBehaviour {

    public Dropdown dw;
    private List<string> ListStr;
    private List<Sprite> sprite_list;

    public string[] showText;
    public Sprite[] sprite;
   
    void Start () {
        dw = GetComponent<Dropdown>();
        ListStr = new List<string>();
        sprite_list = new List<Sprite>();
        //ListStr.Add("1");
        //ListStr.Add("2");
        //ListStr.Add("3");
        // 清除選項(xiàng)內(nèi)容
        // dw.ClearOptions();
        // dw.options.Clear();
        // 添加選項(xiàng)內(nèi)容
        // dw.AddOptions(ListStr);
        
        // 添加List列表
        AddNames();
        // 賦值
        DropValue();
        // 檢測(cè)值改變
        DropValueChange(dw.value);  // 因?yàn)橐婚_(kāi)始默認(rèn)調(diào)用了第一個(gè)值
        dw.onValueChanged.AddListener(DropValueChange);
    }

    public void DropValueChange(int index)
    {
        Debug.Log(index);
        if (index == 0)
        {
            Debug.Log("模式1調(diào)用了");
        }
        if (index == 1)
        {
            Debug.Log("模式2調(diào)用了");
        }
        if (index == 2)
        {
            Debug.Log("模式3調(diào)用了");
        }
    }

    // 給內(nèi)部option賦值
    public void DropValue()
    {
        // 清除選項(xiàng)內(nèi)容
        dw.options.Clear();
        // 申明一個(gè)DropData
        Dropdown.OptionData temoData;
        for (int i = 0; i < showText.Length; i++)
        {
            //給每一個(gè)option選項(xiàng)賦值         
            temoData = new Dropdown.OptionData();
            temoData.text = showText[i];
            temoData.image = sprite_list[i];
            dw.options.Add(temoData);
        }
        // 默認(rèn)選擇第一個(gè)
        dw.captionText.text = showText[0];
    }

    // 將數(shù)組內(nèi)的元素添加到List列表中
    void AddNames()
    {
        for (int i = 0; i < showText.Length; i++)
        {
            ListStr.Add(showText[i]);
        }
        for (int i = 0; i < sprite.Length; i++)
        {
            sprite_list.Add(sprite[i]);
        }
    }
}
  • Scrollbar

Handle Rect(操作條矩形):當(dāng)前值處于最小值與最大值之間比例的顯示范圍钉迷,也就是整個(gè)滑條的最大可控制范圍至非。
Direction(方向):滾動(dòng)條的方向,從左至右糠聪,從上至下還是其他的荒椭。
Value(值):當(dāng)前滾動(dòng)條對(duì)應(yīng)的值。
Size(操作條矩形長(zhǎng)度):操作條矩形對(duì)應(yīng)的縮放長(zhǎng)度舰蟆。
//(指定可滾動(dòng)的位置數(shù)量)
Numbers Of Steps:滾動(dòng)條可滾動(dòng)的位置數(shù)目趣惠,為0和1時(shí)不生效(事實(shí)上只有0個(gè)可滾動(dòng)位置或1個(gè)可滾動(dòng)位置那還叫滾動(dòng)條嗎)狸棍,
例如設(shè)為2,則拖動(dòng)滾動(dòng)條時(shí)滾動(dòng)條只會(huì)處在最小值的位置和最大值的位置信卡,因?yàn)樗目蓾L動(dòng)位置只有2個(gè)隔缀,
例如設(shè)為3,則拖動(dòng)滾動(dòng)條時(shí)滾動(dòng)條只會(huì)處在最小值的位置傍菇、最大值的位置以及中間位置猾瘸,因?yàn)樗目蓾L動(dòng)位置只有3個(gè)。
On Value Changed:值改變時(shí)觸發(fā)消息丢习。

  • ScrollRect

屬性:



Content —— 滑動(dòng)的內(nèi)容 ( 所有需要滑動(dòng)展示的內(nèi)容 )
Horizontal —— 是否支持左右滑動(dòng)
Vertical —— 是否支持上下滑動(dòng)
MovementType —— 滑動(dòng)類(lèi)型 ( Unrestricted 不受滑動(dòng)內(nèi)容邊界限制 Elastic 帶邊界回彈的(Elasticity 彈力) clamped 邊界夾緊 )
Inertia —— 是否支持滑動(dòng)慣性( Deceleration Rate 減速率 牵触,我感覺(jué)就是慣性的大小)
scroll sensitivity —— 滾動(dòng)的靈敏度
Viewport —— 視口 ( 一般是Content 的父物體,帶Mask遮罩后的展示區(qū)域)
Horizontar Scrollbar —— 左右的滾動(dòng)條( 連接的滾動(dòng)條必須放在Scroll View下 )
Visibility —— 滾動(dòng)條可見(jiàn)性 ( Permanent 不變的( 只有選擇這個(gè)關(guān)聯(lián)的Scrollbar才能隱藏 ) auto hide自動(dòng)隱藏(如果內(nèi)容不需要滾動(dòng)就可以看到隱藏滾動(dòng)條) Auto Hide and Expand Viewport 自動(dòng)隱藏并擴(kuò)展視圖 ( Spacing 滑動(dòng)區(qū)域和滾動(dòng)條的間距) )

  • 引入事件函數(shù)
using UnityEngine.UI;
using UnityEngine;
using UnityEngine.EventSystems;

public class TestOne : MonoBehaviour , IBeginDragHandler,IEndDragHandler, IDragHandler,IDropHandler
{
    public ScrollRect sr;
    public Text t;
    public Scrollbar sb;
    void Start () {
        sr = GetComponent<ScrollRect>();
        t = GetComponentInChildren<Text>();
        sr.content = t.rectTransform;
        sr.horizontal = false;
        sr.vertical = true;
        sr.verticalScrollbar = sb;
        sr.onValueChanged.AddListener(OnValueChange);     
    }

    public void OnValueChange(Vector2 value)
    {
        Debug.Log(value);
        if (value.y > 0.4)
        {
            Debug.Log("第一頁(yè)");
        }
    }

    // 剛開(kāi)始拖拽的時(shí)候
    public void OnBeginDrag(PointerEventData eventData)
    {
        Debug.Log("開(kāi)始拖拽");
        // 假設(shè):一個(gè)頁(yè)面有太多的數(shù)據(jù)咐低,這個(gè)時(shí)候最好通過(guò)提前預(yù)加載進(jìn)行展示數(shù)據(jù)
        // 加載第二頁(yè)的數(shù)據(jù)
        // 加載其他內(nèi)容
    }

    public void OnDrag(PointerEventData eventData)
    {
        // 當(dāng)拖拽的時(shí)候
        Debug.Log("正在拖拽");
    }

    public void OnDrop(PointerEventData eventData)
    {
        // 當(dāng)我們不拖拽的時(shí)候揽思,調(diào)用在OnEndDrag之前
    }

    // 當(dāng)結(jié)束拖拽的時(shí)候
    public void OnEndDrag(PointerEventData eventData)
    {
        Debug.Log("結(jié)束拖拽" + eventData.pressPosition);
        // 制作結(jié)束拖拽后的邏輯,可以體視用戶沒(méi)有內(nèi)容了
    } 

小練習(xí):寫(xiě)個(gè)小框架滑動(dòng)菜單

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class TestThree : MonoBehaviour,IBeginDragHandler, IEndDragHandler
{
    private float[] pageArray = new float[] {0,0.5f,1 };
    private float targetPosition = 0;
    private bool isDrag = false;

    public ScrollRect sr;
    public Toggle[] tgArray;
    public float smooth = 5f;
    void Start () {
        if (isDrag == false)
        {
            sr.horizontalNormalizedPosition = Mathf.Lerp(sr.horizontalNormalizedPosition, targetPosition, Time.deltaTime * smooth);
        }
    }
    
    // Update is called once per frame
    void Update () {
        
    }
    public void MovePange1(bool isOn)
    {
        if (isOn == true)
        {
            targetPosition = pageArray[0];
        }
    }
    public void MovePange2(bool isOn)
    {
        if (isOn == true)
        {
            targetPosition = pageArray[2];
        }
    }
    public void MovePange3(bool isOn)
    {
        if (isOn == true)
        {
            targetPosition = pageArray[3];
        }
    }


    public void OnBeginDrag(PointerEventData eventData)
    {
        isDrag = true;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        isDrag = false;
        float posX = sr.horizontalNormalizedPosition;
        int index = 0;
        float offset = Mathf.Abs(pageArray[index] - posX);
        for (int i = 0; i < pageArray.Length; i++)
        {
            float offsetTmp = Mathf.Abs(pageArray[i]-posX);
            if (offsetTmp < offset)
            {
                index = i;
                offset = offsetTmp;
            }
        }
        targetPosition = pageArray[index];
        tgArray[index].isOn = true;
        print(sr.horizontalNormalizedPosition);
    }
}

  • Scroll View
    就是由ScrollRect和ScrollBar等控件組成的见擦,滿足開(kāi)發(fā)者需求的集合體控件
ScollView 控件下由三個(gè)組成部分钉汗,
Viewport 視圖,
Scrollbar Horizontal ,水平滾動(dòng)條, 
Scrollbar Vertical 鲤屡,垂直滾動(dòng)條损痰。

ScrollView的Content不能根據(jù)實(shí)際Content下的游戲物體的多少自動(dòng)改變Content的寬高問(wèn)題

在實(shí)際使用UGUI開(kāi)發(fā)的過(guò)程中發(fā)現(xiàn)一個(gè)UGUI的BUG:當(dāng)Content下的子物體增加時(shí),ScrollBar下的Handle滑條大小沒(méi)有實(shí)時(shí)根據(jù)發(fā)生Content下的子物體數(shù)量發(fā)生變化。(在Hierarchy面板中右鍵創(chuàng)建UI->ScrollView,在子物體中找到Content,需要按行列布置的游戲物體都作為Content的子物體掛在Content下)(以開(kāi)發(fā)垂直的ScrollView為例)在查找問(wèn)題的過(guò)程中發(fā)現(xiàn):我的這個(gè)項(xiàng)目里Content的高小于遮罩層Viewport的的高陶因,致使ScrollBar滑條的size一直為1的狀態(tài)。調(diào)整Content的高使高大于遮罩層Viewport的的高后又發(fā)現(xiàn)如下問(wèn)題:在編輯模式下ScrollBar滑條的size只根據(jù)Content與遮罩層Viewport的大小比例進(jìn)行了調(diào)整辽社,而不是根據(jù)Content的子物體數(shù)量進(jìn)行變換,致使了在Content下添加的子物體的總高大于Content設(shè)置的高時(shí)下拉滑條并不能全部顯示的問(wèn)題翘鸭,并且在游戲運(yùn)行時(shí)ScrollBar的Size又重新變回1了滴铅,無(wú)論怎么調(diào)整參數(shù)都無(wú)濟(jì)于事。于是自己寫(xiě)了一個(gè)腳本就乓,根據(jù)Content下的子物體的個(gè)數(shù)來(lái)控制Content的寬高(原理是修改RectTransform的sizedelta)

/* 
 * 說(shuō)明:掛在UGUI中ScrollView中的Content游戲物體下(在Hierarchy面板中右鍵創(chuàng)建UI->ScrollView,在子物體中找到Content) * 
 * 功能:解決ScrollView中Content不能根據(jù)實(shí)際Content下的游戲物體的多少自動(dòng)改變Content的寬高問(wèn)題
 *     以至于在Content動(dòng)態(tài)添加需要排序的游戲物體時(shí)ScrollBar滑條變更不正確的問(wèn)題 
 *   (Content Size Fitter組件是用于文本組件時(shí)自動(dòng)根據(jù)文本變更大小的組件,這里不適用) 
*/ 
using System.Collections;
using System.Collections.Generic;
using UnityEngine; 
public class ScrollViewContentTool : MonoBehaviour {  
   /// <summary>    
   /// 根據(jù)ScrollBar的類(lèi)型自動(dòng)調(diào)整Content的寬或高   
  /// </summary>    
public enum ScrollBarType   {    
    Vertical,      //為垂直狀態(tài)時(shí)需設(shè)置RectTransform的Anchors為Min(0,1),Max(1,1)        
    Horizontal,    //為水平向右延伸狀態(tài)時(shí)需設(shè)置RectTransform的Anchors為Min(0,0),Max(0,1)        HorizontalAndVertical    
}     
public ScrollBarType m_barType;     
/// <summary>    
/// 該Content表示實(shí)際寬高(這里寬高大小應(yīng)該為Viewport遮罩層的大小)    
/// </summary>    
public float m_ContentWidth = 0;    
public float m_ContentHeight = 0;     
/// <summary>   
 /// Content下排列的游戲物體X軸和Y軸的間距    
/// </summary>    
public Vector2 m_Spacing = Vector2.zero;    
private RectTransform m_rectTransform = null;    
private int m_tempChildCount = 0;    
private Vector2 m_ChildSize = Vector2.zero;  
//存儲(chǔ)Content子物體的寬高   
// Use this for initialization  
private void Awake () {       
   m_rectTransform = this.GetComponent<RectTransform>();        
   m_tempChildCount = this.transform.childCount;        
       if (m_tempChildCount > 0) 
          m_ChildSize = this.transform.GetChild(0).GetComponent<RectTransform>().sizeDelta;        
       if (m_barType == ScrollBarType.Horizontal)       
       {            
          if (m_ContentWidth == 0) Debug.LogError("請(qǐng)?jiān)O(shè)置Content的Width!!");            
          m_rectTransform.anchorMin = new Vector2(0, 0);            
          m_rectTransform.anchorMax = new Vector2(0, 1);            
          m_rectTransform.sizeDelta = new Vector2(m_ContentWidth, 0);       
       }  else if (m_barType == ScrollBarType.Vertical)        {            
              if (m_ContentHeight == 0) Debug.LogError("請(qǐng)?jiān)O(shè)置Content的Height!!");           
             m_rectTransform.anchorMin = new Vector2(0, 1);            
            m_rectTransform.anchorMax = new Vector2(1, 1);            
            m_rectTransform.sizeDelta = new Vector2(0, m_ContentHeight);       
       }  else if (m_barType == ScrollBarType.HorizontalAndVertical)       
       {            
          if (m_ContentHeight == 0 || m_ContentWidth == 0) Debug.LogError("請(qǐng)?jiān)O(shè)置Content的Width和Height!!");                  
          m_rectTransform.anchorMin = new Vector2(0, 0);           
          m_rectTransform.anchorMax = new Vector2(1, 1);            
          m_rectTransform.sizeDelta = new Vector2(0, 0);       
       }         
     //Debug.Log(this.transform.GetChild(0).GetComponent<RectTransform>().sizeDelta);   
}       

private void Update () { 
       if (m_tempChildCount != this.transform.childCount)        
       {            
               m_tempChildCount = this.transform.childCount;            
               UpdateContentSize(m_tempChildCount);        
      }   
 }     
/// <summary>    
/// 根據(jù)Content下子物體數(shù)量的變化更新Content的寬高    
/// </summary>    
private void UpdateContentSize(int _count)    {        
      if (m_barType == ScrollBarType.Horizontal)        
      {            
            if (_count * m_ChildSize.x > m_ContentWidth)           
            {                
                m_rectTransform.sizeDelta = new Vector2(_count * (m_ChildSize.x + m_Spacing.x), 0);            
            }       
       }  
      else if (m_barType == ScrollBarType.Vertical)       
     {            
            if (_count * m_ChildSize.y > m_ContentHeight)           
           {                
              m_rectTransform.sizeDelta = new Vector2(0, _count * (m_ChildSize.y + m_Spacing.y));
            }       
     }        
        //此時(shí)的m_rectTransform.sizeDelta代表往右和往下的增量失息,為0時(shí)代表Content的初始大小       
      else if (m_barType == ScrollBarType.HorizontalAndVertical)       
     {    
              if (_count * m_ChildSize.x > m_ContentWidth)         
              {               
                 float width = Mathf.Abs(m_ContentWidth - _count * (m_ChildSize.x + m_Spacing.x));         
                 m_rectTransform.sizeDelta = new Vector2(width, 0); 
              }             
              if (_count * m_ChildSize.y > m_ContentHeight)          
              {               
                  float height = Mathf.Abs(m_ContentHeight - _count * (m_ChildSize.y + m_Spacing.y));                        
                  m_rectTransform.sizeDelta = new Vector2(0, -height);        
              }   
     }  
  }
}
  • ScrollView無(wú)限滾動(dòng)
    scrollview理論上是支持無(wú)限多個(gè)item單元(即滾動(dòng)的單元條目),但實(shí)際應(yīng)用中档址,我們?cè)谝婚_(kāi)始實(shí)例化幾個(gè)或者十幾個(gè)item對(duì)象時(shí)一般是沒(méi)問(wèn)題,但是當(dāng)item非常多時(shí)邻梆,幾百或者上千時(shí)守伸,完全實(shí)例化比較耗時(shí)消耗性能大,也有可能帶來(lái)占用手機(jī)內(nèi)存比較高浦妄,甚至?xí)寖?nèi)存溢出尼摹。
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
 
[RequireComponent(typeof(GridLayoutGroup))]
[RequireComponent(typeof(ContentSizeFitter))]
public class InfinityGridLayoutGroup : MonoBehaviour 
{
 
    [SerializeField]
    int minAmount = 0;//實(shí)現(xiàn)無(wú)限滾動(dòng)见芹,需要的最少的child數(shù)量。屏幕上能看到的+一行看不到的蠢涝,比如我在屏幕上能看到 2 行玄呛,每一行 2 個(gè)。則這個(gè)值為 2行*2個(gè) + 1 行* 2個(gè) = 6個(gè)和二。
 
    RectTransform rectTransform;
 
    GridLayoutGroup gridLayoutGroup;
    ContentSizeFitter contentSizeFitter;
 
    ScrollRect scrollRect;
 
    List<RectTransform> children=new List<RectTransform>();
 
    Vector2 startPosition;
 
    int amount = 0;
 
    public delegate void UpdateChildrenCallbackDelegate(int index, Transform trans);
    public UpdateChildrenCallbackDelegate updateChildrenCallback = null;
 
    int realIndex = -1;
    int realIndexUp = -1; //從下往上;
 
    bool hasInit = false;
    Vector2 gridLayoutSize;
    Vector2 gridLayoutPos;
    Dictionary<Transform, Vector2> childsAnchoredPosition = new Dictionary<Transform, Vector2>();
    Dictionary<Transform, int> childsSiblingIndex = new Dictionary<Transform, int>();
 
 
    // Use this for initialization
    void Start ()
    {
        //StartCoroutine(InitChildren());
    }
 
    IEnumerator InitChildren()
    {
        yield return 0;
 
        if (!hasInit)
        {
            //獲取Grid的寬度;
            rectTransform = GetComponent<RectTransform>();
 
            gridLayoutGroup = GetComponent<GridLayoutGroup>();
            gridLayoutGroup.enabled = false;
            contentSizeFitter = GetComponent<ContentSizeFitter>();
            contentSizeFitter.enabled = false;
 
            gridLayoutPos = rectTransform.anchoredPosition;
            gridLayoutSize = rectTransform.sizeDelta;
 
            
            //注冊(cè)ScrollRect滾動(dòng)回調(diào);
            scrollRect = transform.parent.GetComponent<ScrollRect>();
            scrollRect.onValueChanged.AddListener((data) => { ScrollCallback(data); });
 
            //獲取所有child anchoredPosition 以及 SiblingIndex;
            for (int index = 0; index < transform.childCount; index++)
            {
                Transform child=transform.GetChild(index);
                RectTransform childRectTrans= child.GetComponent<RectTransform>();
                childsAnchoredPosition.Add(child, childRectTrans.anchoredPosition);
 
                childsSiblingIndex.Add(child, child.GetSiblingIndex());
            }
        }
        else
        {
            rectTransform.anchoredPosition = gridLayoutPos;
            rectTransform.sizeDelta = gridLayoutSize;
 
            children.Clear();
 
            realIndex = -1;
            realIndexUp = -1;
 
            //children重新設(shè)置上下順序;
            foreach (var info in childsSiblingIndex)
            {
                info.Key.SetSiblingIndex(info.Value);
            }
 
            //children重新設(shè)置anchoredPosition;
            for (int index = 0; index < transform.childCount; index++)
            {
                Transform child = transform.GetChild(index);
                
                RectTransform childRectTrans = child.GetComponent<RectTransform>();
                if (childsAnchoredPosition.ContainsKey(child))
                {
                    childRectTrans.anchoredPosition = childsAnchoredPosition[child];
                }
                else
                {
                    Debug.LogError("childsAnchoredPosition no contain "+child.name);
                }
            }
        }
 
        //獲取所有child;
        for (int index = 0; index < transform.childCount; index++)
        {
            Transform trans = transform.GetChild(index);
            trans.gameObject.SetActive(true);
 
            children.Add(transform.GetChild(index).GetComponent<RectTransform>());
 
            //初始化前面幾個(gè);
            UpdateChildrenCallback(children.Count - 1, transform.GetChild(index));
        }
 
        startPosition = rectTransform.anchoredPosition;
 
        realIndex = children.Count - 1;
 
        //Debug.Log( scrollRect.transform.TransformPoint(Vector3.zero));
 
       // Debug.Log(transform.TransformPoint(children[0].localPosition));
 
        hasInit = true;
 
        //如果需要顯示的個(gè)數(shù)小于設(shè)定的個(gè)數(shù);
        for (int index = 0; index < minAmount; index++)
        {
            children[index].gameObject.SetActive(index < amount);
        }
 
        if (gridLayoutGroup.constraint == GridLayoutGroup.Constraint.FixedColumnCount)
        {
            //如果小了一行徘铝,則需要把GridLayout的高度減去一行的高度;
            int row = (minAmount - amount) / gridLayoutGroup.constraintCount;
            if (row > 0)
            {
                rectTransform.sizeDelta -= new Vector2(0, (gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y) * row);
            }
        }
        else
        {
            //如果小了一列,則需要把GridLayout的寬度減去一列的寬度;
            int column = (minAmount - amount) / gridLayoutGroup.constraintCount;
            if (column > 0)
            {
                rectTransform.sizeDelta -= new Vector2((gridLayoutGroup.cellSize.x + gridLayoutGroup.spacing.x) * column, 0);
            }
        }
    }
    
    // Update is called once per frame
    void Update () 
    {
    
    }
 
 
    void ScrollCallback(Vector2 data)
    {
        UpdateChildren();
    }
 
    void UpdateChildren()
    {
        if (transform.childCount < minAmount)
        {
            return;
        }
 
        Vector2 currentPos = rectTransform.anchoredPosition;
 
        if (gridLayoutGroup.constraint == GridLayoutGroup.Constraint.FixedColumnCount)
        {
            float offsetY = currentPos.y - startPosition.y;
 
            if (offsetY > 0)
            {
                //向上拉惯吕,向下擴(kuò)展;
                {
                    if (realIndex >= amount - 1)
                    {
                        startPosition = currentPos;
                        return;
                    }
 
                    float scrollRectUp = scrollRect.transform.TransformPoint(Vector3.zero).y;
 
                    Vector3 childBottomLeft = new Vector3(children[0].anchoredPosition.x, children[0].anchoredPosition.y - gridLayoutGroup.cellSize.y, 0f);
                    float childBottom = transform.TransformPoint(childBottomLeft).y;
 
                    if (childBottom >= scrollRectUp)
                    {
                        //Debug.Log("childBottom >= scrollRectUp");
 
                        //移動(dòng)到底部;
                        for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                        {
                            children[index].SetAsLastSibling();
 
                            children[index].anchoredPosition = new Vector2(children[index].anchoredPosition.x, children[children.Count - 1].anchoredPosition.y - gridLayoutGroup.cellSize.y - gridLayoutGroup.spacing.y);
 
                            realIndex++;
 
                            if (realIndex > amount - 1)
                            {
                                children[index].gameObject.SetActive(false);
                            }
                            else
                            {
                                UpdateChildrenCallback(realIndex, children[index]);
                            }
                        }
 
                        //GridLayoutGroup 底部加長(zhǎng);
                        rectTransform.sizeDelta += new Vector2(0, gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y);
 
                        //更新child;
                        for (int index = 0; index < children.Count; index++)
                        {
                            children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                        }
                    }
                }
            }
            else
            {
                //Debug.Log("Drag Down");
                //向下拉惕它,下面收縮;
                if (realIndex + 1 <= children.Count)
                {
                    startPosition = currentPos;
                    return;
                }
                RectTransform scrollRectTransform = scrollRect.GetComponent<RectTransform>();
                Vector3 scrollRectAnchorBottom = new Vector3(0, -scrollRectTransform.rect.height - gridLayoutGroup.spacing.y, 0f);
                float scrollRectBottom = scrollRect.transform.TransformPoint(scrollRectAnchorBottom).y;
 
                Vector3 childUpLeft = new Vector3(children[children.Count - 1].anchoredPosition.x, children[children.Count - 1].anchoredPosition.y, 0f);
 
                float childUp = transform.TransformPoint(childUpLeft).y;
 
                if (childUp < scrollRectBottom)
                {
                    //Debug.Log("childUp < scrollRectBottom");
 
                    //把底部的一行 移動(dòng)到頂部
                    for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                    {
                        children[children.Count - 1 - index].SetAsFirstSibling();
 
                        children[children.Count - 1 - index].anchoredPosition = new Vector2(children[children.Count - 1 - index].anchoredPosition.x, children[0].anchoredPosition.y + gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y);
 
                        children[children.Count - 1 - index].gameObject.SetActive(true);
 
                        UpdateChildrenCallback(realIndex - children.Count - index, children[children.Count - 1 - index]);
                    }
 
                    realIndex -= gridLayoutGroup.constraintCount;
 
                    //GridLayoutGroup 底部縮短;
                    rectTransform.sizeDelta -= new Vector2(0, gridLayoutGroup.cellSize.y + gridLayoutGroup.spacing.y);
 
                    //更新child;
                    for (int index = 0; index < children.Count; index++)
                    {
                        children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                    }
                }
            }
        }
        else
        {
            float offsetX = currentPos.x - startPosition.x;
 
            if (offsetX < 0)
            {
                //向左拉,向右擴(kuò)展;
                {
                    if (realIndex >= amount - 1)
                    {
                        startPosition = currentPos;
                        return;
                    }
 
                    float scrollRectLeft = scrollRect.transform.TransformPoint(Vector3.zero).x;
 
                    Vector3 childBottomRight = new Vector3(children[0].anchoredPosition.x+ gridLayoutGroup.cellSize.x, children[0].anchoredPosition.y, 0f);
                    float childRight = transform.TransformPoint(childBottomRight).x;
 
                   // Debug.LogError("childRight=" + childRight);
 
                    if (childRight <= scrollRectLeft)
                    {
                        //Debug.Log("childRight <= scrollRectLeft");
 
                        //移動(dòng)到右邊;
                        for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                        {
                            children[index].SetAsLastSibling();
 
                            children[index].anchoredPosition = new Vector2(children[children.Count - 1].anchoredPosition.x + gridLayoutGroup.cellSize.x + gridLayoutGroup.spacing.x, children[index].anchoredPosition.y);
 
                            realIndex++;
 
                            if (realIndex > amount - 1)
                            {
                                children[index].gameObject.SetActive(false);
                            }
                            else
                            {
                                UpdateChildrenCallback(realIndex, children[index]);
                            }
                        }
 
                        //GridLayoutGroup 右側(cè)加長(zhǎng);
                        rectTransform.sizeDelta += new Vector2(gridLayoutGroup.cellSize.x + gridLayoutGroup.spacing.x,0);
 
                        //更新child;
                        for (int index = 0; index < children.Count; index++)
                        {
                            children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                        }
                    }
                }
            }
            else
            {
                //Debug.Log("Drag Down");
                //向右拉废登,右邊收縮;
                if (realIndex + 1 <= children.Count)
                {
                    startPosition = currentPos;
                    return;
                }
                RectTransform scrollRectTransform = scrollRect.GetComponent<RectTransform>();
                Vector3 scrollRectAnchorRight = new Vector3(scrollRectTransform.rect.width + gridLayoutGroup.spacing.x, 0, 0f);
                float scrollRectRight = scrollRect.transform.TransformPoint(scrollRectAnchorRight).x;
 
                Vector3 childUpLeft = new Vector3(children[children.Count - 1].anchoredPosition.x, children[children.Count - 1].anchoredPosition.y, 0f);
 
                float childLeft = transform.TransformPoint(childUpLeft).x;
 
                if (childLeft >= scrollRectRight)
                {
                    //Debug.LogError("childLeft > scrollRectRight");
 
                    //把右邊的一行 移動(dòng)到左邊;
                    for (int index = 0; index < gridLayoutGroup.constraintCount; index++)
                    {
                        children[children.Count - 1 - index].SetAsFirstSibling();
 
                        children[children.Count - 1 - index].anchoredPosition = new Vector2(children[0].anchoredPosition.x - gridLayoutGroup.cellSize.x - gridLayoutGroup.spacing.x,children[children.Count - 1 - index].anchoredPosition.y);
 
                        children[children.Count - 1 - index].gameObject.SetActive(true);
 
                        UpdateChildrenCallback(realIndex - children.Count - index, children[children.Count - 1 - index]);
                    }
 
                    
 
                    //GridLayoutGroup 右側(cè)縮短;
                    rectTransform.sizeDelta -= new Vector2(gridLayoutGroup.cellSize.x + gridLayoutGroup.spacing.x, 0);
 
                    //更新child;
                    for (int index = 0; index < children.Count; index++)
                    {
                        children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                    }
 
                    realIndex -= gridLayoutGroup.constraintCount;
                }
            }
        }
 
        startPosition = currentPos;
    }
 
    void UpdateChildrenCallback(int index,Transform trans)
    {
        if (updateChildrenCallback != null)
        {
            updateChildrenCallback(index, trans);
        }
    }
 
 
    /// <summary>
    /// 設(shè)置總的個(gè)數(shù);
    /// </summary>
    /// <param name="count"></param>
    public void SetAmount(int count)
    {
        amount = count;
 
        StartCoroutine(InitChildren());
    }
}

MCV方式進(jìn)行ScrollView使用淹魄,并對(duì)內(nèi)部數(shù)據(jù)進(jìn)行設(shè)置

Model

public class ScrollVItemDataModel{
    public int index;
    public string name;
    public string imageURL;

    // 構(gòu)造方法
    public ScrollVItemDataModel(int Index, string Name,string ImageURL)
    {
        index = Index;
        name = Name;
        imageURL = ImageURL;
    }   
}

Control

public class ScrollViewItem : MonoBehaviour {

    // 獲取Item里面的控件
    private Button ItemBtn;
    private Text ItemBtnText;
    // 數(shù)據(jù)類(lèi)
    public ScrollViewItemData data;

    private void Awake()
    {
        ItemBtn =this.gameObject.GetComponent<Button>();
        ItemBtnText =  ItemBtn.GetComponentInChildren<Text>();      
    }

    public void SetData(ScrollViewItemData Data)
    {
        data = Data;
        ItemBtnText.text = Data.name;
    }
}

View

 // 添加數(shù)據(jù)與Item
    List<ScrollViewItem> itemList = new List<ScrollViewItem>();
    List<ScrollViewItemData> itemDataList = new List<ScrollViewItemData>();

    // 獲取網(wǎng)格布局組,進(jìn)行控件大小排布
    GridLayoutGroup grid;
    // 獲取rect控件
    ScrollRect scrollRect;
    // 設(shè)置布局大小
    ContentSizeFitter fitter;

    // 個(gè)數(shù)
    private int count = 20;

    void Start()
    {
        // 20條內(nèi)容
        for (int i = 0; i < count; i++)
        {
            itemDataList.Add(new ScrollViewItemData(i, "第" + i + "個(gè)元素", "https://123.com"));
        }
        // 獲取網(wǎng)格grid堡距,內(nèi)容尺寸fitter甲锡,scrollRect
        grid = GetComponent<GridLayoutGroup>();
        fitter = GetComponent<ContentSizeFitter>();
        scrollRect = GetComponentInParent<ScrollRect>();
        //監(jiān)聽(tīng)ScrollRect的回調(diào)
        // scrollRect.onValueChanged.AddListener((data) => { ScrollCallback(data); });
        // 獲取ScrollView寬高(像素)
        Vector2 viewSize = scrollRect.GetComponent<RectTransform>().sizeDelta;
       // Debug.Log(viewSize.y);
       // Debug.Log(grid.cellSize.y);
        
        // 生成20的預(yù)制體
        for (int i = 0; i < count; i++)
        {
            if (itemDataList.Count <= i)
                break;
            GameObject itemR = Resources.Load("Prefabs/Item") as GameObject;
            GameObject itemObj = Instantiate(itemR, this.transform) as GameObject;
            ScrollViewItem item = itemObj.AddComponent<ScrollViewItem>();
            itemList.Add(item);
            item.SetData(itemDataList[i]);
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市羽戒,隨后出現(xiàn)的幾起案子缤沦,更是在濱河造成了極大的恐慌,老刑警劉巖半醉,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疚俱,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡缩多,警方通過(guò)查閱死者的電腦和手機(jī)呆奕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)衬吆,“玉大人梁钾,你說(shuō)我怎么就攤上這事⊙仿眨” “怎么了姆泻?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)冒嫡。 經(jīng)常有香客問(wèn)我拇勃,道長(zhǎng),這世上最難降的妖魔是什么孝凌? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任方咆,我火速辦了婚禮,結(jié)果婚禮上蟀架,老公的妹妹穿的比我還像新娘瓣赂。我一直安慰自己榆骚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布煌集。 她就那樣靜靜地躺著妓肢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪苫纤。 梳的紋絲不亂的頭發(fā)上碉钠,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音方面,去河邊找鬼放钦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛恭金,可吹牛的內(nèi)容都是我干的操禀。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼横腿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼颓屑!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起耿焊,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤揪惦,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后罗侯,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體器腋,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年钩杰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纫塌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡讲弄,死狀恐怖措左,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情避除,我是刑警寧澤怎披,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站瓶摆,受9級(jí)特大地震影響凉逛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜群井,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一鱼炒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦昔瞧、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至稍坯,卻和暖如春酬荞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瞧哟。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工混巧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人勤揩。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓咧党,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親陨亡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子傍衡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Canvas 渲染順序 遵循刷油漆規(guī)則(畫(huà)家算法) 依次由Render CameraDepth值、Sorting ...
    沉麟閱讀 1,463評(píng)論 0 0
  • 一负蠕、Unity簡(jiǎn)介 1. Unity界面 Shift + Space : 放大界面 Scene界面按鈕渲染模式2D...
    MYves閱讀 8,207評(píng)論 0 22
  • 1蛙埂、通過(guò)CocoaPods安裝項(xiàng)目名稱(chēng)項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明先生_X自主閱讀 15,980評(píng)論 3 119
  • 秋天的樹(shù)葉,是你寄托的思念遮糖。 疆邊的戍守绣的,是你一生的追求。 當(dāng)花兒盛開(kāi)欲账,夢(mèng)想在靜靜怒放屡江。 愿你能幸福,家等著英雄歸來(lái)敬惦。
    ting夢(mèng)想抱著你閱讀 230評(píng)論 0 1
  • 有效的本地 cache 機(jī)制盼理,可以避免不必要的重復(fù)網(wǎng)絡(luò)加載,不僅能提高相關(guān)應(yīng)用場(chǎng)景的資源加載速度俄删,也可以避免不必要...
    coderanger閱讀 4,001評(píng)論 0 3