[MAUI]在.NET MAUI中复刻苹果Cover Flow

news2024/10/6 2:32:13

文章目录

    • 原理
      • 3D旋转
      • 平行变换
    • 创建3D变换控件
      • 绘制封面图片
      • 应用3D旋转
      • 应用平行变换
      • 绘制倒影
      • 创建绑定属性
    • 创建绑定数据
    • 创建布局
      • 计算位置
      • 计算3D旋转
    • 创建动效
    • 项目地址

Cover Flow是iTunes和Finder中的一个视图选项,允许用户使用水平滚动的图像查看他们的音乐库或文件。

2007年9月5日iPod classic/nano3/touch在同一场发布会上发布,苹果首次向我们展示了Cover Flow

在这里插入图片描述

在iOS7之前的“音乐”App中,旋转设备90度,或在iTunes中的“查看”下,选择“Cover Flow”都可以进入到Cover Flow视图。

Cover Flow的交互设计非常优秀:通过指尖滑动从堆叠的专辑库中翻动和挑选一张专辑的交互方式不仅有趣,而且在有限的屏幕空间内,展现了更多的专辑封面。

但由于流媒体时代弱化了专辑的概念,拟物化设计退潮以及设备性能/续航等方面的考虑,苹果逐步放弃了Cover Flow。

在2012年新发布的iTunes 11,2013年新发布的iOS 7,以及2018年发布的MacOS Mojave中删除了Cover Flow界面,Gallery View取而代之

那个是乔布斯时代的苹果——使事情变得简单和有趣。最近我很怀念这个功能,但由于我手头上已经没有任何一台设备能访问这个功能了。于是在
.NET MAUI 中复刻了Cover Flow。

在这里插入图片描述

在这里插入图片描述

使用.NET MAUI实现跨平台支持,本项目可运行于Android、iOS平台。

原理

实际上,Cover flow的原理非常简单,核心算法是对专辑图片进行3D变换(3DTransform)。

.NET MAUI 并没有直接提供3D变换,但我们可以通过SkiaSharp来实现。

PS: Skia 本身是一个开源图形库,它提供适用于各种语言和硬件平台的通用 API,(如 C++/Qt、Chrome、Android、iOS等 ),根据本博文提到的算法,你可以用Skia尝试在你擅长的平台上实现相同的效果。

3D旋转

视图元素的3D变换(3DTransform)中,有一类是以视图元素的Y或X轴作为旋转中心做旋转,称之为3D旋转,除了专业的程序设计领域外,经常使用图形处理工具,甚至是ppt的同学可能都熟悉这个概念。在ppt中插入图形,设置形状格式,可以看到“三维旋转”的选项,如下图:

在这里插入图片描述

这里涉及到一个透视的概念,透视是指在视觉上,远处的物体比近处的物体小,来思考一下,在现实世界中要看到同样大小的物体,可以离得很近,视野变大,物体的畸变会变大。也可以离得很远,用一个望远镜去看,视野变小,物体的畸变也会变小。透视参数就是在屏幕中模拟了现实世界中近大远小透视效果,我简单用ptt做一个演示:

在这里插入图片描述

三个图形沿Y轴方向旋转, 从左到右透视距离依次减小,透视角度依次增大,换句话说是离得更近,视野变大,物体的畸变变大。

在大多数支持3D旋转的图形系统中都会包含透视这个参数变量,如css中的perspective亦或是ppt中的“透视”格式。

在Skia中,3D变换是通过矩阵乘法实现的,这里需要大致了解数字图像处理的基本知识,可以参考这里。

矩阵乘法就是把原始图像矩阵的横排和变换矩阵的竖排相应位相乘,将结果相加。

在二维空间,原始图像中的每个像素点 (x,y) 所代表的单列矩阵,通过变换矩阵相乘,得到新的像素点 (x’,y’)。
例如缩小图像:

在这里插入图片描述

因为要考虑平移等非线性计算,常用3*3的矩阵来表示变换
在三维空间,用一个4*4的矩阵来表示变换,例如围绕Y轴旋转的变换矩阵如下:

|  cos(α)  0  –sin(α)  0  |
|    0     1     0     0  |
|  sin(α)  0   cos(α)  0  |
|    0     0     0     1  |

平行变换

另外涉及到的图像处理是平行变换(Skew),每一个平台上的值可能不同,但是原理都是通过增加或减少X轴或Y轴的值来实现平行变换。

在这里插入图片描述

在Skia中,根据参数值转换 x’ 后的值随着 y 增加而增加。 这就是导致倾斜的原因。

如有一个200*100的图形,其左上角位于 (0、0) 的点上,并且呈现 xSkew 值为 1.5,则以下并行影像结果如下:

在这里插入图片描述

底部边缘 y 的坐标值为 100,因此将 150 像素移向右侧。

接下来我们用代码实现3D变换

创建3D变换控件

我们还是以分治的思路实现,图片变换由控件内部实现,平移及动画由控件外部实现。

新建.NET MAUI项目,命名Coverflow。将界面图片资源文件拷贝到项目\Resources\Raw中并将他们包含在MauiImage资源清单中。

<ItemGroup>
	  <MauiImage Include="Resources\Raw\*.jpg" />
</ItemGroup>

在项目中添加SkiaSharp绘制功能的引用Microsoft.Maui.Graphics.Skia以及SkiaSharp.Views.Maui.Controls

<ItemGroup>
    <PackageReference Include="Microsoft.Maui.Graphics.Skia" Version="7.0.59" />
    <PackageReference Include="SkiaSharp.Views.Maui.Controls" Version="2.88.3" />
</ItemGroup>

创建3D变换的图片控件RotationImage.xaml,代码如下:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:forms="clr-namespace:SkiaSharp.Views.Maui.Controls;assembly=SkiaSharp.Views.Maui.Controls"
             x:Class="Coverflow.RotationImage">

        <forms:SKCanvasView x:Name="canvasView"
                           Grid.Row="8"
                           PaintSurface="OnCanvasViewPaintSurface" />

</ContentView>

绘制封面图片

在RotationImage.xaml.cs中添加代码:

SKBitmap对象

public SKBitmap bitmap { get; private set; }

初始化方法,以及在图形大小变化时应用初始化

private async void RotationImage_SizeChanged(object sender, EventArgs e)
{
    await InitBitmap();
}

private async Task InitBitmap()
{
    using (Stream stream = await FileSystem.OpenAppPackageFileAsync("./15.jpg"))
    {
        if (stream!=null)
        {
            var mainDisplayInfo = DeviceDisplay.Current.MainDisplayInfo;
            var pixcelHeight = mainDisplayInfo.Density*200;
            var pixcelWidth = mainDisplayInfo.Density*200;

            var bitmap = SKBitmap.Decode(stream);
            bitmap= bitmap.Resize(new SKImageInfo((int)pixcelHeight,
                (int)pixcelWidth),
                SKFilterQuality.Medium);
            this.bitmap=bitmap;
        }

    }
}

初始化时将读取图片资源文件,然后将图片缩放到200*200的大小。

注意此处使用mainDisplayInfo.Density将MAUI各平台的逻辑分辨率转为图片的真实分辨率

此时在画布中绘制了一个简单的200*200专辑封面图片

在这里插入图片描述

应用3D旋转

在Skia用SKMatrix44类来描述4*4的变换矩阵,同时提供了 CreateRotation 和 CreateRotationDegrees 方法,可用于指定旋转围绕的轴

RotationImage_SizeChanged中,添加代码如下:


SKMatrix matrix = SKMatrix.CreateTranslation(-xCenter, -yCenter);

SKMatrix44 matrix44 = SKMatrix44.CreateIdentity();
matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(1, 0, 0, (float)0));
matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 1, 0, (float)25));
matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 0, 1, (float)0));

SKMatrix44 perspectiveMatrix = SKMatrix44.CreateIdentity();
perspectiveMatrix[3, 2] = -1 / 800;
matrix44.PostConcat(perspectiveMatrix);

