【Unity3D】无限循环列表(扩展版)

news2024/12/16 13:55:10

  基础版:【Unity技术分享】UGUI之ScrollRect优化_ugui scrollrect 优化-CSDN博客

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

public delegate void OnBaseLoopListItemCallback(GameObject cell, int index);
public class BaseLoopList : MonoBehaviour
{
    public int m_Row = 1; //排
    public bool m_IsVertical = true;
    public float m_SpacingX = 0f; //间距
    public float m_SpacingY = 0f; //间距
    public GameObject m_CellGameObject; //指定的cell

    private Dictionary<GameObject, int> m_GameObjectNumDict;


    //-> 回调相关        
    public event OnBaseLoopListItemCallback onItemShow; //Lua 回调
    public event OnBaseLoopListItemCallback onItemHide; //Lua 回调

    protected RectTransform rectTrans;


    protected float m_PlaneWidth;
    protected float m_PlaneHeight;


    protected float m_ContentWidth;
    protected float m_ContentHeight;


    protected float m_CellObjectWidth;
    protected float m_CellObjectHeight;


    protected GameObject m_Content;
    protected RectTransform m_ContentRectTrans;


    private bool m_isInited = false;


    //记录 物体的坐标 和 物体 
    protected struct CellInfo
    {
        public Vector3 pos;
        public GameObject obj;
    };
    protected CellInfo[] m_CellInfos;


    protected bool m_IsInited = false;


    protected ScrollRect m_ScrollRect;


    protected int m_MaxCount = -1; //列表数量


    protected int m_MinIndex = -1;
    protected int m_MaxIndex = -1;


    protected bool m_IsClearList = false; //是否清空列表

    protected Vector4 m_Padding = Vector4.zero; //(left,top,right,bottom) 左,上 偏移Item(左上角为锚点) 右,下 扩大Content(宽度和高度)


    //c# 初始化
    public virtual void Init()
    {
        if (m_isInited)
            return;

        m_isInited = true;

        m_GameObjectNumDict = new Dictionary<GameObject, int>();
        m_Content = this.GetComponent<ScrollRect>().content.gameObject;


        if (m_CellGameObject == null)
        {
            //m_CellGameObject = m_Content.transform.GetChild(0).gameObject;
            Debug.LogError("m_CellGameObject 不能为 null");
        }
        /* Cell 处理 */
        //m_CellGameObject.transform.SetParent(m_Content.transform.parent, false);
        //SetPoolsObj(m_CellGameObject);

        RectTransform cellRectTrans = m_CellGameObject.GetComponent<RectTransform>();
        cellRectTrans.pivot = new Vector2(0f, 1f);
        CheckAnchor(cellRectTrans);
        cellRectTrans.anchoredPosition = Vector2.zero;


        //记录 Cell 信息
        m_CellObjectHeight = cellRectTrans.rect.height;
        m_CellObjectWidth = cellRectTrans.rect.width;


        //记录 Plane 信息
        rectTrans = GetComponent<RectTransform>();
        Rect planeRect = rectTrans.rect;
        m_PlaneHeight = planeRect.height;
        m_PlaneWidth = planeRect.width;


        //记录 Content 信息
        m_ContentRectTrans = m_Content.GetComponent<RectTransform>();
        Rect contentRect = m_ContentRectTrans.rect;
        SetContentHeight(contentRect.height);
        SetContentWidth(contentRect.width);


        m_ContentRectTrans.pivot = new Vector2(0f, 1f);
        //m_ContentRectTrans.sizeDelta = new Vector2 (planeRect.width, planeRect.height);
        //m_ContentRectTrans.anchoredPosition = Vector2.zero;
        CheckAnchor(m_ContentRectTrans);


        m_ScrollRect = this.GetComponent<ScrollRect>();


        m_ScrollRect.onValueChanged.RemoveAllListeners();
        //添加滑动事件
        m_ScrollRect.onValueChanged.AddListener(delegate (Vector2 value) { ScrollRectListener(value); });
    }

