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

.NET MAUI 基础知识 NET Multi-platform App UI (.NET MAUI) 是微软推出的新一代跨平台UI框架,是Xamarin.Forms的继任者。它允许开发者使用单一的代码库和项目结构,创建可在Android、iOS、macOS和Windows上运行的本地应用程序。.NET MAUI采用C#和XAML作为开发语言,为开发者提供了统一的编程模型和API,简化了跨平台应用开发流程。 阅读详情


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开发知识!

.NET MAUI 发展历程:从 Xamarin 到现代跨平台应用开发框架 NET MAUI代表了微软跨平台移动开发策略的重要发展,它不仅继承Xamarin的优势,还进一步扩展了应用范围和性能。作为统一的UI框架,MAUI在设计上解决了Xamarin相关框架的许多局限性,并且更好地集成到.NET生态系统中。尽管.NET MAUI相对于Flutter和React Native等框架在市场份额上可能仍有差距,但它在.NET开发者社区中获得了广泛采用,并且随着Microsoft的持续投资和社区的积极参与,其生态系统和能力将不断增强。 阅读详情

相关推荐

深入学习 MAUI:跨平台应用开发的未来

NET MAUI 是基于.NET 6+的一个跨平台 UI 框架,可以让开发者使用单一代码库来创建多平台应用。Android:智能手机和平板设备。iOS:iPhone、iPad 等设备。Windows:Windows 10/11 台式机和UWP设备。macOS:Mac 系统。通过本文的介绍,你应该已经对.NET MAUI有了一个全面的了解,从环境配置到基础应用的创建,再到平台特定功能的实现。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 3139

C# .Net MAUI 从入门到入土

NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架,用于使用 C# 和 XAML 创建本机移动和桌面应用。使用 .NET MAUI,可以从单个共享代码库开发可在 Android、iOS、macOS 和 Windows 上运行的应用。

熊思雨的博客 2万+

寻迹Arduino智能小车

Arduino巡线寻迹智能小车

Rachael_Wang的博客 9998

.NET MAUI学习笔记——3.创建第一个程序_初级篇

没接触过的人可能不知道app shell是啥?其实我也不知道,不过在这里应该可以暂时理解为一种UI框架(或UI结构)。可以按下图理解,当VS创建.NET MAUI项目时,会生成4个重要的代码文件。可以在解决方案管理器(Solution Explorer)中看到它们:这些文件用于配置和运行.NET MAUI应用程序。每个文件都有不同的用途,它们的描述如下:这是一个用于引导应用程序的代码文件。里面的代码作为应用程序的跨平台入口点,用于配置和启动应用程序。

三千幻想乡 5936

超越界面设计:GUI Guider与LVGL在STM32F103上的系统集成与架构思考

本文探讨了GUI Guider与LVGL在STM32F103微控制器上的系统集成与架构设计,重点分析了工程模块化组织、内存管理优化、硬件驱动接口设计以及FreeRTOS多任务集成。针对STM32F103ZET6的资源限制,提供了实用的移植策略和性能优化方案,帮助开发者构建高效、可维护的嵌入式GUI系统。

j2k3l4的博客 922

UE5.3.2 + VS2022社区版在Win11上的C++编译环境配置全解

Unreal Engine 5的C++开发依赖严格的工具链协同,其核心在于Visual Studio编译器版本、Windows SDK与引擎构建系统(UBT)的精准匹配。UE5.3.2强制要求MSVC v143.4(即VS2022 17.4+)及Windows 11 SDK 10.0.22621.0,任何偏差都会引发LNK2019链接失败、C1083头文件缺失或MSB8066构建中断等典型错误。该配置不仅关乎安装顺序,更涉及注册表清理、PATH环境变量、SDK路径注入与运行时DLL加载等底层机制。适用于Wi

weixin_33978722的博客 367

学习.NET MAUI Blazor(二)、MAUI是个啥

`.NET MAUI,全称.NET Multi-platform App UI` 顾名思义,就是跨平台UI框架。使用.NET MAUI,**理论**上使用一套代码就可以开发出可运行在 Android、iOS、macOS 和 Windows 上的应用

What If... 4535

ROS Noetic + Realsense ROS 2.3.2 在鲁班猫4上的完整工作空间搭建与相机启动调试

本文详细介绍了在鲁班猫4(RK3588S)开发板上搭建ROS Noetic与Realsense ROS 2.3.2开发环境的完整流程,包括Realsense SDK安装、工作空间配置、D435i深度相机驱动调试等关键步骤,为机器人视觉系统开发提供实用指南。

weixin_33217202的博客 237

认识.Net MAUI跨平台框架

macos: Visual Studio 2022 for Mac 17.4 或更高。windows : Visual Studio 2022 17.3 或更高。.NET 多平台应用 UI (.NET MAUI) 是一个开源的。,前身是Xamarin.Forms!NET MAUI,共享代码库,可在。创建本机移动和桌面应用。

