Unity iPhoneX适配方案【NGUI&UGUI】

2023-11-01

本文作者旨在通过改锚点的方式,分别实现在NGUI和UGUI上的iPhone X适配技术方案,并结合自身项目经验,阐述了主要的实现细节,希望能对广大游戏开发团队有借鉴意义。

适配来源: 按照苹果官方人机界面指南 :Apple 开发者中心

在iPhone X 异形屏幕上,苹果提出了Safe Area安全区的概念,这个安全区域的意思是,UI在Safe Area能够保证显示不会被裁切掉。

在这里插入图片描述

按照苹果的设计规范,要求我们把UI控件放在Safe Area内,而且不能留黑边。在Unity中就需要解决,怎么以更少的工作量把所有界面的控件停靠在Safe Area内,黑边的部分用场景或者背景图填充。

当我们横持iPhoneX的时候:
iPhone X整体像素为2436 x 1125像素;
整体SafeArea区域为2172 x 1062像素;

左右插槽(齐刘海和圆角,再加一个边距)各132像素;

底部边距(由于iPhoneX没有Home键,会有一个虚拟的主屏幕的指示条)主屏幕的指示条占用63像素高度,顶部没有边界是0像素。

一、技术方案
1.改相机ViewPort
直接把UI相机的视口改为Rect(132/2436, 0, 2172/2436, 1062/1125),然后把背景图设为另外一个相机。这样做的好处是,完全不用改原来的Layout。坏处是,多个UI的情况下,背景图和主UI之间的深度关系要重新设置。

2.缩放
把主UI的Scale设为0.9,背景图的Scale设为1.1,这样就能不留黑边。这个方法的好处是简单,坏处是会引起一些Tween已及Active/InActive切换之间的问题。

3.改锚点
分2种情况,NGUI和UGUI都有点不同。正好我都有2个项目的完整适配经验,所以才写了这个分享。

二、实现细节
首先我们拿到iPhone X 安全区域,Unity得开发插件OC代码来获取。SafeArea.mm拷贝到项目的Plugins/iOS目录中。

CGRect CustomComputeSafeArea(UIView* view)
{
    CGSize screenSize = view.bounds.size;
    CGRect screenRect = CGRectMake(0, 0, screenSize.width, screenSize.height);
    
    UIEdgeInsets insets = UIEdgeInsetsMake(0, 0, 0, 0);
    if ([view respondsToSelector: @selector(safeAreaInsets)])
        insets = [view safeAreaInsets];
    
    screenRect.origin.x += insets.left;
    screenRect.size.width -= insets.left + insets.right;

    float scale = view.contentScaleFactor;
    screenRect.origin.x *= scale;
    screenRect.origin.y *= scale;
    screenRect.size.width *= scale;
    screenRect.size.height *= scale;
    return screenRect;
}

//外部调用接口
extern "C" void GetSafeArea(float* x, float* y, float* w, float* h)
{
    UIView* view = GetAppController().unityView;
    CGRect area = CustomComputeSafeArea(view);
    *x = area.origin.x;
    *y = area.origin.y;
    *w = area.size.width;
    *h = area.size.height;
}

设计通用的适配component,哪些面板要适配,就直接添加这个脚本。

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


/// <summary>
/// 设计安全区域面板(适配iPhone X)
/// Jeff 2017-12-1
/// 文件名 SafeAreaPanel.cs
/// </summary>
public class SafeAreaPanel : MonoBehaviour
{

    private RectTransform target;

#if UNITY_EDITOR
    [SerializeField]
    private bool Simulate_X = false;
#endif


    void Awake()
    {
        target = GetComponent<RectTransform>();
        ApplySafeArea();
    }