    public virtual void Destroy()
    {
        if (m_CellInfos != null)
        {
            for (int i = 0; i < m_CellInfos.Length; i++)
            {
                SetPoolsObj(m_CellInfos[i].obj);
                m_CellInfos[i].obj = null;
            }
        }
        m_GameObjectNumDict.Clear();
    }

    private void DisposeAll()
    {
        m_Padding = Vector4.zero;
        onItemShow = null;
        onItemHide = null;
        if (poolsObj != null)
        {
            foreach (var v in poolsObj)
            {
                if (v != null)
                {
                    GameObject.Destroy(v);
                }
            }
            poolsObj = null;
        }
        if (m_CellInfos != null)
        {
            foreach (var v in m_CellInfos)
            {
                if (v.obj != null)
                {
                    GameObject.Destroy(v.obj);
                }
            }
            m_CellInfos = null;
        }
    }

    //检查 Anchor 是否正确
    private void CheckAnchor(RectTransform rectTrans)
    {
        if (m_IsVertical)
        {
            if (!((rectTrans.anchorMin == new Vector2(0, 1) && rectTrans.anchorMax == new Vector2(0, 1)) ||
                     (rectTrans.anchorMin == new Vector2(0, 1) && rectTrans.anchorMax == new Vector2(1, 1))))
            {
                rectTrans.anchorMin = new Vector2(0, 1);
                rectTrans.anchorMax = new Vector2(1, 1);
            }
        }
        else
        {
            if (!((rectTrans.anchorMin == new Vector2(0, 1) && rectTrans.anchorMax == new Vector2(0, 1)) ||
                     (rectTrans.anchorMin == new Vector2(0, 0) && rectTrans.anchorMax == new Vector2(0, 1))))
            {
                rectTrans.anchorMin = new Vector2(0, 0);
                rectTrans.anchorMax = new Vector2(0, 1);
            }
        }
    }

    public void SetPadding(float left, float top, float right, float bottom)
    {
        m_Padding = new Vector4(left, top, right, bottom);
        SetContentWidth(m_ContentWidth);
        SetContentHeight(m_ContentHeight);
    }

    private float GetPaddingX()
    {
        return m_Padding.x;
    }

    private float GetPaddingY()
    {
        return m_Padding.y;
    }

    private float GetExpandWidth()
    {
        return m_Padding.z;
    }

    private float GetExpandHeight()
    {
        return m_Padding.w;
    }

    public void SetContentWidth(float value)
    {
        m_ContentWidth = value + GetPaddingX() + GetExpandWidth();
        m_ContentWidth = m_ContentWidth < rectTrans.rect.width ? rectTrans.rect.width : m_ContentWidth;
    }

    public void SetContentHeight(float value)
    {
        m_ContentHeight = value + GetPaddingY() + GetExpandHeight();
        m_ContentHeight = m_ContentHeight < rectTrans.rect.height ? rectTrans.rect.height : m_ContentHeight;
    }

