Implementation of timing sliding bulletin board in unity and dynamically setting the size of gridLayout

First post the effect:
insert image description here
1. Dynamically set the size of the gridLayout.
The core component is rectTransform, and the core attribute is rectTransform.anchoredPosition, which is used to set the distance from the anchor point. Otherwise, only setting the width and height will cause the grid to only use the anchor point (usually centered) Center extension. The second core property is rectTransform.sizeDelta, which is used to set the width and height of the control. It is very simple to implement, just get the width and height of the picture put in and multiply it by the total to get the total width and height of the sliding box.

boardBtns.GetComponent<RectTransform>().anchoredPosition = new Vector2(posX*(num-1),0);
boardBtns.GetComponent<RectTransform>().sizeDelta = new Vector2(width*num, boardBtns.GetComponent<RectTransform>().rect.height);

boardBtns is the control containing the gridLayout component, which is the parent object of all announcements.

2. Realization of timed sliding bulletin board
The core component is scrollrect, and
the value of the core property scrollrect.horizontalNormalizedPosition returns a floating point number of 0-1. After experimenting, you will know that this can be used to control where the sliding frame is drawn. The smaller the value, the better close to the start.
And the drag interface that needs to inherit the Unity event, which are IBeginDragHandler and IEndDragHandler (IDragHandler is used to monitor events when dragging, but it is not implemented if it feels useless). At the same time, a core variable needs to be set to indicate which page to slide to now,
I Name it currIndex, and when you slide to the currIndex page (starting from 0), the value of the above scrollrect.horizontalNormalizedPosition is currIndex * ((float)1 / (num - 1)))

 public void OnBeginDrag(PointerEventData eventData)//记录起始位置
    {
    
    
        lastX = sr.horizontalNormalizedPosition;
    }

    public void OnEndDrag(PointerEventData eventData)//滑动结束,根据判断的方向设置index的加减然后根据index的值朝某个方向滑动
    {
    
    
        if (Mathf.Abs(lastX- sr.horizontalNormalizedPosition)>=0.01f)
        {
    
    
            if (lastX < sr.horizontalNormalizedPosition)//向左划
            {
    
    
                if (currIndex<num-1)
                {
    
    
                    currIndex++;
                    StopAllCoroutines();//一定要停止协程!!否则会导致协程重复执行,滑动框会乱划
                    StartCoroutine(MoveTo(currIndex * ((float)1 / (num - 1))));
                }
            }
            else if (lastX > sr.horizontalNormalizedPosition)//向右划
            {
    
    
                if (currIndex >0)
                {
    
    
                    currIndex--;
                    StopAllCoroutines();
                    StartCoroutine(MoveTo(currIndex * ((float)1 / (num - 1))));
                }
            }
        }
    }

Next, implement the function of using the coroutine to smoothly move the bulletin board, mainly using the Mathf.Lerp interpolation function.

IEnumerator MoveTo(float targetX)
    {
    
    
        while (true)
        {
    
    
            if (Mathf.Abs(sr.horizontalNormalizedPosition - targetX) >= 0.01f)//未到时滑动
            {
    
    
                sr.horizontalNormalizedPosition = Mathf.Lerp(
                sr.horizontalNormalizedPosition, targetX,
                Time.deltaTime * (Mathf.Abs(currIndex - lastIndex)*10));
            }
            else//停止
            {
    
    
                sr.horizontalNormalizedPosition = targetX;
                lastIndex = currIndex;
                toggles[currIndex].isOn = true;
                timer = 0;
                canSlide = true;
                break;
            }
            yield return null;
        }
    }

Next, click the toggle to jump to the corresponding page. In the scene, you need to add a toggleGroup component on the bulletin board and set the group of each toggle to this toggleGroup, and then add a listening event for the toggle value change event, mainly changing the value of currIndex, and The i in the toggle array corresponds one by one.

bt.onValueChanged.AddListener((bool isOn)=> {
    
     OnboardToggleClick(isOn,bt); });
void OnboardToggleClick(bool isOn,Toggle t)
    {
    
    
        for (int i = 0; i < toggles.Length; i++)
        {
    
    
            if (toggles[i].isOn) {
    
     currIndex = i; break; }
        }
        StopAllCoroutines();
        StartCoroutine(MoveTo(currIndex * ((float)1 / (num - 1))));
    }

Finally, the timing function is realized. In fact, it is to set a timer to increase the currIndex cycle, and then start the mobile coroutine.

void Update () {
    
    
        timer += Time.deltaTime;
        if (timer>=6 && canSlide)//6s滑动一次
        {
    
    
            canSlide = false;
            if (currIndex < num-1) currIndex++;
            else currIndex = 0;
            StopAllCoroutines();
            StartCoroutine(MoveTo(currIndex * ((float)1 / (num-1))));
        }
	}

Finally, paste the code of the entire script. I wrote two scenes, which can be reused. Most of the other operations are to assign values ​​to Image and Text and to add listener events to Button, which can be played freely.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;