2208

【实战】——零代码玩转Supervisely人像分割:从标注到模型训练的数据流水线搭建

本文详细介绍了如何零代码使用Supervisely平台搭建人像分割数据流水线,从智能标注到数据集格式转换,再到模型训练与优化。Supervisely的智能标注工具和协作功能大幅提升了人像分割项目的效率,特别适合视频会议背景虚化、虚拟试衣等应用场景。

weixin_30694389的博客 416

需求跟踪详解

需求跟踪是指在软件项目开发过程中,建立并维护需求与项目各阶段工作产物(如设计文档、代码模块、测试用例等)之间对应关系的过程。它不仅记录需求从提出到实现的完整路径,还能反映需求变更时对各阶段工作的影响范围,是连接用户期望与实际软件开发产出的桥梁。

跟佟格湾一起学习计算机知识吧~ 1423

无缝跨平台!C#跨平台开发利器——.NET MAUI

NET MAUI是.NET Multi-platform App UI的缩写,是.NET中的新一代跨平台开发框架。它基于.NET 6,整合了Xamarin.Forms和.NET MAUI for macOS,使得开发人员能够通过一套代码构建多个平台的应用程序。

MrQinin的博客 3284

Flink 运维监控与指标采集实战(Prometheus + Grafana 全流程)

Flink运维监控在实时计算场景中至关重要,因为Flink作业需要7×24小时稳定运行,对性能、资源、故障感知和状态变化的实时监控是保障系统稳定的关键。Flink自带的Metrics系统提供了基本的监控能力,但为了更全面的监控,Prometheus+Grafana成为最主流的解决方案。通过配置PrometheusReporter和Grafana仪表盘,可以实现对Flink作业的全面监控,包括CPU、内存、吞吐量、Checkpoint状态、KafkaSink性能等关键指标。此外,自定义指标采集和报警机制的配置

晴天彩虹雨的博客 1368

C# MAUI ImageButton无法正确缩放图片的解决(妥协)方案

与路径格式有关,如果直接使用带反斜杠。的路径,虽然并不会报错,但是ImageButton无法对其正确缩放,如果使用正斜杠。就可以正常缩放了。

F_CILF_CIL的博客 851

如何创建 SAP ABAP CDS View 的 Association

所以本文我们虽然学习了如何创建 SAP CDS View 的 association,知道了 association 是用来在 CDS View 里将两张数据库表关联起来,但根本不知道怎么使用这个 association. 而且从 association 的写法来看,似乎和本教程之前介绍 inner join,left join 这些数据库表的连接操作没什么区别,都是根据两张表的 carrid 和 connid 字段相同进行的连接。只看到了我们在 CDS View 源代码实现里,放出来的四个字段。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 904

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

.NET MAUI学习笔记——2.构建第一个程序_初级篇

想了一下,MAUI主打的是跨平台,号称『一次编写,随处运行』,如果还要出专门针对某个平台的构建指南,岂不是砸了自己的招牌。因此,不管是Windows、Android、iOS还是macOS,在构建第一个程序上,是大同小异的,官方文档中并没有给每种设备的构建列出单独的大章节,。不过安装环境这个东西,应该不需要单独开一篇文章讲吧,因为是在VS2022下开发,只需要在安装VS2022时勾选上MAUI环境即可(如果VS已经装完了但没有装MAUI的,可以再次打开安装器,重装并勾选MAUI)。

三千幻想乡 3126

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

[MAUI 项目实战] 手势控制音乐播放器(四):圆形进度条

在项目中添加SkiaSharp绘制功能的引用以及。

jevonsflash的专栏 2283

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

NET MAUI简介

强大的生态系统:作为.NET 生态系统的一部分,.NET MAUI 可以利用.NET 平台的丰富资源和工具,如 Visual Studio 等强大的开发工具,提高开发效率。- 共享代码库:允许大部分的 UI 和逻辑代码共享,减少了重复代码的编写,但对于一些特定平台的特殊需求,也可以通过特定平台的源代码文件进行扩展和定制。- 插件和工具支持:拥有活跃的社区,提供了大量的插件和工具,扩展了框架的功能,开发者可以根据自己的需求选择合适的插件进行集成。

地球空间 1247

.NET MAUI 跨平台应用开发(一)

.NET MAUI 是由微软开发的一种跨平台技术。本书的首版是在 .NET 6 上编写的。然而,第二版与 .NET 8 的发布同步,带来了各种改进。最新的 .NET MAUI 版本主要寻求提升代码质量。同时,对支持 iOS 和 Android 的开发环境也进行了更新,分别升级到 Xcode 15 和 Android API 34。目标改进集中在一系列关键方面,如纠正内存泄漏、改进 UI 控件、实施特定平台的修复和优化性能。这些改进的目标是加强内存管理、提高应用程序的稳定性,并确保在不同平台间用户体验的一致性

龙哥盟 1646