    public virtual void SetCount(int num)
    {
        m_MinIndex = -1;
        m_MaxIndex = -1;


        //-> 计算 Content 尺寸
        if (m_IsVertical)
        {
            float contentSize = (m_SpacingY + m_CellObjectHeight) * Mathf.CeilToInt((float)num / m_Row);
            SetContentHeight(contentSize);
            SetContentWidth(m_ContentRectTrans.rect.width);
            m_ContentRectTrans.sizeDelta = new Vector2(m_ContentWidth, m_ContentHeight);
            if (num != m_MaxCount)
            {
                m_ContentRectTrans.anchoredPosition = new Vector2(m_ContentRectTrans.anchoredPosition.x, 0);
            }
        }
        else
        {
            float contentSize = (m_SpacingX + m_CellObjectWidth) * Mathf.CeilToInt((float)num / m_Row);
            SetContentWidth(contentSize);
            SetContentHeight(m_ContentRectTrans.rect.height);
            m_ContentRectTrans.sizeDelta = new Vector2(m_ContentWidth, m_ContentHeight);
            if (num != m_MaxCount)
            {
                m_ContentRectTrans.anchoredPosition = new Vector2(0, m_ContentRectTrans.anchoredPosition.y);
            }
        }

        //-> 计算 开始索引
        int lastEndIndex = 0;


        //-> 过多的物体 扔到对象池 ( 首次调 ShowList函数时 则无效 )
        if (m_IsInited)
        {
            lastEndIndex = num - m_MaxCount > 0 ? m_MaxCount : num;
            lastEndIndex = m_IsClearList ? 0 : lastEndIndex;


            int count = m_IsClearList ? m_CellInfos.Length : m_MaxCount;
            for (int i = lastEndIndex; i < count; i++)
            {
                if (m_CellInfos[i].obj != null)
                {
                    SetPoolsObj(m_CellInfos[i].obj);
                    if (onItemHide != null)
                    {
                        int objNum = 0;
                        m_GameObjectNumDict.TryGetValue(m_CellInfos[i].obj, out objNum);
                        onItemHide.Invoke(m_CellInfos[i].obj, objNum);
                    }
                    m_CellInfos[i].obj = null;
                }
            }
        }


        //-> 以下四行代码 在for循环所用
        CellInfo[] tempCellInfos = m_CellInfos;
        m_CellInfos = new CellInfo[num];


        //-> 1: 计算 每个Cell坐标并存储 2: 显示范围内的 Cell
        for (int i = 0; i < num; i++)
        {
            // * -> 存储 已有的数据 ( 首次调 ShowList函数时 则无效 )
            if (m_MaxCount != -1 && i < lastEndIndex)
            {
                CellInfo tempCellInfo = tempCellInfos[i];
                //-> 计算是否超出范围
                float rPos = m_IsVertical ? tempCellInfo.pos.y : tempCellInfo.pos.x;
                if (!IsOutRange(rPos))
                {
                    //-> 记录显示范围中的 首位index 和 末尾index
                    m_MinIndex = m_MinIndex == -1 ? i : m_MinIndex; //首位index
                    m_MaxIndex = i; // 末尾index


                    if (tempCellInfo.obj == null)
                    {
                        tempCellInfo.obj = GetPoolsObj();
                    }
                    tempCellInfo.obj.transform.GetComponent<RectTransform>().anchoredPosition = tempCellInfo.pos;
                    if (!m_GameObjectNumDict.ContainsKey(tempCellInfo.obj))
                    {
                        m_GameObjectNumDict.Add(tempCellInfo.obj, i);
                    }
                    else
                    {
                        m_GameObjectNumDict[tempCellInfo.obj] = i;
                    }
                    tempCellInfo.obj.SetActive(true);


                    //-> 回调 Lua 函数
                    Func(tempCellInfo.obj);
                }
                else
                {
                    if (tempCellInfo.obj != null)
                    {
                        SetPoolsObj(tempCellInfo.obj);
                        if (onItemHide != null)
                        {
                            int objNum = 0;
                            m_GameObjectNumDict.TryGetValue(tempCellInfo.obj, out objNum);
                            onItemHide.Invoke(tempCellInfo.obj, objNum);
                        }
                        tempCellInfo.obj = null;
                    }
                }
                m_CellInfos[i] = tempCellInfo;
                continue;
            }


            CellInfo cellInfo = new CellInfo();


            float pos = 0;  //坐标( isVertical ? 记录Y : 记录X )
            float rowPos = 0; //计算每排里面的cell 坐标


            // * -> 计算每个Cell坐标
            if (m_IsVertical)
            {
                pos = m_CellObjectHeight * Mathf.FloorToInt(i / m_Row) + m_SpacingY * Mathf.FloorToInt(i / m_Row);
                rowPos = m_CellObjectWidth * (i % m_Row) + m_SpacingX * (i % m_Row);
                cellInfo.pos = new Vector3(rowPos + GetPaddingX(), -pos - GetPaddingY(), 0);
            }
            else
            {
                pos = m_CellObjectWidth * Mathf.FloorToInt(i / m_Row) + m_SpacingX * Mathf.FloorToInt(i / m_Row);
                rowPos = m_CellObjectHeight * (i % m_Row) + m_SpacingY * (i % m_Row);
                cellInfo.pos = new Vector3(pos + GetPaddingX(), -rowPos - GetPaddingY(), 0);
            }


            //-> 计算是否超出范围
            float cellPos = m_IsVertical ? cellInfo.pos.y : cellInfo.pos.x;
            if (IsOutRange(cellPos))
            {
                cellInfo.obj = null;
                m_CellInfos[i] = cellInfo;
                continue;
            }


            //-> 记录显示范围中的 首位index 和 末尾index
            m_MinIndex = m_MinIndex == -1 ? i : m_MinIndex; //首位index
            m_MaxIndex = i; // 末尾index


            //-> 取或创建 Cell
            GameObject cell = GetPoolsObj();
            cell.transform.GetComponent<RectTransform>().anchoredPosition = cellInfo.pos;
            if (!m_GameObjectNumDict.ContainsKey(cell.gameObject))
            {
                m_GameObjectNumDict.Add(cell.gameObject, i);
            }
            else
            {
                m_GameObjectNumDict[cell.gameObject] = i;
            }


            //-> 存数据
            cellInfo.obj = cell;
            m_CellInfos[i] = cellInfo;


            //-> 回调 Lua 函数
            Func(cell);
        }


        m_MaxCount = num;
        m_IsInited = true;


    }