matrix= matrix.PostConcat(matrix44.Matrix);

matrix= matrix.PostConcat(
    SKMatrix.CreateTranslation(xCenter, yCenter));

将变换矩阵应用到画布中

canvas.SetMatrix(matrix);

此时在画布中专辑封面图片以800的透视距离,绕Y轴旋转25度

应用平行变换

首先计算倾斜角度,如有一个200*100的图形,其左上角位于 (0、0) 的点上,图中的角度α:

在这里插入图片描述

150 像素到 100 像素垂直方向的比率是该角度的正切值,即 56.3 度。

RotationImage_SizeChanged中,对matrix对象应用平行变换

matrix.SkewY =  (float)Math.Tan(Math.PI * (float)15 / 180);

此时在画布中专辑封面图片以15度平行变换

在这里插入图片描述

绘制倒影

在cover flow中,封面图片包含倒影效果。

之前的绘制的封面图片,在控件中央(也是画布中央)的位置。为了放置倒影后仍然处于控件中心,画布应该一分为二:上半部分绘制封面图片,下半部分绘制倒影。

更改代码:

//float yBitmap = yCenter - bitmap.Height / 2;
float yBitmap = yCenter-bitmap.Height;

绘制倒影封面图片:

using (SKPaint paint = new SKPaint())
{
    paint.Color = SKColors.Black.WithAlpha((byte)(255 * 0.8));
    canvas.Scale(1, -1, 0, yCenter);
    canvas.DrawBitmap(bitmap, xBitmap, yBitmap, paint);
    SKRect rect = SKRect.Create(xBitmap, yBitmap, bitmap.Width, bitmap.Height);
    canvas.DrawRect(rect, paint);
}

倒影用一个黑色半透明的矩形覆盖在原始封面图片上,并且将画布沿Y轴翻转,使得倒影图片在封面图片的下方。

在这里插入图片描述

创建绑定属性

将图片源,旋转角度,平行角度等作为绑定属性,以便在XAML中绑定。代码忽略。

在这里插入图片描述

创建绑定数据

创建MainPageViewModel.cs,用于界面绑定数据源。

AlbumInfo描述专辑信息

public class AlbumInfo
{
    public AlbumInfo() { }

    public string AlbumName { get; set; }
    public string AlbumArtSource { get; set; }
}

在MainPageViewModel构造函数中,初始化AlbumInfo列表,在控件中绑定此列表作为数据源

创建布局

在MainPage.xaml中,创建一个Grid作为App后台任务专辑封面容器,我们将使用绑定集合的方式,将专辑封面添加到这个容器中。

代码如下:

<Grid Grid.Row="1"
    x:Name="BoxLayout"
    Background="black"
    BindableLayout.ItemsSource="{Binding AlbumInfos}">

它的DataTemplate代表一个专辑信息,使用Grid布局,专辑封面图片与专辑名称分别位于Grid的第一行和第二行。

<BindableLayout.ItemTemplate>
    <DataTemplate>
        <Grid Style="{StaticResource BoxFrameStyle}"
                Background="Transparent">
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition Height="auto"></RowDefinition>
            </Grid.RowDefinitions>
            <controls:RotationImage WidthRequest="200"
                                    HeightRequest="500"
                                    ImageWidth="200"
                                    ImageHeight="200"
                                    Source="{Binding AlbumArtSource}"></controls:RotationImage>


            <Label Margin="0,30,0,0"
                    Text="{Binding AlbumName}"
                    HorizontalTextAlignment="Center"
                    VerticalOptions="Center"></Label>


        </Grid>
    </DataTemplate>

</BindableLayout.ItemTemplate>

对专辑封面Grid的样式进行定义:

<ContentPage.Resources>
   <Style TargetType="Grid"
               x:Key="BoxFrameStyle">
            <Setter Property="HeightRequest"
                    Value="100"></Setter>
            <Setter Property="WidthRequest"
                    Value="100"></Setter>
            <Setter Property="HorizontalOptions"
                    Value="Center"></Setter>
            <Setter Property="VerticalOptions"
                    Value="Center"></Setter>
        </Style>
