Problema de unidade: quando ScrollView, LayoutGroup e ContentSizeFitter são usados juntos, a interface de adaptação não pode ser atualizada e atualizada a tempo quando ocorrem alterações dinâmicas.

Problema de unidade: quando ScrollView, LayoutGroup e ContentSizeFitter são usados ​​juntos, a interface de adaptação não pode ser atualizada e atualizada a tempo quando ocorrem alterações dinâmicas.

Índice

Problema de unidade: quando ScrollView, LayoutGroup e ContentSizeFitter são usados ​​juntos, a interface de adaptação não pode ser atualizada e atualizada a tempo quando ocorrem alterações dinâmicas.

1. Breve introdução

2. Fenômeno problemático

3. Análise de problemas

4. Ideias para resolução de problemas

5. Etapas de implementação da solução de caso

6. Código chave do caso


1. Breve introdução

Durante o desenvolvimento do Unity, registramos alguns relatórios de erros para que possamos lidar com os mesmos problemas posteriormente.

Às vezes usamos ScrollView, LayoutGroup e ContentSizeFitter juntos durante o desenvolvimento. Para layouts simples, eles geralmente se atualizam e se adaptam automaticamente muito bem, mas às vezes, quando são complicados, podem não se ajustar e se adaptar automaticamente bem.

ScrollView exibe conteúdo em uma área rolável. Quando você adiciona conteúdo a um ScrollView, o conteúdo é adicionado ao contêiner de conteúdo do ScrollView (#unity-content-container).

Layout Group é traduzido como "grupo de layout". Pode ser entendido a partir do significado literal. Ele pode fazer o layout dinâmico de um grupo de elementos. A dinâmica mencionada aqui é que quando o número de elementos no grupo muda, o Layout Group pode ajudá-lo de forma inteligente re-layout.

ContentSizeFitter atua como um controlador de layout, controlando o tamanho de seus próprios elementos de layout. O tamanho é determinado pelo tamanho mínimo ou preferencial fornecido pelo componente do elemento de layout no objeto do jogo. Esses elementos de layout podem ser componentes de imagem ou texto, grupos de layout ou componentes de elementos de layout.

É importante notar que quando uma transformação de retângulo é dimensionada - seja por meio de ContentSizeFitter ou outra coisa - a escala é dimensionada em torno de um valor base. Isso significa que você pode usar o valor base para controlar a direção da escala.

Por exemplo, quando o pivô estiver no centro, o ContentSizeFitter expandirá a transformação retangular uniformemente em todas as direções. Quando o pivô está no canto superior esquerdo, o redimensionador de conteúdo expande a transformação do retângulo para baixo e para a direita.

2. Fenômeno problemático

No fenômeno, não há problema com a exibição do layout gerado no início. Quando alguns itens são adicionados dinamicamente, a exibição do layout ficará incorreta, haverá sobreposição ou o layout deslizante de rolagem não será totalmente exibido.

3. Análise de problemas

Dentro do estojo:

Quando há muito conteúdo, ScrollView pode ser usado para deslizar e navegar automaticamente pelo conteúdo, LayoutGroup é usado para organização e ContentSizeFitter é usado para adaptar e ajustar automaticamente o tamanho da tela.

Vale ressaltar: utilizo aqui o LayoutGroup e o ContentSizeFitter aninhados, ou seja, os subobjetos do Item também possuem os componentes LayoutGroup e ContentSizeFitter que organizam e adaptam automaticamente o tamanho.

Devido ao aninhamento, durante a geração dinâmica, LayoutGroup e ContentSizeFitter também são aninhados no objeto filho. Quando LayoutGroup e ContentSizeFitter no objeto pai são calculados, ocorrerão erros de cálculo, o layout estará incorreto e o layout deslizante de rolagem não será totalmente exibido . O fenomeno.

4. Ideias para resolução de problemas

1. Atualização forçada da tela

Canvas.ForceUpdateCanvases();

2. Para gridLayout, verticalLayout ou horizontalLayout do Unity, muitas vezes há o problema de que o tamanho e a posição do componente estão incorretos após adicionar novos membros ou alterar o tamanho do membro. De modo geral, este método pode resolver o problema.

LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform);

3. Use switch gameobject para aguardar um quadro ou outros métodos para resolver o problema e, em seguida, processe-o.

horizLayoutGroup.CalculateLayoutInputHorizontal();
horizLayoutGroup.CalculateLayoutInputVertical();
horizLayoutGroup.SetLayoutHorizontal();
horizLayoutGroup.SetLayoutVertical();

4. Além disso, o componente ContentSizeFitter pode ajustar automaticamente o tamanho do objeto pai de acordo com o tamanho de seus objetos filhos. No entanto, às vezes, após adicionar conteúdo dinamicamente, ContentSizeFitter pode não ser atualizado imediatamente. Você pode inserir o seguinte

// 手动强制更新 ContentSizeFitter
ContentSizeFitter contentSizeFitter = yourContent.GetComponent<ContentSizeFitter>();
if (contentSizeFitter != null)
{
    contentSizeFitter.SetLayoutHorizontal();
    contentSizeFitter.SetLayoutVertical();
}