    //实时刷新列表时用
    public virtual void UpdateList()
    {
        NormalPerformanceMode();
    }


    //刷新某一项
    public void UpdateCell(int index)
    {
        CellInfo cellInfo = m_CellInfos[index - 1];
        if (cellInfo.obj != null)
        {
            float rangePos = m_IsVertical ? cellInfo.pos.y : cellInfo.pos.x;
            if (!IsOutRange(rangePos))
            {
                Func(cellInfo.obj);
            }
        }
    }


    // 更新滚动区域的大小
    public void UpdateSize()
    {
        Rect rect = GetComponent<RectTransform>().rect;
        m_PlaneHeight = rect.height;
        m_PlaneWidth = rect.width;
    }


    //滑动事件
    protected virtual void ScrollRectListener(Vector2 value)
    {
        NormalPerformanceMode(); //普通性能模式
    }

    //普通性能模式
    private void NormalPerformanceMode()
    {
        if (m_CellInfos == null)
            return;

        //检查超出范围
        for (int i = 0, length = m_CellInfos.Length; i < length; i++)
        {
            CellInfo cellInfo = m_CellInfos[i];
            GameObject obj = cellInfo.obj;
            Vector3 pos = cellInfo.pos;


            float rangePos = m_IsVertical ? pos.y : pos.x;
            //判断是否超出显示范围
            if (IsOutRange(rangePos))
            {
                //把超出范围的cell 扔进 poolsObj里
                if (obj != null)
                {
                    SetPoolsObj(obj);
                    if (onItemHide != null)
                    {
                        int objNum = 0;
                        m_GameObjectNumDict.TryGetValue(obj, out objNum);
                        onItemHide.Invoke(obj, objNum);
                    }
                    m_CellInfos[i].obj = null;
                }
            }
            else
            {
                if (obj == null)
                {
                    //优先从 poolsObj中 取出 (poolsObj为空则返回 实例化的cell)
                    GameObject cell = GetPoolsObj();
                    cell.transform.localPosition = pos;
                    if (!m_GameObjectNumDict.ContainsKey(cell.gameObject))
                    {
                        m_GameObjectNumDict.Add(cell.gameObject, i);
                    }
                    else
                    {
                        m_GameObjectNumDict[cell.gameObject] = i;
                    }
                    m_CellInfos[i].obj = cell;


                    Func(cell);
                }
            }
        }
    }