</ContentPage.Resources>

效果如下:

在这里插入图片描述

计算位置

Cover Flow的滑动交互由两种方式实现:1. 左右轻扫屏幕,切换到上一张或下一张专辑封面;2. 拨动底部Slider控件,切换到指定的专辑封面。

两种方式都会改变当前位置,我们将当前位置定义为一个整数,表示当前专辑在容器中的索引。

private int currentPos;

当手势触发时,根据手势方向,改变当前位置:

this.currentPos=e.Direction==SwipeDirection.Right
    ? Math.Max(0, this.currentPos-1)
    : Math.Min(this.BoxLayout.Children.Count-1, this.currentPos+1);

当Slider控件的值发生变化时,根据Slider的值,计算当前位置:


var currentPos = (int)Math.Floor(e.NewValue*  (this.BoxLayout.Children.Count-1));
if (this.currentPos!=currentPos)
{
    this.currentPos = currentPos;
}

当前位置索引的值始终在0到专辑封面数量减1之间。

当前封面是从专辑堆叠中挑选出来的,它的位置是固定的,左右两边的封面相对于当前封面,有一个固定的距离,step为当前封面和左右第一张封面之间的距离,slidePadding为其它封面和当前封面之间的距离。

在这里插入图片描述

其它封面的位置,分为两种情况:1. 在当前封面的左边;2. 在当前封面的右边。

封面叠层的顺序是当前封面最靠上,左右两边的封面随着距离由近及远,依次向下叠放。

创建RenderTransform方法,作为刷新的入口,当当前位置发生变化时,调用此方法,重新计算每个专辑封面的位置和叠放顺序。

private void RenderTransform(int currentPos)
{
    var step=40.0;
    var currentSlidePadding=100.0;
    foreach (var bitmapLayout in this.BoxLayout.Children)
    {
        var pos = this.BoxLayout.Children.IndexOf(bitmapLayout);
        double xBitmap;
        int zIndex;
        if (pos < currentPos)
        {
            zIndex=pos;
            xBitmap = (double)(-(currentPos * step) + (pos * step)  - currentSlidePadding);
        }
        else if (pos > currentPos)
        {
            zIndex=this.BoxLayout.Children.Count-pos;
            xBitmap = (double)(((pos - currentPos) * step)  + currentSlidePadding);
        }
        else
        {
            xBitmap =  0;
            zIndex=this.BoxLayout.Children.Count;
        }

        (bitmapLayout as VisualElement).ZIndex = zIndex;
        (bitmapObj as RotationImage).TranslationX=xBitmap;
    }
}

创建后,运行效果如下

在这里插入图片描述

计算3D旋转

我们对当前封面的左边的封面,以及当前封面的右边的封面,分别计算旋转角度,以实现3D效果。

var rotateY = 65;
foreach (var bitmapLayout in this.BoxLayout.Children)
{
    double targetRotateY;
    if (pos < currentPos)
    { 
        targetRotateY=rotateY;
    }
    else if (pos > currentPos)
    {   
        targetTransY=transY;
    }
    else
    {
        targetTransY=0;
    }
    (bitmapObj as RotationImage).RotateY=targetRotateY;
}

在这里插入图片描述

再对3D旋转的封面进行平行变换调整,并对封面位置作微调

var rotateY = 65;
var skewY = 0;
var transY = 0;
foreach (var bitmapLayout in this.BoxLayout.Children)
{
   
    double targetRotateY;
    double targetSkewY;
    double targetTransY;
    if (pos < currentPos)
    {
      
        targetRotateY=rotateY;
        targetSkewY=skewY;
        targetTransY=-transY;

    }
    else if (pos > currentPos)
    {
       
        targetRotateY=-rotateY;
        targetSkewY=-skewY;
        targetTransY=transY;
    }
    else
    {
        targetRotateY=0;
        targetSkewY=0;
        targetTransY=0;

    }

    (bitmapObj as RotationImage).RotateY=targetRotateY;
    (bitmapObj as RotationImage).TranslationX=xBitmap;
    (bitmapObj as RotationImage).SkewY=targetSkewY;
    (bitmapObj as RotationImage).TransY=targetTransY;
}