认识跨平台UI框架Flutter和MAUI区别,如何选。

.NET 跨平台开发框架对比:MAUI 与 Flutter 摘要: .NET MAUI 是微软官方推出的跨平台 UI 框架,基于 C#/XAML,继承了 Xamarin 的优势,提供原生控件渲染和 .NET 生态集成。Flutter 则是 Google 的跨平台解决方案,采用 Dart 语言和自绘引擎,实现高度一致的 UI 和卓越性能。两者关键区别在于:MAUI 适合 .NET 开发者,强调原生体验和企业集成;Flutter 则长于 UI 定制和跨平台一致性,支持更多目标平台。技术选型应基于团队技能、项目需

yuanpan的专栏 2073

.NET MAUI学习笔记——1.初识.NET MAUI_初级篇

NETMAppUI(简称.NET MAUI)是一个跨平台框架,它用C#和XAML来创建原生的移动端和桌面端应用程序。使用.NET MAUI,你只需维护一套共享的代码库就能开发运行在Android、iOS、macOS和Windows上的应用程序。.NET MAUI是开源的,它是Xamarin.Forms的进化版,从移动端扩展到了桌面场景,并且对UI控件进行了重建,以提高性能和可拓展性。如果你以前用过Xamarin.Forms来构建跨平台UI,你会注意到它与.NET MAUI有许多相似之处。

三千幻想乡 4135

从Xamarin到.NET MAUI:C#跨平台开发的3个关键选择

优先考虑.NET MAUI,因为它是最新的、官方支持的框架如果主要是Web应用,考虑Blazor如果已有Xamarin项目,考虑迁移到.NET MAUI技术总结:.NET MAUI是C#跨平台开发的首选框架:代码重复率降低40%,性能提升20%Blazor适合Web应用:一套代码,部署到Web、iOS、AndroidXamarin适合已有项目维护:但建议迁移到.NET MAUI“在C#跨平台开发中,.NET MAUI的性能优势非常明显,特别是在需要高性能和一致用户体验的场景中,

java专栏 2486

【MAUI】控件

.NET Multi-platform App UI (.NET MAUI) 应用的用户界面 (UI) 由映射到每个目标平台的本机控件的对象构成。 用于创建 .NET MAUI 应用的用户界面的主控件组包括页面、布局和视图。 .NET MAUI 页面通常占据整个屏幕或窗口。 页面通常包含布局,其中包含视图以及可能的其他布局。 页面、布局和视图派生自 VisualElement 类。 此类提供可在派生类中发挥帮助作用的各种属性、方法和事件。

欢迎指错||纠正||建议||水评+点赞&&评论&&关注&&转发 3765

C# 开发者的 .NET MAUI 指南(一)

NET MAUI 是微软的跨平台开发框架,用于构建 iOS、Android、Windows、Mac 和 Tizen 应用程序。使用.NET MAUI,您只需构建一次 UI 和逻辑,并为每个平台生成本地代码。它是的后续技术,并增加了强大的新功能和能力。.NET MAUI 社区工具包补充.NET MAUI,提供源代码生成器、行为等更多功能,极大地增强并扩展.NET MAUI,使其成为构建应用程序的首选开发框架。

龙哥盟 863

.NET MAUI 跨平台开发全栈指南:从零构建现代化多端应用

本文系统介绍了.NET MAUI跨平台开发框架的核心技术与实战指南。主要内容包括:1) 环境搭建与项目结构解析;2) XAML UI构建体系与布局技巧;3) Shell导航系统深度解析;4) MVVM模式与数据绑定实现;5) 平台特定功能开发方案;6) 性能优化与发布指南。文章通过"构建真实App"的主线,详细讲解了从基础到进阶的完整开发流程,重点解决了官方文档碎片化、概念跳跃等痛点问题,提供大量实际场景下的解决方案和最佳实践,帮助开发者快速掌握.NET MAUI开发的核心技能。

程序人生,算法世界 1030

.NET MAUI学习指南

由于.NET MAUI这项技术出来不久相关的学习资源暂时除了官网以外没有太好的学习资源,这篇文章主要向大家分享几种学习.NET MAUI的学习途径,如果有好的学习资源欢迎大家私信给我然后更新到后续的文章里。(以下推荐学习途径均为免费且无广告的资源,如果遇到收费请勿相信注意防骗。本文只是友情推荐不存在任何利益关系。)大概从下面几点分享(防止看大图头晕):1.官方文档2.视频教程3.书籍4..NET ...

dotNET跨平台 2498
上一篇: [学习笔记]解决因C#8.0的语言特性导致EFCore实体类型映射的错误
下一篇: [MAUI]模仿Chrome下拉标签页的交互实现
林晓lx
林晓lx 2017年优快云移动跨平台大赛优秀奖获得者 2017年优快云移动跨平台大赛优秀奖获得者
博客等级 码龄15年 3761粉丝 123原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林晓lx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值