    //判断是否超出显示范围
    protected bool IsOutRange(float pos)
    {
        Vector3 listP = m_ContentRectTrans.anchoredPosition;
        if (m_IsVertical)
        {
            if (pos + listP.y > m_CellObjectHeight || pos + listP.y < -rectTrans.rect.height)
            {
                return true;
            }
        }
        else
        {
            if (pos + listP.x < -m_CellObjectWidth || pos + listP.x > rectTrans.rect.width)
            {
                return true;
            }
        }
        return false;
    }


    //对象池 机制  (存入, 取出) cell
    protected Stack<GameObject> poolsObj = new Stack<GameObject>();
    //取出 cell
    protected virtual GameObject GetPoolsObj()
    {
        GameObject cell = null;
        if (poolsObj.Count > 0)
        {
            cell = poolsObj.Pop();
        }


        if (cell == null)
        {
            cell = Instantiate(m_CellGameObject) as GameObject;
        }
        cell.transform.SetParent(m_Content.transform);
        cell.transform.localScale = Vector3.one;
        SetActive(cell, true);


        return cell;
    }
    //存入 cell
    protected virtual void SetPoolsObj(GameObject cell)
    {
        if (cell != null)
        {
            poolsObj.Push(cell);
            SetActive(cell, false);
        }
    }


    //回调
    protected void Func(GameObject selectObject)
    {
        int num = 0;
        m_GameObjectNumDict.TryGetValue(selectObject, out num);
        onItemShow?.Invoke(selectObject, num);
    }

    void SetActive(GameObject cell, bool isShow)
    {
        cell.SetActive(isShow);
    }

    protected void OnDestroy()
    {
        DisposeAll();
    }
}

其他2个使用案例C#脚本代码:

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

public class LoopListManager : MonoBehaviour
{
    public BaseLoopList baseLoopList;
    private Dictionary<int, BaseLoopListItem> loopListItemDict;

    void Start()
    {
        baseLoopList.onItemShow += OnShow;
        baseLoopList.onItemHide += OnHide;
        loopListItemDict = new Dictionary<int, BaseLoopListItem>();
        baseLoopList.Init();
        //baseLoopList.SetPadding(20, 30, 0, 0);//支持Padding四个方向的偏移
        baseLoopList.SetCount(50);
    }

    private BaseLoopListItem GetItem(GameObject cell, int index)
    {
        BaseLoopListItem item;
        loopListItemDict.TryGetValue(index, out item);
        if (item == null)
        {
            item = cell.GetComponent<BaseLoopListItem>();
            loopListItemDict.Add(index, item);
        }
        return item;
    }

    public void OnShow(GameObject cell, int index)
    {
        Debug.Log("Show:" + index);
        BaseLoopListItem item = GetItem(cell, index);
        item.OnShow(index);
    }

    public void OnHide(GameObject cell, int index)
    {
        Debug.Log("Hide:" + index);
        BaseLoopListItem item = GetItem(cell, index);
        item.OnHide(index);

        //注意: 无限循环列表的Item是重复利用的物体,逻辑上Hide之后必须从缓存中移除,否则会一定会出现Item刷新异常;
        //原因: 若不移除会出现Show(index物体)时会拿到一个不正确位置的物体, 甚至很大可能是一个已显示中的物体(形成覆盖效果)
        loopListItemDict.Remove(index);
    }
}
using UnityEngine;
using TMPro;
public class BaseLoopListItem : MonoBehaviour
{
    public TextMeshProUGUI text;

    public void OnShow(int index)
    {
        text.text = index.ToString();
    }

    public void OnHide(int index)
    {
        text.text = "";
    }
}

注意事项:无限循环列表的Item物体是重复利用的,因此OnHide回调后必须将传递进来的物体所有相关的缓存引用清空,例如案例是将其从字典移除loopListItemDict.Remove(index);

Content选择左上角锚点(看情况可选其他,但不要用自适应stretch) 以及不要挂任何自动控制布局组件,如:VerticalLayoutGroup、HorizontalLayoutGroup、GridLayoutGroup、ContentSizeFitter等...(因为会破坏无限循环列表对Content的控制)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2260526.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Git-基础操作命令