最后配置封面图片的缩放,以及封面标题显示、隐藏。

效果如下:

在这里插入图片描述

至此我们完成了静态的工作内容,下一步要让界面的过渡动画更加流畅,我们将使用MAUI的动画框架,实现平滑的过渡动画。

在这里插入图片描述

创建动效

我们通过创建Animation对象,添加子动画来实现。详情请参考Animation子动画。

RotateY、SkewY、TranslationX、Scale直接赋值的方式将由动画代替。动画是一种缓动机制,通过属性的缓慢改变实现平滑的过渡动画。

在渲染中我们为每一个封面创建一个Animation对象,然后添加子动画,最后调用Animation对象的Commit方法,

在400ms内将各属性缓慢应用到界面上。各属性步调一致,所以动画的过程是平滑的。

foreach (var bitmapLayout in this.BoxLayout.Children)
{
    uint duration = 400;
    ...

    Animation albumAnimation = new Animation();


    var originTranslationX = (bitmapLayout as VisualElement).TranslationX;
    var originScale = (bitmapLayout as VisualElement).Scale;
    var animation1 = new Animation(v => (bitmapLayout as VisualElement).TranslationX = v, originTranslationX, xBitmap, Easing.CubicInOut);
    var animation2 = new Animation(v => (bitmapLayout as VisualElement).Scale = v, originScale, targetScale, Easing.CubicInOut);


    if (targetSkewY!=(bitmapObj as RotationImage).SkewY)
    {
        var animation4 = new Animation(v => (bitmapObj as RotationImage).SkewY = v, (bitmapObj as RotationImage).SkewY, targetSkewY, Easing.CubicInOut);
        albumAnimation.Add(0, 1, animation4);

    }

    if (targetRotateY!=(bitmapObj as RotationImage).RotateY)
    {
        var animation3 = new Animation(v => (bitmapObj as RotationImage).RotateY = v, (bitmapObj as RotationImage).RotateY, targetRotateY, Easing.CubicInOut);
        albumAnimation.Add(0, 1, animation3);

    }

    if (targetTransY!=(bitmapObj as RotationImage).TransY)
    {
        var animation5 = new Animation(v => (bitmapObj as RotationImage).TransY = v, (bitmapObj as RotationImage).TransY, targetTransY, Easing.CubicInOut);
        albumAnimation.Add(0, 1, animation5);

    }
    albumAnimation.Add(0, 1, animation1);
    albumAnimation.Add(0, 1, animation2);

    albumAnimation.Commit((bitmapLayout as VisualElement), "AlbumArtImageAnimation", 16, duration);
}

效果如下:

在这里插入图片描述

在页面大小变化时,重新渲染变换。

    private void MainPage_SizeChanged(object sender, EventArgs e)
    {
        RenderTransform(currentPos);
    }

step和currentSlidePadding值将由屏幕宽度计算得出,使得在不同屏幕大小设备,或者横竖屏切换时,效果保持一致。

var xCenter = this.BoxLayout.Width / 2;
var step = xCenter*0.12;
var currentSlidePadding = this.BoxLayout.Width * 0.15;

在这里插入图片描述

项目地址

Github:maui-samples

关注我,学习更多.NET MAUI开发知识!

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

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

相关文章

使用Qt Creator编写窗体程序并打包发布

1、设置编辑器显示语言为中文(个人习惯) 2、新建窗体应用程序 3、简单修改一下代码 3.1 双击ui文件进入设计模式 3.2 从左侧组件中直接将需要使用的组件拖拽到窗体中 3.3 添加槽函数 选中按钮&#xff0c;右键菜单中 点击 转到槽&#xff0c;头文件和.cpp文件会自动添加对…