public class OnBoard : MonoBehaviour,IBeginDragHandler,IEndDragHandler{
    
    
    float posX;//board偏移量
    float width;//board宽度
    float height;//board高度
    Transform boardBtns;
    ScrollRect sr;
    Transform boardToggles;
    int num;//the count of boards
    Toggle[] toggles;
    string[] boardTexts;
    Sprite[] boardImages;
    int lastIndex;//上次索引(toggle)
    int currIndex;//现在索引
    float lastX;//上次sr位置
    float timer;
    bool canSlide = true;
    //timer to auto slide
    // Use this for initialization
    void Start () {
    
    
        switch (SceneManager.GetActiveScene().name)
        {
    
    
            case "Main":
                num = 4;
                boardImages = new Sprite[num];
                boardImages = Resources.LoadAll<Sprite>("Background");
                boardTexts = new string[]{
    
     "Battle", "Heroes", "Room", "Summon" };
                break;
            case "Summon":
                num = 3;
                boardImages = new Sprite[num];
                boardImages = Resources.LoadAll<Sprite>("Summon");
                boardTexts = new string[num];
                break;
            default:
                break;
        }
        toggles = new Toggle[num];
        
        boardBtns = transform.Find("boardBtns");
        sr = GetComponent<ScrollRect>();
        boardToggles = transform.Find("boardToggles");
        width = boardBtns.GetComponent<RectTransform>().sizeDelta.x;
        height= boardBtns.GetComponent<RectTransform>().sizeDelta.y;
        posX = width / 2;
        boardBtns.GetComponent<RectTransform>().anchoredPosition = new Vector2(posX*(num-1),0);
        boardBtns.GetComponent<RectTransform>().sizeDelta = new Vector2(width*num, boardBtns.GetComponent<RectTransform>().rect.height);
        //instantiate btns and toggles
        for (int i = 0; i < num; i++)
        {
    
    
            //btns
            GameObject boardBtn = Instantiate((GameObject)GameFuncs.GetResource("Prefabs/boardBtn"));
            boardBtn.GetComponent<RectTransform>().sizeDelta = new Vector2(width, height);
            boardBtn.transform.SetParent(boardBtns);
            boardBtn.GetComponent<Image>().sprite = boardImages[i];
            boardBtn.GetComponentInChildren<Text>().text = boardTexts[i];
            boardBtn.GetComponent<Button>().onClick.AddListener(()=> {
    
     OnboardBtnClick(boardBtn.GetComponentInChildren<Text>().text); });
            //toggles
            GameObject boardToggle = Instantiate((GameObject)GameFuncs.GetResource("Prefabs/boardToggle"));
            boardToggle.transform.SetParent(boardToggles);
            Toggle bt = boardToggle.GetComponent<Toggle>();
            bt.group = boardToggles.GetComponent<ToggleGroup>();
            if (i == 0) bt.isOn = true;
            bt.onValueChanged.AddListener((bool isOn)=> {
    
     OnboardToggleClick(isOn,bt); });
            toggles[i] = bt;
        }
    }
	
	// 定时滚动
	void Update () {
    
    
        timer += Time.deltaTime;
        if (timer>=6 && canSlide)//6s滑动一次
        {
    
    
            canSlide = false;
            if (currIndex < num-1) currIndex++;
            else currIndex = 0;
            StopAllCoroutines();
            StartCoroutine(MoveTo(currIndex * ((float)1 / (num-1))));
        }
	}
    void OnboardBtnClick(string boardStr)
    {
    
    
        switch (SceneManager.GetActiveScene().name)
        {
    
    
            case "Main":
                GameFuncs.GoToSceneAsync(boardStr);
                break;
            case "Summon":
                break;
            default:
                break;
        } 
    }
    void OnboardToggleClick(bool isOn,Toggle t)
    {
    
    
        for (int i = 0; i < toggles.Length; i++)
        {
    
    
            if (toggles[i].isOn) {
    
     currIndex = i; break; }
        }
        StopAllCoroutines();
        StartCoroutine(MoveTo(currIndex * ((float)1 / (num - 1))));
    }
    public void OnBeginDrag(PointerEventData eventData)
    {
    
    
        lastX = sr.horizontalNormalizedPosition;
    }

    public void OnEndDrag(PointerEventData eventData)//toggle change ison
    {
    
    
        if (Mathf.Abs(lastX- sr.horizontalNormalizedPosition)>=0.01f)
        {
    
    
            if (lastX < sr.horizontalNormalizedPosition)//向左划
            {
    
    
                if (currIndex<num-1)
                {
    
    
                    currIndex++;
                    StopAllCoroutines();
                    StartCoroutine(MoveTo(currIndex * ((float)1 / (num - 1))));
                }
            }
            else if (lastX > sr.horizontalNormalizedPosition)//向右划
            {
    
    
                if (currIndex >0)
                {
    
    
                    currIndex--;
                    StopAllCoroutines();
                    StartCoroutine(MoveTo(currIndex * ((float)1 / (num - 1))));
                }
            }
        }
    }
    IEnumerator MoveTo(float targetX)
    {
    
    
        while (true)
        {
    
    
            if (Mathf.Abs(sr.horizontalNormalizedPosition - targetX) >= 0.01f)
            {
    
    
                sr.horizontalNormalizedPosition = Mathf.Lerp(
                sr.horizontalNormalizedPosition, targetX,
                Time.deltaTime * (Mathf.Abs(currIndex - lastIndex)*10));
            }
            else
            {
    
    
                sr.horizontalNormalizedPosition = targetX;
                lastIndex = currIndex;
                toggles[currIndex].isOn = true;
                timer = 0;
                canSlide = true;
                break;
            }
            yield return null;
        }
    }
}

Guess you like

Origin blog.csdn.net/qq_39804671/article/details/100717948