目录 Git基础操作命令 case *查看提交日志 log 版本回退 get add . Git基础操作命令 我们创建并且初始化这个仓库以后&#xff0c;我们就要在里面进行操作。 Git 对于文件的增删改查存在几个状态&#xff0c;这些修改状态会随着我们执行Git的命令而发生变化。 untracked、…

Flutter Navigator2.0的原理和Web端实践

01 背景与动机 在Navigator 2.0推出之前&#xff0c;Flutter主要通过Navigator 1.0和其提供的 API&#xff08;如push(), pop(), pushNamed()等&#xff09;来管理页面路由。然而&#xff0c;Navigator 1.0存在一些局限性&#xff0c;如难以实现复杂的页面操作&#xff08;如移…

【容器】k8s学习笔记基础部分(三万字超详细)

概念 应用部署方式演变 在部署应用程序的方式上&#xff0c;主要经历了三个时代&#xff1a; 传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物理机上 优点&#xff1a;简单&#xff0c;不需要其它技术的参与 缺点&#xff1a;不能为应用程序定义资源使…

PostgreSQL 常用运维SQL整理

一、查询并杀会话 -- 查询会话 select pid,usename,client_addr,client_port,query_start,query,wait_event from pg_stat_activity; -- 杀会话 select pg_terminate_backend(pid号); -- 使用如下命令自动生成杀会话语句 select datid,datname,pid,usesysid,usename,applicat…

前端0基础用Cursor完成管理系统页面 - 1

Cursor下载 下载链接: https://www.cursor.com/ Hello World! 作为完全不会前端的人&#xff0c;首先需要让AI帮我们搭建一个HelloWorld界面 确定语言框架 首先要给AI框定好前端语言和框架&#xff0c;由于AI的物料大量来自网上的开源项目&#xff0c;所以越是受欢迎的开源…

系统组件优化的思考框架

我之前的文章里有分享过自己总结的做技术选型的思考框架&#xff0c;本文将会分享一下我总结的做系统组件调优/优化的思考框架。 组件优化的思考框架 常见的互联网架构基本离不开数据库、缓存、消息队列、搜索、数据处理等等各种组件&#xff0c;虽然组件的形态不一、功能不同…

Linux shell的七大功能 ---自动补齐、管道机制、别名

1、自动补齐---TAB 输入命令的前几个字符&#xff0c;按下tab键&#xff0c;会自动补齐完整的字符&#xff0c;若有多个命令、文件或目录的前几个字符相同&#xff0c;按下tab将会全部列举出来 2、管道机制---| 例如&#xff1a;ls -- help |more 将有关ls的帮助内容传递给“|…

计算机网络-基础概念(HTTP,TPC/IP, DNS,URL)

HTTP不同的版本 HTTP0.9于1990年问世&#xff0c;此时HTTP并没有作为正式的标准被建立。HTTP正式被公布是1996年的5月&#xff0c;版本命名为HTTP/1.0。HTTP1.1&#xff0c;1997年1月公布&#xff0c;目前仍然是主流版本的HTTP协议版本。 TCP/IP 通常使用的网络是在TCP/IP协…

12.3【JAVA-EXP4-DEBUGSTUDY】

java升级版本 JDK 1.8 是 Java Development Kit 的第 8 版本&#xff0c;发布于 2014 年 3 月 18 日。这个版本是 Java SE&#xff08;Standard Edition&#xff09;的一部分&#xff0c;包含了 Java 编程语言的实现、编译器、调试工具和其他相关组件 JDK 1.8: 这里的 1.8 表…

在Windows上运行mediapipe:适合新手的AI框架

一、mediapipe简介 mediapipe可以被视为谷歌版的onnx&#xff0c;其设计目的在于跨平台部署AI模型&#xff0c;并提供一系列工具来监测不同平台、不同设备运行人工智能模型时的性能表现。 尽管mediapipe已经陆续支持训练自定义模型&#xff0c;但博主更推荐使用Pytorch/Tenso…

自然语言处理:我的学习心得与笔记