中间件_RabbitMQ五种消息模型

文章目录 1.简单消息队列模型2.Work工作队列模型3.发布订阅模型3.1.Fanout广播3.2.Direct路由3.3.Topics通配符 RabbitMQ官方文档 RabbitMQ 提供了5种常用消息模型。但是其实3、4、5这三种都属于订阅模型&#xff0c;只不过进行路由的方式不同。 1.简单消息队列模型 简单消息队…

C语言入门篇——编译篇

目录 1、程序环境 1.1 ANSI C 标准 1.2程序的翻译环境和执行环境 1.3运行环境 2、预处理详解 2.1、预定义符号 2.2、#define 2.2.1#define定义表示符 2.2.2#define定义宏 2.2.3#define替换规则 2.4#和## 2.2.5带副作用的宏参数 2.2.6宏和函数对比 3、#undef 4、…

项目1:登录功能设计

需求 后端接口设计MySQL表常用功能模块 后端总和前端实现方案 home页面 需求 实现一个登录功能 实现的功能 注册(邮箱注册) 登录(邮箱密码) 重置密码 查看操作记录(登录, 注册, 重置密码, 登出. 都算操作) 登出 后端接口设计 1. 人机验证 只要下面出现 人机验证 的功能都需要使…

容器化:MySQL

1 缘起 开启容器化之路。 2 容器化MySQL 2.1 查看MySQL镜像 docker search mysql2.2 指定版本&#xff1a;5.7.30 通过官网查看&#xff1a;https://hub.docker.com/ docker pull mysql:5.7.302.3 路径挂载 容器路径挂载到宿主机。 新建宿主机路径 mkdir -p /home/xind…

ElasticSearch-索引和文档的创建修改删除

目录 一、创建索引 二、查看索引 三、索引是否存在 四、删除索引 五、创建文档 六、查看文档 七、更新文档 八、文档是否存在 九、删除文档 一、创建索引 # 创建一个默认的索引&#xff0c;默认是标准分词器的索引 PUT /es_db2# 创建一个默认为ik分词器的索引 PUT /e…

十万条数据,后端不分页咋办!(如何优化长列表渲染)

十万条数据&#xff0c;后端不分页咋办&#xff01;&#xff08;如何优化长列表渲染&#xff09; 长列表是什么&#xff1f; 我们通常把一组数量级很大的数据叫做长列表&#xff0c;比如渲染一组上千条的数据&#xff0c;我们以数组的形式拿到这些信息&#xff0c;然后遍历渲…

Rust快速安装

Rust依赖C编译&#xff0c;Rust官方推荐的安装方式是利用VisualSudio安装C环境&#xff0c;VisualStuidio用过的都懂&#xff0c;庞大无比、卡顿、下载还贼慢(我当时装了一上午好像)&#xff0c;因此我们通过其它方式配置C 安装C环境 下载MinGW 64 win32 seh Mingw官网&…

Java的并发集合框架

文章目录 一、并发集合框架1. 简介2. 接口Iterable2. 接口Collection3. 接口List4. 接口Set5. 接口Queue6. Deque 二、非阻塞队列1. 概念2. ConcurrentHashMap使用&#xff08;1&#xff09;简介&#xff08;2&#xff09;验证HashMap不是线程安全的&#xff08;3&#xff09;验…

ld文件中指定变量在flash中的地址定义

本文说的是在gcc环境中&#xff0c;Keil或IAR可能有自己的使用方法。 我们在定义变量时&#xff0c;有时候需要把变量定义放到flash中的固定位置或区域&#xff0c;此时需要修改工程中的链接文件&#xff08;link file&#xff0c;ld文件&#xff09;。 方法一 修改ld文件中的…

软件IIC通信以及源码解析(如何使用)