    void ApplySafeArea()
    {
        var area = SafeAreaUtils.Get();

#if UNITY_EDITOR

        /*
        iPhone X 横持手机方向:
        iPhone X 分辨率
        2436 x 1125 px

        safe area
        2172 x 1062 px

        左右边距分别
        132px

        底边距 (有Home条)
        63px

        顶边距
        0px
        */

        float Xwidth = 2436f;
        float Xheight = 1125f;
        float Margin = 132f;
        float InsetsBottom = 63f;

        if ((Screen.width == (int)Xwidth && Screen.height == (int)Xheight) 
        || (Screen.width == 812 && Screen.height == 375))
        {
            Simulate_X = true;
        }

        if (Simulate_X)
        {
            var insets = area.width * Margin / Xwidth;
            var positionOffset = new Vector2(insets, 0);
            var sizeOffset = new Vector2(insets * 2, 0);
            area.position = area.position + positionOffset;
            area.size = area.size - sizeOffset;
        }
#endif

        var anchorMin = area.position;
        var anchorMax = area.position + area.size;
        anchorMin.x /= Screen.width;
        anchorMin.y /= Screen.height;
        anchorMax.x /= Screen.width;
        anchorMax.y /= Screen.height;
        target.anchorMin = anchorMin;
        target.anchorMax = anchorMax;
    }
}
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;

/// <summary>
/// iPhone X适配工具类
/// Jeff 2017-12-1
/// 文件名 SafeAreaUtils.cs
/// </summary>
public class SafeAreaUtils
{
#if UNITY_IOS
    [DllImport("__Internal")]
    private static extern void GetSafeArea(out float x, out float y, out float w, out float h);
#endif


    /// <summary>
    /// 获取iPhone X 等苹果未来的异性屏幕的安全区域Safe are
    /// </summary>
    /// <param name="showInsetsBottom"></param>
    /// <returns></returns>
    public static Rect Get()
    {
        float x, y, w, h;
#if UNITY_IOS && !UNITY_EDITOR
            GetSafeArea(out x, out y, out w, out h);
#else
        x = 0;
        y = 0;
        w = Screen.width;
        h = Screen.height;
#endif
        return new Rect(x, y, w, h);
    }
}

.

比如这样,给Panel加了Safe Area Panel这个组件,勾选Simulate_X模拟iPhone X运行。在这里插入图片描述运行时图(红色区域是UI主面板正常是全屏的,这里根据Safe Area,自动适配后调整锚点展示的左右边距下边距,最底层蓝色区域是场景或者UI背景图区域)。

添加一个812x375就可以模拟iPhoneX的效果
在这里插入图片描述
如果是旧项目是使用NGUI来开发的,原理一样,也得用到以上Safa Area.mm来获取安全区域,不同处在于修改NGUI的源码,而NGUI版本有好多。不要忘记把SafeArea.mm拷贝到项目的Plugins/iOS目录中。我提供思路和核心代码,需要你结合自己使用的NGUI来修改。

NGUI中UI Sprite、UILabel、UIPanel等等都是继承抽象类UIRect。在这里插入图片描述
UIRect UI矩形包含4个锚点(每边一个),我们就是要控制锚点在安全区域显示。

在NGUITools.CS中增加代码:

#if UNITY_IOS && !UNITY_EDITOR
    [DllImport("__Internal")]
    private static extern void GetSafeArea(out float x, out float y, out float w, out float h);
#endif

    public static Rect SafeArea
    {
        get
        {
            return GetSafeArea();
        }
    }

    /// <summary>
    /// 获取iPhone X 等苹果未来的异型屏幕的安全区域SafeArea
    /// </summary>
    /// <returns>Rect</returns>
    public static Rect GetSafeArea()
    {
        float x, y, w, h;
#if UNITY_IOS && !UNITY_EDITOR
        GetSafeArea(out x, out y, out w, out h);
#else
        x = 0;
        y = 0;
        w = Screen.width;
        h = Screen.height;
#endif
        return new Rect(x, y, w, h);
    }

