Implementation of UGUI picture running lamp

Posted by ShogunWarrior on Fri, 12 Nov 2021 15:39:25 +0100

Today, we use UGUI to display multiple pictures automatically. The details are as follows

1. Read all pictures from a specific folder

2. Arrange and display all pictures. If it is beyond the range of the screen, scroll circularly

3. Click the picture and pause scrolling. The picture is enlarged and displayed in the middle of the screen. Click again to zoom back and continue scrolling.

First, traverse the folder and read all the pictures

// Get all pictures in a specific path
    Dictionary<string, Texture2D> GetAllImgInPath( string fullPath)
    {
        Dictionary<string, Texture2D> retDict = new Dictionary<string, Texture2D>();
        // First determine whether the path exists
        if( Directory.Exists( fullPath) == false)
        {
            return retDict;
        }
        // Traverse all files in the path
        string [] filePathArr = Directory.GetFiles( fullPath);
        string ext = string.Empty;
        string []imgExtArr = new string[]{".jpg", ".png", ".bmp"};
        foreach( string fullName in filePathArr)
        {
            // Judge whether it is a picture according to the suffix
            ext = Path.GetExtension( fullName);
            if( ((IList)imgExtArr).Contains(ext))
            {
                // Read image
                byte[] imgBytes = File.ReadAllBytes( fullName);
                Texture2D t2d = new Texture2D(1,1);
                t2d.LoadImage( imgBytes);
                retDict.Add( Path.GetFileName( fullName), t2d);
            }
        }
        return retDict;
    }

Then create a RawImage object for each image. I can't find a function to directly create ugui controls in ugui. I can only make a RawImage preset, and then use the preset to Instantiate a new one.

// Initialize all images
    void InitAllImg( Dictionary<string, Texture2D> texDict)
    {
        if( m_imgCellPerfab == null || m_imgCellParent == null)
        {
            Debug.LogError( "InitAllImg ERR!! The preset or parent node is null!");
            return;
        }
        m_allImgs.Clear();
        foreach( KeyValuePair<string, Texture2D> pair in texDict)
        {   
            // New rawImage
            Texture2D t2d = pair.Value;
            RawImage imgCell = Instantiate( m_imgCellPerfab);
            imgCell.texture = t2d;
            imgCell.GetComponent<Transform>().SetParent( m_imgCellParent, false);
            // Add a click event to the picture
            EventTriggerListener.Get(imgCell.gameObject).onDown += OnClickImg;
            m_allImgs.Add( imgCell);
        }

        InitImgPos();
    }

Now that these pictures can be displayed, it's time to deal with the location of these pictures. Set a spacing distance, and then calculate the initial position of the next image according to the width of the image

// Initialization location
    void InitImgPos()
    {
        // First calculate the total width
        float totalW = m_spacing;
        foreach( RawImage img in m_allImgs)
        {
            // Picture width + spacing
            RectTransform rectTran = img.GetComponent<RectTransform>();
            totalW = totalW + rectTran.rect.width + m_spacing;
        }
        // Center if the total width is smaller than the parent node width. If the total width is larger than the width of the parent node, start from the far left
        Vector2 parentSize = m_imgCellParent.GetComponent<RectTransform>().sizeDelta;
        float startX = 0;
        if( totalW < parentSize.x)
        {
            // Center
            startX = -totalW/2;
        }
        else
        {
            // From the far left
            startX = -parentSize.x/2;
        }
        float x = startX + m_spacing;
        // Initialize the location of each picture
        foreach( RawImage img in m_allImgs)
        {
            // Picture width + spacing
            RectTransform rectTran = img.GetComponent<RectTransform>();
            // Because it is center aligned, the offset is half the width
            x = x + rectTran.sizeDelta.x/2; 
            rectTran.localPosition = new Vector3( x, 0, 0);
            // Location of next picture
            x = x + rectTran.sizeDelta.x/2 + m_spacing;
        }
    }

After that, the movement is processed, that is, the moving distance is calculated according to the speed of each frame, and then each picture moves this distance. If the movement is beyond the range of the parent node, reset the position to the back of the queue (that is, the current position plus the total width)

// useTime: the time used to process the move
    void DealMove( float useTime)
    {
        float dis = useTime * m_moveSp;
        float x = 0;
        Vector2 parentSize = m_imgCellParent.GetComponent<RectTransform>().sizeDelta;
        // After traversing all the pictures, calculate the new location
        foreach( RawImage img in m_allImgs)
        {
            RectTransform rectTran = img.GetComponent<RectTransform>();
            x = rectTran.localPosition.x - dis;
            // If you run out of range, add it to the back
            if( x < -(parentSize.x/2 + rectTran.sizeDelta.x/2 + m_spacing))
            {
                x = x + m_totalWidth;
            }
            rectTran.localPosition = new Vector3( x, 0, 0);
        }
    }

So far, the running lantern effect of circular rolling has been completed.

 

Next, we need to deal with the start / stop of zooming in / out and scrolling after clicking the picture.

        To achieve the zoom in / out effect, you need to create another picture specifically for zoom in and out. Because if you zoom in directly with the original image, if its level is not the highest, the image with a higher level will be covered on it after zooming in. The dotween plug-in is required for image zooming.

// Start Popup
    public void StartPop( RawImage srcImg, PopCB popCB)
    {
        m_srcImg = srcImg;
        m_popCB = popCB;
        // 
        m_popPlane.SetActive( true);
        // Initialize the size and position of the picture to be scaled according to the source picture
        RectTransform rectTran = m_scaleImg.GetComponent<RectTransform>();
        RectTransform srcImgTran = srcImg.GetComponent<RectTransform>();
        rectTran.sizeDelta = srcImgTran.sizeDelta;
        rectTran.localPosition = srcImgTran.localPosition;
        m_scaleImg.texture = srcImg.texture;
        // Calculate the multiple that needs to be scaled
        float scaleX = m_maxSize.x/srcImgTran.sizeDelta.x;
        float scaleY = m_maxSize.y/srcImgTran.sizeDelta.y;
        float scale = Mathf.Min( scaleX, scaleY);
        m_bWaiting = true;
        Sequence quence = DOTween.Sequence();
        quence.Append( rectTran.DOScale( new Vector3(scale, scale, 1), m_animTime));
        quence.Join( rectTran.DOLocalMove( new Vector3(0,0,0), m_animTime));
        quence.AppendCallback( ()=>{
            // Animation complete
            m_bWaiting = false;
        });  
    }

It is used when adding click events to the picture

EventTriggerListener.Get(imgCell.gameObject).onDown += OnClickImg;

EventTriggerListener is an event listening class encapsulated by itself. See the project source file for the specific code.

Topics: Unity Unity3d