以对读取MPU6050为例&#xff0c;解析如何采用IIC通信源码。 IIC的的通信&#xff0c;通常三种用途读写。分为&#xff1a; 1&#xff1a; 2&#xff1a; 3&#xff1a; 注&#xff1a;其中最常用的就是1和3了。 对1进行讲解&#xff1a; 指定地址写&#xff0c;通常用作对状…

【网络】- TCP/IP四层(五层)协议 - 网际层(网络层) - IP地址

目录 一、概述 二、IP地址的定义 三、IP地址由网络和主机两部分标识组成 一、概述 上篇文章简单介绍了网际协议IP。网际协议 IP 大致分为三大作用模块&#xff0c; ①IP寻址、 ②路由&#xff08;最终节点为止的转发&#xff09; 、③IP分包与组包。 这篇文章主要详细介绍IP地址…

【HTTP协议详解】

目录 1.什么是http2.抓包工具2.1 抓包工具2.2 抓包原理 3.Http协议格式3.1Http请求报文3.2Http响应报文的格式 4.请求报文格式4.1 报文首行4.2 请求报文header 5. 响应报文格式6.构造Http请求7.Https协议7.1 对称密钥7.2 非对称密钥7.3 证书 1.什么是http HTTP全称为“超文本协…

《MySQL是怎么运行的》阅读分享

mysql运行的整体架构简介 Mysql是由两部分构成&#xff0c;一部分是服务器程序&#xff0c;一部分是客户端程序。 服务器程序又包括两部分&#xff1a; 第一部分server层包括连接器、查询缓存、分析器、优化器、执行器等。涵盖 MySQL 的大多数核心服务功能&#xff0c;以及所有…

LeetCode:738.单调递增的数字 714.买卖股票的最佳时机含手续费 968.监控二叉树

738.单调递增的数字 题目 当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单调递增的。 给定一个整数 n &#xff0c;返回 小于或等于 n 的最大数字&#xff0c;且数字呈 单调递增 。 贪心 class Solution {public int monotoneIncrea…

数据结构——单链表(C语言)

在这⼀条⼗分漫长的路上&#xff0c;我⾛过阳关⼤道&#xff0c;也⾛过独⽊⼩桥。路旁有深⼭⼤泽&#xff0c;也有平坡宜⼈&#xff1b;有杏花春⾬&#xff0c;也有塞北秋风&#xff1b;有⼭重⽔复&#xff0c;也有柳暗花明&#xff1b;有迷途知返&#xff0c;也有绝处逢⽣。—…

[论文分享] Function Representations for Binary Similarity

Function Representations for Binary Similarity [TDSC 2022] Luca Massarelli , Giuseppe Antonio Di Luna, Fabio Petroni, Leonardo Querzoni, and Roberto Baldoni 二进制相似度问题在于仅考虑两个函数的编译形式来判断它们是否相似。近年来&#xff0c;计算二进制相似度…

【2023 · CANN训练营第一季】进阶班 Atlas 200I DK 智能小车

1 智能小车三维结构设计 1.1 基本模块 坚固酷炫结构模块运动控制模块超声波传感器模块摄像头视觉模块其他传感器模块 1.2 结构设计基本原则 从零开始设计并搭建智能小车&#xff0c;在满足外观要求的基础上&#xff0c;要满足小车运转过程中的运动干涉率为O&#xff0c;并且…

玩转ChatGPT:Show Me插件尝鲜

一、写在前面 之前&#xff0c;不少人问我GPT能否画技术路线图&#xff0c;然后看到了这个插件&#xff1a;Show Me&#xff1a; 简单问GPT这个插件的使用方法&#xff1a; 二、尝鲜过程 &#xff08;1&#xff09;用TA提供的例子试一试&#xff1a; 咒语&#xff1a;请用图…

009、实例连接访问控制

实例连接访问控制 1、实例连接访问控制概述2、pg_hba.conf文件3、名单格式4、pg_hba.conf 示例:5、当有重复或者冲突的时候1、实例连接访问控制概述 • 实例访问控制就像是一道防火墙,用它来控制来自于不同主机、不同用户是否 允许访问指定的数据库、以及验证方式。 2、pg…