Pytorch 1.Pytorch基本语法 1.1 认识Pytorch 1.2 Pytorch中的autograd 2.Pytorch初步应用 2.1 使用Pytorch构建一个神经网络 2.2 使用Pytorch构建一个分类器 小节总结 学习了什么是Pytorch. 。Pytorch是一个基于Numpy的科学计算包,作为Numpy的替代者,向用户提供使用GPU强大…

IAR环境下STM32静态库编译及使用

IAR环境下STM32静态库编译及使用 前言 最近了解到了STM32的静态库与动态库&#xff0c;在此记录一下STM32静态库的生成与使用。 静态库的作用主要是对代码进行封装及保护&#xff0c;使其他使用者只知其然而不知其所以然&#xff0c;因为封装后的静态库只有.h文件没有.c文件。…

【常考前端面试题总结】---2025

React fiber架构 1.为什么会出现 React fiber 架构? React 15 Stack Reconciler 是通过递归更新子组件 。由于递归执行&#xff0c;所以更新一旦开始&#xff0c;中途就无法中断。当层级很深时&#xff0c;递归更新时间超过了 16ms&#xff0c;用户交互就会卡顿。对于特别庞…

Leetcode 面试150题 399.除法求值

系列博客目录 文章目录 系列博客目录题目思路代码 题目 链接 思路 广度优先搜索 我们可以将整个问题建模成一张图&#xff1a;给定图中的一些点&#xff08;点即变量&#xff09;&#xff0c;以及某些边的权值&#xff08;权值即两个变量的比值&#xff09;&#xff0c;试…

hbase读写操作后hdfs内存占用太大的问题

hbase读写操作后hdfs内存占用太大的问题 查看内存信息hbase读写操作 查看内存信息 查看本地磁盘的内存信息 df -h查看hdfs上根目录下各个文件的内存大小 hdfs dfs -du -h /查看hdfs上/hbase目录下各个文件的内存大小 hdfs dfs -du -h /hbase查看hdfs上/hbase/oldWALs目录下…

使用webrtc-streamer查看实时监控

摄像头配置&#xff08;海康摄像头为例&#xff09; 摄像头视频编码应改成H264格式 webrtc-streamer下载 webrtc-streamer下载地址 下载后解压出来双击运行&#xff0c;端口默认8000 VUE2项目引入文件 在项目静态文件“public”中需引入两个js文件“webrtcstreamer.js”与“…

L1-3流量分析

1. 初步分析 数据包下载 流量分析基础篇 使用科来网络分析系统&#xff0c;打开L1-3.pcapng数据包&#xff0c;查看数据包中ssh的协议占的比例较大。 2. 通过分析数据包L1-3&#xff0c;找出黑客的IP地址&#xff0c;并将黑客的IP地址作为FLAG(形式:[IP地址)提交; 获取的fl…

【经典】制造供应链四类策略(MTS、MTO、ATO、ETO)细说

关注作者 制造供应链的牛鞭问题与复杂问题主要是从两个方面解决&#xff0c;一是同步化供应链消减从需求到供应的放大效应&#xff0c;二是供应链细分&#xff0c;针对不同的客户、不同的需求供应的匹配策略来应对复杂性&#xff0c;更好的满足客户并以最低的总成本来实现。 对…

前端成长之路:CSS盒子模型

盒子模型是页面布局的核心&#xff0c;通过盒子模型才能更好的进行页面布局。 网页布局的本质 网页布局的核心本质其实是&#xff1a;HTML网页元素就是一个个的盒子box&#xff0c;通过CSS可以设置好盒子的样式&#xff0c;和盒子需要摆放的位置&#xff1b;简单说来就是通过…

LeetCode刷题 -- 字符串

目录 最长公共前缀题目解析算法原理代码 最长回文子串题目解析算法原理代码 二进制求和题目解析算法原理代码 字符串相乘题目解析算法原理代码 最长公共前缀 题目链接 题目解析 只需找出字符串中的公共的最长字符串即可 算法原理 1.法一&#xff1a;两两字符串比较&#xff0c;…