#if UNITY_EDITOR
    static int mSizeFrame = -1;
    static System.Reflection.MethodInfo s_GetSizeOfMainGameView;
    static Vector2 mGameSize = Vector2.one;

    /// <summary>
    /// Size of the game view cannot be retrieved from Screen.width and Screen.height when the game view is hidden.
    /// </summary>

    static public Vector2 screenSize
    {
        get
        {
            int frame = Time.frameCount;

            if (mSizeFrame != frame || !Application.isPlaying)
            {
                mSizeFrame = frame;

                if (s_GetSizeOfMainGameView == null)
                {
                    System.Type type = System.Type.GetType("UnityEditor.GameView,UnityEditor");
                    s_GetSizeOfMainGameView = type.GetMethod("GetSizeOfMainGameView",
                        System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
                }
                mGameSize = (Vector2)s_GetSizeOfMainGameView.Invoke(null, null);
            }
            return mGameSize;
        }
    }
#else
    /// <summary>
    /// Size of the game view cannot be retrieved from Screen.width and Screen.height when the game view is hidden.
    /// </summary>

    static public Vector2 screenSize { get { return new Vector2(Screen.width, Screen.height); } }
#endif



    
    public static bool Simulate_X
    {
        get
        {
#if UNITY_EDITOR
            return (Screen.width == 812 && Screen.height == 375);
#else
            return false;
#endif
        }
    }

    /// <summary>
    /// 模拟iPhone X比例
    /// </summary>
    public static float Simulate_iPhoneXScale
    {
        get
        {
            if (!Simulate_X) return 1f;

            /*
            iPhone X 横持手机方向分辨率:2436 x 1125 px
            SafeArea:2172 x 1062 px
            左右边距分别:132px
            底边距(有Home条):63px
            顶边距:0px
            */
            float xwidth = 2436f;
            float xheight = 1125f;
            float margin = 132f;

            return (xwidth - margin * 2) / xwidth;
        }
    }

锚点的适配最终都会调用NGUITools.GetSides这个方法,这个方法实际上是NGUI为Camera写的扩展方法。

找到NGUITools.cs的static public Vector3[] GetSides(this Camera cam,float depth,Transform relativeTo)。我们追加一个bool showInSafeArea, 默认false。

static public Vector3[] GetSides(this Camera cam, float depth, Transform relativeTo, bool showInSafeArea = false)
    {
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7
        if (cam.isOrthoGraphic)
#else
        if (cam.orthographic)
#endif
        {
            float xOffset = 1f;
#if UNITY_IOS
            if (showInSafeArea)  
            {  
                xOffset = SafeArea.width / Screen.width;
            }  
#elif UNITY_EDITOR 
            if (showInSafeArea)
            {
                xOffset = Simulate_iPhoneXScale;
            }
#endif

            float os = cam.orthographicSize;
            float x0 = -os * xOffset;
            float x1 = os * xOffset;
            float y0 = -os;
            float y1 = os;

            Rect rect = cam.rect;
            Vector2 size = screenSize;

            float aspect = size.x / size.y;
            aspect *= rect.width / rect.height;
            x0 *= aspect;
            x1 *= aspect;

            // We want to ignore the scale, as scale doesn't affect the camera's view region in Unity
            Transform t = cam.transform;
            Quaternion rot = t.rotation;
            Vector3 pos = t.position;

            int w = Mathf.RoundToInt(size.x);
            int h = Mathf.RoundToInt(size.y);

            if ((w & 1) == 1) pos.x -= 1f / size.x;
            if ((h & 1) == 1) pos.y += 1f / size.y;

            mSides[0] = rot * (new Vector3(x0, 0f, depth)) + pos;
            mSides[1] = rot * (new Vector3(0f, y1, depth)) + pos;
            mSides[2] = rot * (new Vector3(x1, 0f, depth)) + pos;
            mSides[3] = rot * (new Vector3(0f, y0, depth)) + pos;
        }
        else
        {
            mSides[0] = cam.ViewportToWorldPoint(new Vector3(0f, 0.5f, depth));
            mSides[1] = cam.ViewportToWorldPoint(new Vector3(0.5f, 1f, depth));
            mSides[2] = cam.ViewportToWorldPoint(new Vector3(1f, 0.5f, depth));
            mSides[3] = cam.ViewportToWorldPoint(new Vector3(0.5f, 0f, depth));
        }

        if (relativeTo != null)
        {
            for (int i = 0; i < 4; ++i)
                mSides[i] = relativeTo.InverseTransformPoint(mSides[i]);
        }
        return mSides;
    }

还需要改动UIRect和UIRectEditor的相关方法:
1.在UIRect.cs中添加

[HideInInspector][SerializeField]public bool mShowInSafeArea = false;

2.修改GetSides的调用

/// <summary>
 /// Convenience function that returns the sides the anchored point is anchored to.
 /// </summary>
public Vector3[] GetSides (Transform relativeTo)
{
    if (target != null)
    {
        if (rect != null) return rect.GetSides(relativeTo);
        if (target.camera != null) return target.camera.GetSides(relativeTo, rect.mShowInSafeArea);//这里增加了是否在安全区域的参数
    }
    return null;
}
 /// <summary>
    /// Get the sides of the rectangle relative to the specified transform.
    /// The order is left, top, right, bottom.
    /// </summary>

    public virtual Vector3[] GetSides (Transform relativeTo)
    {
        if (anchorCamera != null)
        {
            return anchorCamera.GetSides(relativeTo, mShowInSafeArea);//这里增加了是否在安全区域的参数
        }
        else
        {
            Vector3 pos = cachedTransform.position;
            for (int i = 0; i < 4; ++i)
                mSides[i] = pos;

            if (relativeTo != null)
            {
                for (int i = 0; i < 4; ++i)
                    mSides[i] = relativeTo.InverseTransformPoint(mSides[i]);
            }
            return mSides;
        }
    }

3.UIRectEditor.CS扩展下

 /// <summary>
/// Draw the "Anchors" property block.
/// </summary>protected virtual void DrawFinalProperties ()
{
    if (!((target as UIRect).canBeAnchored))
    {
        if (NGUIEditorTools.DrawHeader("iPhone X"))
        {
            NGUIEditorTools.BeginContents();
            {
                GUILayout.BeginHorizontal();
                NGUIEditorTools.SetLabelWidth(100f);
                NGUIEditorTools.DrawProperty("ShowInSafeArea", serializedObject, "mShowInSafeArea", GUILayout.Width(120f));
                GUILayout.Label("控制子节点的锚点在安全区域内显示");
                GUILayout.EndHorizontal();

            }
            NGUIEditorTools.EndContents();
        }
    }
    

    //......原来的逻辑....
}

补充:实际项目中,部分节点是UIAnchor来设置,所以这个脚本也要适配找到UIAnchor的UpDate。
4.GetSides的调用加上mShowInSafeArea。

 if (pc.clipping == UIDrawCall.Clipping.None)
{
    // Panel has no clipping -- just use the screen's dimensions
    float ratio = (mRoot != null) ? (float)mRoot.activeHeight / Screen.height * 0.5f : 0.5f;
    mRect.xMin = -Screen.width * ratio;
    mRect.yMin = -Screen.height * ratio;
    mRect.xMax = -mRect.xMin;
    mRect.yMax = -mRect.yMin;
}

5.这里都是直接使用Screen.width和Height,要改成安全区域Safe Area.width和Safe Area.height。

if (pc.clipping == UIDrawCall.Clipping.None)
{
    // Panel has no clipping -- just use the screen's dimensions
    float ratio = (mRoot != null) ? (float)mRoot.activeHeight / NGUITools.SafeArea.height * 0.5f : 0.5f;
    mRect.xMin = -NGUITools.SafeArea.width * ratio * NGUITools.Simulate_iPhoneXScale;
    mRect.yMin = -NGUITools.SafeArea.height * ratio;
    mRect.xMax = -mRect.xMin;
    mRect.yMax = -mRect.yMin;
}

这样NGUI也就可以了。
在这里插入图片描述在这里插入图片描述
以上就是Unity3D适配iPhone X技术方案,希望大家能有收获。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unity iPhoneX适配方案【NGUI&UGUI】 的相关文章

  • 浅谈C++的sort函数用法

    目录 sort简介 一 默认排序 二 参数排序 三 自定义排序规则 四 排序字符数组 sort简介 头文件为algorithm 其排序方式类似于快速排序 比冒泡选择之类的小杂鱼高级 函数调用形式为 sort 参数a 参数b 参数c 参数a是
  • 华为OD机试真题-二元组个数【2023.Q1】

    题目描述 给定两个数组a b 若a i b j 则称 i j 为一个二元组 求在给定的两个数组中 二元组的个数 输入描述 第一行输入 m 第二行输入m个数 表示第一个数组 第三行输入 n 第四行输入n个数 表示第二个数组 输出描述 二元组个
  • Python利用情感词典做情感分析

    情感分析是大数据时代常见的一种分析方法 多用于对产品评论的情感挖掘 以探究顾客的满意度程度 在做情感分析时 有两种途径 一种是基于情感词典的分析方法 一种是基于机器学习的方法 两者各有利弊 在此 笔者主要想跟大家分享基于python平台利用
  • 区块链发展面临三大挑战

    区块链技术最近几年在世界范围一直是个热门话题 这种 热 源自于区块链的确是有很多优势的技术 它呈现出美好的前景 但同时也因为区块链发展会带来非常大的挑战 而且这种挑战可以说是历史性的 那么区块链会带来哪些挑战呢 我觉得主要有以下三个方面 第
  • 基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(十六)实例化

    Vries的原教程地址如下 https learnopengl cn github io 04 20Advanced 20OpenGL 10 20Instancing 关于实例化的详细设置介绍与设置与参数设置请查看这个教程 本篇旨在对Vir
  • C++的嵌套依赖别名(typename的用法)

    看了很多遍 还是记录一下 1 在模板声明时typename和class是等价的 template
  • PyTorch训练时准确率不变

    今天复现了文章中的一个模型 刚开始学习率lr 0 01 准确率总是为20 分类目标有5个类 基本不变 刚开始我以为给模型的数据传错了 或者模型的处理有那个步骤有问题 最终多次尝试后 发现把学习率降低 结果就有效了 如我把学习率降低为lr 0
  • 我所钟爱的电影之二-公路片

    我爱公路片 人生只不过一次流浪 命运之途中 沿途风景或许都会遗忘 咫尺和遥远或许就在一瞬间 逝去的我们会怀念 一辈子就是活着的每一天 也许我不能环游世界 但幸好这个世界上有电影可以带我去 不管出走的初衷为何 在途中我们都会遇见爱 只因我们在
  • Selenium六 find_element_by_xpath()的几种方法

    Xpath XML Path Language 是W3C定义的用来在XML文档中选择节点的语言 一 从根目录 开始 有点像Linux的文件查看 代表根目录 一级一级的查找 直接子节点 相当于css selector中的 gt 号 html
  • SpringCloudAlibaba - Seata (2) AT 模式源码分析

    seata AT 模式的业务零侵入性 依靠的就是自动装配 starter 包 1 如何开启的全局事务 实现核心为 SeataAutoConfiguration 注入的 GlobalTransactionScanner Conditional
  • Qt 开发应用--颜色选择器ColorCopy

    Qt 开发应用 颜色选择器ColorCopy Qt颜色选择器 提供10大类100种颜色可选 点击即为复制 随处 Ctrl V 粘贴使用 提供有 Red Pink Purple Indigo Blue Green Yellow Orange
  • 进程和线程以及协程

    1 基本概念 进程和线程 进程 是系统资源分配的基本单位 实现了操作系统的并发 线程 是CPU调度的基本单位 实现了进程内的并发执行 并发是把任务在不同的时间点交给处理器进行处理 在同一时间点 任务并不会同时运行 并行是把每一个任务分配给每
  • 个人经济学管理tips

    摘录一些观点 作为茶余饭后的谈资 不清楚自己的热爱和目标时 每天把头脑最清醒的1小时留给自己 学习 思考 3个小时陪伴家人 剩下的时间 谁给钱多就给谁干 一居室好过养老年金险 房产保值升值 租金跑得赢通胀 一套刚需 一套改善 一套投资 三套
  • Win10系统下编译FFmpeg

    1 使用git下载源码 git clone git source ffmpeg org ffmpeg git ffmpeg 2 FFmpeg在windows平台编译需要使用MinGW w64来编译 单独使用MinGW w64比较麻烦 推荐使
  • pip镜像安装 python 安装库

    pip install openpyxl i https mirrors aliyun com pypi simple pip 本身更新 pip install upgrade pip vvv 上面是阿里云的 我用了特别快 语法 安装pip
  • 专利情况的基本了解

    专利 目标专利的拆解 提前关键词 构建检索式 适当的进行补充检 拆解已有技术的技术特征 申请书 说明书 权利要求 摘要 附图 优先权请求 发明 实用新型和外观设计 发明专利 实用新型专利和外观设计专利 发明专利 针对产品 方法或者产品 方法
  • c语言中两个有序数组合并,C语言算法:有序数组合并-2020-08-21

    方法 就是同时遍历两个数组 通过比大小 组成一个新数组 数组参数最好带上一个长度参数 防止越界 代码 合并数组 其中a b都是从小到大有序排列的数组 void mergeList int a int aLen int b int bLen
  • 高德地图api 地理编码(地址-->坐标)geocoder.getLocation在官方可以测试出结果,下载代码到本地却用不了 问题解决

    问题 高德地图api 地理编码 地址 gt 坐标 功能 通过输入 地址信息 得到 经纬度信息 geocoder getLocation在官方可以测试出结果 下载代码到本地却用不了 官方示例测试 可以从地址得到坐标 下载官方代码本地运行却出不
  • 最全的雅思8000词汇pdf_雅思听力场景分类词汇汇总,听力提分先搞定它!

    很多烤鸭来和哥聊天 聊听力的时候 大部分都会出现以下对话内容 为了让大家更加身临其境 我就做的趣味性点了哈 一 定 要 看 完 对 大家都是拿完资料就溜 一有问题就找哥谈心 不夸哥就算了 还不拿赞出来给哥 哼 抱住坚强的自己 擦干眼泪给你们

随机推荐

  • 2023 K8s 认证工程师 CKA 考题分析和题库练习(下)

    目录 10 考核知识 检查可用节点数量 题目内容 题目内容中文解释 做题解答 11 考核知识 一个 Pod 封装多个容器 题目内容 题目内容中文解释 官方文档搜索关键字 pod 编辑做题解答 12 考核知识 持久卷 PersistentVo
  • python列表+元组+字典+集合

    声明 本人的所有博客皆为个人笔记 作为个人知识索引使用 因此在叙述上存在逻辑不通顺 跨度大等问题 希望理解 分享出来仅供大家学习翻阅 若有错误希望指出 感谢 Python列表 序列中的每个元素都分配一个数字 它的位置 或索引 第一个索引是0
  • java设置多个数据源

    1 设置config properties文件 设置两个数据库连接 2 设置spring context xml文件 定义名为testDataSource和dataSource两个连接
  • LeetCode刷题顺序(新手入门)

    本刷题策略为leetcode官方的新手村策略 跟着主页官方的新手村策略刷题 按照每天刷三简单题或两中等题或一难题的速度刷题 每天预计花费1 5h 下面的顺序是探索卡中的顺序 数组 分为三部分 1 做好初始定义 2 运用基础算法思想 3 双索
  • 蛋白质组学数据的归一化/标准化处理

    1 前言 目的 调整由于技术 如处理 上样 预分 仪器等造成的样本间误差 这实际上是一种数据缩放的方法 一般在一个表达矩阵中 会涉及到多个样本 其表达量差异比较大 不能直接进行比较 比如某个样本表达量很大 在总体中就会占据绝对领导地位 这样
  • 邮件钓鱼的防守策略

    一 攻击背景 在历年的实战攻防演练中 人的漏洞是网络安全最大的脆弱点 而钓鱼攻击就是从内部攻破堡垒至关重要的手段 攻击者通过伪装成可信来源发送虚假邮件 诱导接收者点击恶意链接 提供敏感信息或执行恶意附件 从而获取机密信息或入侵系统 因此 在
  • MATLAB 之 基本概述

    文章目录 一 MATLAB 主要功能 1 数值计算功能 2 符号计算功能 3 绘图功能 4 程序设计语言功能 5 工具箱的扩展功能 二 MATLAB 操作界面 1 主窗口 2 命令行窗口 3 当前文件夹窗口 4 工作区窗口 5 搜索路径 三
  • [leetcode 周赛 149] 1154 一年中的第几天

    目录 1154 Day of the Year 一年中的第几天 描述 思路 代码实现 1154 Day of the Year 一年中的第几天 描述 给你一个按 YYYY MM DD 格式表示日期的字符串 date 请你计算并返回该日期是当
  • 【error】Lock wait timeout exceeded; try restarting transaction(mysql)事务锁

    目录 1 报错信息 2 解决方案 2 1 方案一 2 2 方案二 2 3 方案三 3 补充说明 3 1 三张表字段说明 原文链接 1 报错信息 背景 在做更新操作时 电脑重启了 重新运行mysql语句时报以下错误 报错信息 Lock wai
  • SQL中分组的一些用法group_concat

    分组查询 后面一篇文章我们将介绍MySQL的聚合函数 https blog csdn net qq 41453285 article details 88318318 group by通常与聚合函数放在一起使用 分组查询允许把数据分为多个逻
  • 高性能Mysql——分区表详解

    文章目录 分表和分区 分表和分区的区别 分表和分区联系呢 分区表分区方式 分区管理 分区表注意事项 分表和分区 分表 MySQL 的分表是真正的分表 一张表分成很多表后 每一个小表都是完整的一张表 都对应三个文件 一个 MYD数据文件 MY
  • html做群聊通讯方法,websocket学习和群聊实现

    WebSocket协议可以实现前后端全双工通信 从而取代浪费资源的长轮询 在此协议的基础上 可以实现前后端数据 多端数据 真正的实时响应 在学习WebSocket的过程中 实现了一个简化版群聊 过程和代码详细记录在这篇文章中 1 概述 1
  • 【转】JWT 登录认证及 token 自动续期方案解读

    转自 https mp weixin qq com s X6Xsxgbfvbf3JCa0i7q4 A 要实现认证功能 很容易就会想到 JWT 或者 Session 但是两者有啥区别 各自有什么优缺点 应该选择谁 JWT 和 Session
  • Java线程随笔

    目录 守护线程 线程可见性 线程时序性 线程的中断机制 守护线程 基本概念 守护线程可以简单理解为后台运行线程 守护线程不需要关心他的结束问题 java垃圾回收就是一个守护线程 例如你的应用程序运行时需要播放音乐 如果将播放音乐这个线程设置
  • iOS下XMPP开发之xmppFramework框架的导入步骤和介绍

    一个将要开发xmpp的项目 建议在项目刚创建就导入框架 这样可以避免一些自己操作失误造成不必要的损失 xmpp中最常用的框架就是 xmppFrameWork 第一种方法直接拖 1 gt 拖入文件夹 在网盘链接的xmppFramework文件
  • 【python手写算法】numpy实现简易神经网络和反向传播算法【1】

    import numpy as np def dense A W Z np matmul A W 矩阵乘法 return 1 1 np exp Z if name main leanring rate 100 A np array 200
  • 你真的懂JavaScript吗

    放在前面 本文原文的标题是 So you think you know JavaScript 在下感觉有些标题党了 不过看了下文章的链接还是很不错的 原文作者是由几个问题展开了说明 问题 1 浏览器的console里会打印出什么 var a
  • 黑客是如何获取足够的流量以支撑其发动DDOS攻击?

    对计算有一些了解的朋友可能都会知道DDoS是一种互联网最普及的攻击方式 也是一些黑客的初级入门的技巧 每一次进行大规模的DDoS的攻击 那打出来的流量都让人咂舌 动静大而且波及极为广阔 DDoS要的就是流量 大多数黑客基本上为获取流量而不择
  • 数字电路设计之verilog的门级描述

    使用verilog的数字电路设计 一般会有晶体管级的描述 门级描述 RTL 行为描述 我们接触得比较多的就是后面两种 前两种更少涉及 现在就说一下门级描述吧 门级描述就是使用各种逻辑门对组合逻辑进行描述 举个栗子 与或非门 这里的and o
  • Unity iPhoneX适配方案【NGUI&UGUI】

    本文作者旨在通过改锚点的方式 分别实现在NGUI和UGUI上的iPhone X适配技术方案 并结合自身项目经验 阐述了主要的实现细节 希望能对广大游戏开发团队有借鉴意义 适配来源 按照苹果官方人机界面指南 Apple 开发者中心 在iPho