5. Atualização atrasada: Se uma atualização não conseguir atingir o efeito de atualização, após adicionar conteúdo ao ScrollRect, às vezes é necessário atualizar o escopo da visualização de rolagem e da barra de rolagem no próximo quadro. Isso pode ser conseguido colocando a atualização no LateUpdate.

  • Se consumir mais desempenho aqui,
  • Você pode tentar acionar a atualização quando houver uma alteração na IU de dados e desativar a atualização após um determinado período de tempo.
  • Basta fazer ajustes razoáveis ​​conforme necessário
void LateUpdate()
{
    // 在 LateUpdate 中更新内容和滚动条范围
    // 更新 Content 大小
    // 更新滚动条范围
}

5. Etapas de implementação da solução de caso

1. Crie um projeto Unity e organize a IU da seguinte maneira, principalmente Scroll View, e adicione os componentes LayoutGroup e ContentSizeFitter ao Content

2. Descrição do pré-fabricado a ser instanciado, ImageGroup e ImageItem

3. Crie um novo script para gerar dinamicamente o conteúdo do ScrollView, inicie a parte de pré-geração e pressione a barra de espaço para gerar aleatoriamente

4. Monte o teste na cena, atribua o objeto pai e o pré-fabricado correspondente

5. Execute, pressione a barra de espaço para gerar itens aleatoriamente. Às vezes, pode não ser possível se adaptar e atualizar a tempo.

6. Após o processamento correspondente, aqui está a atualização no LateUpdate

  • Se consumir mais desempenho aqui,
  • Você pode tentar acionar a atualização quando houver uma alteração na IU de dados e desativar a atualização após um determinado período de tempo.
  • Basta fazer ajustes razoáveis ​​conforme necessário

7. O problema de não conseguir atualizar o layout a tempo durante a execução da cena foi basicamente resolvido.

6. Código chave do caso


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

/// <summary>
/// ScrollView ,LayoutGroup,ContentSizeFitter 一起使用时,动态变化时无法及时刷新更新适配界面的问题
/// </summary>
public class Test : MonoBehaviour
{
    #region Data

    /// <summary>
    /// ImageGroup 预制体
    /// </summary>
    public GameObject ImageGroup;
    /// <summary>
    /// ImageItem 预制体
    /// </summary>
    public GameObject ImageItem;
    /// <summary>
    /// ParentTran 父物体 ImageGroup
    /// </summary>
    public Transform ParentTran;

    /// <summary>
    /// ImageGroup 列表
    /// </summary>
    List<GameObject> m_ImageGroupGoLst;

    #endregion

    #region Lifecycle function
    /// <summary>
    /// Start is called before the first frame update
    /// </summary>
    void Start()
    {
        Init();
    }

    /// <summary>
    /// Update is called once per frame
    /// </summary>
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space)) {
            GameObject go = GetRandomImageGroup();
            CreateImageItemGameObject(go.transform);
        }
    }

    /// <summary>
    /// LateUpdate is called once per frame
    /// </summary>
    private void LateUpdate()
    {
        // 如果这里比较耗性能,
        // 可以试着在有数据UI变化的时候触发更新若干时间关闭更新
        // 根据需要合理调整即可
        RefreshUICanvas();
    }

    #endregion

    #region Private Function

    /// <summary>
    /// 初始化生成部分队列
    /// </summary>
    void Init() {
        m_ImageGroupGoLst = new List<GameObject>();
        for (int i = 0; i < 2; i++)
        {
            GameObject go = CreateImageGroupGameObject();
            if (i == 1) {
                for (int ii = 0; ii < 4; ii++)
                {
                    CreateImageItemGameObject(go.transform);
                }
            }
            m_ImageGroupGoLst.Add(go);
        }
    }

    /// <summary>
    /// 生成 ImageGroup 实体
    /// </summary>
    /// <returns></returns>
    GameObject CreateImageGroupGameObject() {
        return GameObject.Instantiate(ImageGroup, ParentTran,false);
    }

    /// <summary>
    /// 生成 ImageItem 实体
    /// </summary>
    /// <returns></returns>
    GameObject CreateImageItemGameObject(Transform parent)
    {
        return GameObject.Instantiate(ImageItem, parent, false);
    }

    /// <summary>
    /// 随机获取 生成的 ImageGroup 实体
    /// </summary>
    /// <returns></returns>
    GameObject GetRandomImageGroup() {
        int index = Random.Range(0, m_ImageGroupGoLst.Count);
        GameObject go = m_ImageGroupGoLst[index];
        return go;
    }

    /// <summary>
    /// 刷新 UI  界面
    /// </summary>
    void RefreshUICanvas()
    {
        // 强制刷新
        Canvas.ForceUpdateCanvases();
        // Layout 重建
        LayoutRebuilder.ForceRebuildLayoutImmediate(ParentTran.GetComponent<RectTransform>());

        // contentSizeFitter 设置
        ContentSizeFitter contentSizeFitter = ParentTran.GetComponent<ContentSizeFitter>();
        if (contentSizeFitter != null)
        {
            contentSizeFitter.SetLayoutHorizontal();
            contentSizeFitter.SetLayoutVertical();
        }
    }

    #endregion
}

Guess you like

Origin blog.csdn.net/u014361280/article/details/135153311