[MAUI]写一个跨平台富文本编辑器

news2024/11/15 21:39:29

文章目录

  • 原理
  • 创建编辑器
    • 定义
    • 实现复合样式
      • 选择范围
      • 字号
      • 字体颜色与背景色
      • 字体下划线
      • 字体加粗与斜体
  • 序列化和反序列化
    • 跨平台实现
    • 集成至编辑器
  • 创建控件
  • 使用控件
  • 最终效果
  • 已知问题
  • 项目地址

富文本编辑器是一种所见即所得(what you see is what you get 简称 WYSIWYG)文本编辑器,用户在编辑器中输入内容和所做的样式修改,都会直接反映在编辑器中。

在Web端常见的有Quill、TinyMCE这些开源免费的富文本编辑器,而目前.NET MAUI方面没有类似的富文本编辑器可以免费使用。

使用.NET MAUI实现一个富文本编辑器并不难,今天就来写一个

在这里插入图片描述

使用.NET MAU实现跨平台支持,本项目可运行于Android、iOS平台。由于篇幅本文只展示Android平台的代码。

原理

.NET MAUI提供了编辑器控件,允许输入和编辑多行文本,虽然提供了字号,字体,颜色等控件属性,但我们无法为每个字符设置样式。我们将通过原生控件提供的范围选择器实现这一功能。

.NET MAUI提供了Handler的跨平台特性,我们将利用Handler实现所见即所得内容编辑器组件。这篇博文介绍了如何用Handler实现自定义跨平台控件,请阅读[MAUI程序设计] 用Handler实现自定义跨平台控件

在各平台中,我们将使用原生控件实现所见即所得的内容编辑器

  • Android使用SpannableString设置文本的复合样式,可以查看https://www.cnblogs.com/jisheng/archive/2013/01/10/2854088.html

  • iOS使用NSAttributeString设置文本的复合样式,可以参考https://blog.csdn.net/weixin_44544690/article/details/124154949

创建编辑器

新建.NET MAUI项目,命名RichTextEditor

在Controls目录中创建WysiwygContentEditor,继承自Editor,用于实现所见即所得的内容编辑器

构造函数中注册HandlerChanged和HandlerChanging事件


public class WysiwygContentEditor : Editor
{
    public WysiwygContentEditor()
    {
        HandlerChanged+=WysiwygContentEditor_HandlerChanged;
        HandlerChanging+=WysiwygContentEditor_HandlerChanging;
    }

}

在HandlerChanged事件中,获取Handler对象,通过它访问虚拟视图和本机视图。

private void WysiwygContentEditor_HandlerChanged(object sender, EventArgs e)
{
    var handler = Handler;
    if (handler != null)
    {
    }
}

android端原生控件为AppCompatEditText,iOS端原生控件为UITextView

//Android
var platformView = handler.PlatformView as AppCompatEditText;
//iOS
var platformView = handler.PlatformView as UITextView;

不同平台的代码,通过.Net6的条件编译实现,有关条件编译的详细信息,请参考官方文档。这次实现的是Android和iOS平台,所以在代码中条件编译语句如下

#if ANDROID

//android codes
...


#endif

#if IOS

//iOS codes
...

#endif


定义

定义StyleType枚举,用于控件可以处理的文本样式更改请求类型。

  • underline:字体下划线
  • italic:字体斜体
  • bold:字体加粗
  • backgoundColor:字体背景色
  • foregroundColor:字体前景色
  • size:字体大小
public enum StyleType
{
    underline, italic, bold, backgoundColor, foregroundColor, size
}


以及StyleArgs类,用于传递样式变更请求的参数

public class StyleArgs : EventArgs
{
    public StyleType Style;

    public string Params;
    public StyleArgs(StyleType style, string @params = null)
    {
        Style = style;
        Params=@params;
    }
}

定义SelectionArgs类,用于传递选择范围变更请求的参数

public class SelectionArgs : EventArgs
{
    public int Start;
    public int End;
    public SelectionArgs(int start, int end)
    {
        Start = start;
        End = end;
    }
}

定义事件用于各平台本机代码的调用

public event EventHandler GetHtmlRequest;
public event EventHandler<string> SetHtmlRequest;
public event EventHandler<StyleArgs> StyleChangeRequested;
public event EventHandler<SelectionArgs> SelectionChangeHandler;

创建StyleChangeRequested的订阅事件以响应样式变更请求,对应不同的样式类型,调用不同的方法实现样式变更。


StyleChangeRequested =new EventHandler<StyleArgs>(
(sender, e) =>

{
    var EditableText = platformView.EditableText;

    switch (e.Style)
    {
        case StyleType.underline:
            UpdateUnderlineSpans(EditableText);
            break;
        case StyleType.italic:
            UpdateStyleSpans(TypefaceStyle.Italic, EditableText);
            break;
        case StyleType.bold:
            UpdateStyleSpans(TypefaceStyle.Bold, EditableText);
            break;
        case StyleType.backgoundColor:
            UpdateBackgroundColorSpans(EditableText, Microsoft.Maui.Graphics.Color.FromArgb(e.Params));
            break;
        case StyleType.foregroundColor:
            UpdateForegroundColorSpans(EditableText, Microsoft.Maui.Graphics.Color.FromArgb(e.Params));
            break;
        case StyleType.size:
            UpdateAbsoluteSizeSpanSpans(EditableText, int.Parse(e.Params));
            break;
        default:
            break;
    }


});


实现复合样式

选择范围

android端使用SelectionStart和SelectionEnd获取选择范围,iOS端使用SelectedRange获取选择范围

//Android

int getSelectionStart() => platformView.SelectionStart;
int getSelectionEnd() => platformView.SelectionEnd;

//iOS
NSRange getSelectionRange() => platformView.SelectedRange;


字号

MAUI控件中字号使用FontSize属性单位为逻辑像素,与DPI设置相关联。
在android本机平台中,字号通过为EditableText对象设置AbsoluteSizeSpan实现,代码如下


void UpdateAbsoluteSizeSpanSpans(IEditable EditableText, int size)
{

    var spanType = SpanTypes.InclusiveInclusive;

    EditableText.SetSpan(new AbsoluteSizeSpan(size, true), getSelectionStart(), getSelectionEnd(), spanType);
    SetEditableText(EditableText, platformView);
}

字体颜色与背景色

Android平台中,字体颜色与背景色通过为EditableText对象设置ForegroundColorSpan和BackgroundColorSpan实现

void UpdateForegroundColorSpans(IEditable EditableText, Microsoft.Maui.Graphics.Color color)
{
    var spanType = SpanTypes.InclusiveInclusive;
    EditableText.SetSpan(new ForegroundColorSpan(color.ToAndroid()), getSelectionStart(), getSelectionEnd(), spanType);
    SetEditableText(EditableText, platformView);
}

void UpdateBackgroundColorSpans(IEditable EditableText, Microsoft.Maui.Graphics.Color color)
{
    var spanType = SpanTypes.InclusiveInclusive;
    EditableText.SetSpan(new BackgroundColorSpan(color.ToAndroid()), getSelectionStart(), getSelectionEnd(), spanType);
    SetEditableText(EditableText, platformView);
}

字体下划线

将选择文本选择范围内若包含下划线,则移除下划线,否则添加下划线

Android平台中通过为EditableText对象设置UnderlineSpan实现为文本添加下划线,通过RemoveSpan方法可以移除下划线,

但选择范围可能已包含下划线片段的一部分,因此移除此下划线片段后,需要重新添加下划线片段,以实现部分移除的效果


void UpdateUnderlineSpans(IEditable EditableText)
{

    var underlineSpans = EditableText.GetSpans(getSelectionStart(), getSelectionEnd(), Java.Lang.Class.FromType(typeof(UnderlineSpan)));

    bool hasFlag = false;
    var spanType = SpanTypes.InclusiveInclusive;

    foreach (var span in underlineSpans)
    {
        hasFlag = true;

        var spanStart = EditableText.GetSpanStart(span);
        var spanEnd = EditableText.GetSpanEnd(span);
        var newStart = spanStart;
        var newEnd = spanEnd;
        var startsBefore = false;
        var endsAfter = false;

        if (spanStart < getSelectionStart())
        {
            newStart = getSelectionStart();
            startsBefore = true;
        }
        if (spanEnd > getSelectionEnd())
        {
            newEnd = getSelectionEnd();
            endsAfter = true;
        }

        EditableText.RemoveSpan(span);

        if (startsBefore)
        {
            EditableText.SetSpan(new UnderlineSpan(), spanStart, newStart, SpanTypes.ExclusiveExclusive);
        }
        if (endsAfter)
        {
            EditableText.SetSpan(new UnderlineSpan(), newEnd, spanEnd, SpanTypes.ExclusiveExclusive);
        }
    }

    if (!hasFlag)
    {
        EditableText.SetSpan(new UnderlineSpan(), getSelectionStart(), getSelectionEnd(), spanType);
    }
    SetEditableText(EditableText, platformView);
}


字体加粗与斜体

Android平台中,字体粗细与斜体通过为EditableText对象设置StyleSpan实现,与设置字体下划线一样,需要处理选择范围内已包含StyleSpan的情况

TypefaceStyle提供了Normal、Bold、Italic、BoldItalic四种字体样式,粗体+斜体样式是通过组合实现的,因此需要处理样式叠加问题


void UpdateStyleSpans(TypefaceStyle flagStyle, IEditable EditableText)
{
    var styleSpans = EditableText.GetSpans(getSelectionStart(), getSelectionEnd(), Java.Lang.Class.FromType(typeof(StyleSpan)));
    bool hasFlag = false;
    var spanType = SpanTypes.InclusiveInclusive;

    foreach (StyleSpan span in styleSpans)
    {
        var spanStart = EditableText.GetSpanStart(span);
        var spanEnd = EditableText.GetSpanEnd(span);
        var newStart = spanStart;
        var newEnd = spanEnd;
        var startsBefore = false;
        var endsAfter = false;

        if (spanStart < getSelectionStart())
        {
            newStart = getSelectionStart();
            startsBefore = true;
        }
        if (spanEnd > getSelectionEnd())
        {
            newEnd = getSelectionEnd();
            endsAfter = true;
        }

        if (span.Style == flagStyle)
        {
            hasFlag = true;
            EditableText.RemoveSpan(span);
            EditableText.SetSpan(new StyleSpan(TypefaceStyle.Normal), newStart, newEnd, spanType);
        }
        else if (span.Style == TypefaceStyle.BoldItalic)
        {
            hasFlag = true;
            EditableText.RemoveSpan(span);
            var flagLeft = TypefaceStyle.Bold;
            if (flagStyle == TypefaceStyle.Bold)
            {
                flagLeft = TypefaceStyle.Italic;
            }
            EditableText.SetSpan(new StyleSpan(flagLeft), newStart, newEnd, spanType);
        }

        if (startsBefore)
        {
            EditableText.SetSpan(new StyleSpan(span.Style), spanStart, newStart, SpanTypes.ExclusiveExclusive);
        }
        if (endsAfter)
        {
            EditableText.SetSpan(new StyleSpan(span.Style), newEnd, spanEnd, SpanTypes.ExclusiveExclusive);
        }

    }
    if (!hasFlag)
    {
        EditableText.SetSpan(new StyleSpan(flagStyle), getSelectionStart(), getSelectionEnd(), spanType);
    }

    SetEditableText(EditableText, platformView);
}

序列化和反序列化

所见即所得的内容需要被序列化和反序列化以便存储或传输,我们仍然使用HTML作为中间语言,好在Android和iOS平台都有HTML互转的对应实现。

  • Android平台中,Android.Text.Html提供了FromHtml()和Html.ToHtml(),
  • iOS中的NSAttributedStringDocumentAttributes提供了DocumentType属性,可以设置为NSHTMLTextDocumentType,使用它初始化AttributedString或调用AttributedString.GetDataFromRange()方法实现HTML和NSAttributedString的互转。

跨平台实现

在Platform/Android目录下创建HtmlParser.Android作为Android平台序列化和反序列化的实现。

public static class HtmlParser_Android
{
    public static ISpanned HtmlToSpanned(string htmlString)
    {
        ISpanned spanned = Html.FromHtml(htmlString, FromHtmlOptions.ModeCompact);
        return spanned;
    }

    public static string SpannedToHtml(ISpanned spanned)
    {
        string htmlString = Html.ToHtml(spanned, ToHtmlOptions.ParagraphLinesIndividual);
        return htmlString;
    }
}

在Platform/iOS目录下创建HtmlParser.iOS作为iOS平台序列化和反序列化的实现。

public static class HtmlParser_iOS
{
    static nfloat defaultSize = UIFont.SystemFontSize;
    static UIFont defaultFont;

    public static NSAttributedString HtmlToAttributedString(string htmlString)
    {
        var nsString = new NSString(htmlString);
        var data = nsString.Encode(NSStringEncoding.UTF8);
        var dictionary = new NSAttributedStringDocumentAttributes();
        dictionary.DocumentType = NSDocumentType.HTML;
        NSError error = new NSError();
        var attrString = new NSAttributedString(data, dictionary, ref error);
        var mutString = ResetFontSize(new NSMutableAttributedString(attrString));

        return mutString;
    }

    static NSAttributedString ResetFontSize(NSMutableAttributedString attrString)
    {
        defaultFont = UIFont.SystemFontOfSize(defaultSize);

        attrString.EnumerateAttribute(UIStringAttributeKey.Font, new NSRange(0, attrString.Length), NSAttributedStringEnumeration.None, (NSObject value, NSRange range, ref bool stop) =>
        {
            if (value != null)
            {
                var oldFont = (UIFont)value;
                var oldDescriptor = oldFont.FontDescriptor;

                var newDescriptor = defaultFont.FontDescriptor;

                bool hasBoldFlag = false;
                bool hasItalicFlag = false;

                if (oldDescriptor.SymbolicTraits.HasFlag(UIFontDescriptorSymbolicTraits.Bold))
                {
                    hasBoldFlag = true;
                }
                if (oldDescriptor.SymbolicTraits.HasFlag(UIFontDescriptorSymbolicTraits.Italic))
                {
                    hasItalicFlag = true;
                }

                if (hasBoldFlag && hasItalicFlag)
                {
                    uint traitsInt = (uint)UIFontDescriptorSymbolicTraits.Bold + (uint)UIFontDescriptorSymbolicTraits.Italic;
                    newDescriptor = newDescriptor.CreateWithTraits((UIFontDescriptorSymbolicTraits)traitsInt);
                }
                else if (hasBoldFlag)
                {
                    newDescriptor = newDescriptor.CreateWithTraits(UIFontDescriptorSymbolicTraits.Bold);
                }
                else if (hasItalicFlag)
                {
                    newDescriptor = newDescriptor.CreateWithTraits(UIFontDescriptorSymbolicTraits.Italic);
                }

                var newFont = UIFont.FromDescriptor(newDescriptor, defaultSize);

                attrString.RemoveAttribute(UIStringAttributeKey.Font, range);
                attrString.AddAttribute(UIStringAttributeKey.Font, newFont, range);
            }

        });

        return attrString;
    }


    public static string AttributedStringToHtml(NSAttributedString attributedString)
    {
        var range = new NSRange(0, attributedString.Length);
        var dictionary = new NSAttributedStringDocumentAttributes();
        dictionary.DocumentType = NSDocumentType.HTML;
        NSError error = new NSError();
        var data = attributedString.GetDataFromRange(range, dictionary, ref error);
        var htmlString = new NSString(data, NSStringEncoding.UTF8);
        return htmlString;
    }
}

集成至编辑器

在所见即所得编辑器中设置两个方法,一个用于获取编辑器中的内容,一个用于设置编辑器中的内容。


public void SetHtmlText(string htmlString)
{
    HtmlString = htmlString;
    SetHtmlRequest(this, htmlString);
}



public string GetHtmlText()
{

    GetHtmlRequest(this, new EventArgs());
    return HtmlString;
}

在HandlerChanged事件方法中的各平台代码段中添加如下代码:

GetHtmlRequest = new EventHandler(
    (sender, e) =>
        {
            var editor = (WysiwygContentEditor)sender;
            HtmlString=HtmlParser_Android.SpannedToHtml(platformView.EditableText);
        }
    );
SetHtmlRequest =new EventHandler<string>(
    (sender, htmlString) =>
        {
            platformView.TextFormatted = HtmlParser_Android.HtmlToSpanned(htmlString);
        }
    );

在富文本编辑器中的内容,最终会生成一个带有内联样式的HTML字符串,如下所示:

在这里插入图片描述

在这里插入图片描述

创建控件

控件由所见即所得编辑器和工具栏组成,所见即所得编辑器用于显示和编辑内容,工具栏用于设置字号、颜色、加粗、斜体、下划线

在这里插入图片描述

创建RichTextEditor的带有Xaml的ContentView。将所见即所得编辑器放置中央,工具栏放置在底部。

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:RichTextEditor.Controls;assembly=RichTextEditor"
             x:Class="RichTextEditor.Controls.RichTextEditor">
    <Border>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="1*"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
                <controls:WysiwygContentEditor MinimumHeightRequest="150"
                        AutoSize="TextChanges"
                        BackgroundColor="{StaticResource PhoneContrastBackgroundBrush}"
                        IsSpellCheckEnabled="false"
                        x:Name="MainEditor"></controls:WysiwygContentEditor>
            </Grid>
    </Border>
</ContentView>

工具栏内的按钮横向排列

<HorizontalStackLayout Grid.Row="3"
                        Spacing="5"
                        Margin="0,10">
    <Button Text="{Binding Source={x:Reference TextSizeCollectionView}, Path=SelectedItem.Name, FallbackValue=Auto}"
            Style="{StaticResource RichTextButtonStyle}"
            Clicked="TextSizeButton_Clicked"
            x:Name="TextSizeButton"></Button>
    <Button Text="Color"
            TextColor="{Binding Source={x:Reference ColorCollectionView}, Path=SelectedItem}"
            Style="{StaticResource RichTextButtonStyle}"
            Clicked="TextColorButton_Clicked"
            x:Name="TextColorButton"></Button>
    <Button Text="B"
            Style="{StaticResource RichTextButtonStyle}"
            FontAttributes="Bold"
            x:Name="BoldButton"
            Clicked="BoldButton_Clicked"></Button>
    <Button Text="I"
            Style="{StaticResource RichTextButtonStyle}"
            FontAttributes="Italic"
            x:Name="ItalicButton"
            Clicked="ItalicButton_Clicked"></Button>
    <Button Text="U"
            Style="{StaticResource RichTextButtonStyle}"
            FontAttributes="None"
            x:Name="UnderLineButton"
            Clicked="UnderLineButton_Clicked"></Button>
</HorizontalStackLayout>

在这里插入图片描述

配置两个选择器:TextSizeCollectionView为字体大小选择器,ColorCollectionView为字体颜色选择器。

当点击字体大小选择器时,弹出字体大小选择器,当点击字体颜色选择器时,弹出字体颜色选择器。

在这里插入图片描述

在这里插入图片描述

<VerticalStackLayout x:Name="OptionsLayout"
                        Grid.Row="2"
                        Spacing="5">
    <CollectionView x:Name="TextSizeCollectionView"
                    Background="Transparent"
                    SelectionChanged="TextSizeCollectionView_SelectionChanged"
                    SelectionMode="Single"
                    HeightRequest="45">
        <CollectionView.ItemsLayout>
            <LinearItemsLayout Orientation="Horizontal"
                                ItemSpacing="5"></LinearItemsLayout>
        </CollectionView.ItemsLayout>
        <CollectionView.ItemTemplate>
            <DataTemplate>

                <Border x:Name="TargetElement"
                        Style="{StaticResource SelectableLayoutStyle}"
                        Background="{StaticResource PhoneContrastBackgroundBrush}"
                        Padding="5,0">
                    <Label Text="{Binding Name}"
                            TextColor="{StaticResource PhoneForegroundBrush}"
                            VerticalOptions="Center"
                            FontSize="{Binding Value}"></Label>
                </Border>



            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

    <CollectionView x:Name="ColorCollectionView"
                    SelectionChanged="ColorCollectionView_SelectionChanged"
                    SelectionMode="Single"
                    HeightRequest="45">
        <CollectionView.ItemsLayout>
            <LinearItemsLayout Orientation="Horizontal"
                                ItemSpacing="5"></LinearItemsLayout>
        </CollectionView.ItemsLayout>
        <CollectionView.ItemTemplate>
            <DataTemplate>

                <Border x:Name="TargetElement"
                        Style="{StaticResource SelectableLayoutStyle}"
                        BackgroundColor="{Binding}"
                        WidthRequest="40"
                        HeightRequest="40"
                        StrokeShape="RoundRectangle 40">

                </Border>

            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</VerticalStackLayout>

后端代码,绑定一些默认值


public static List<Color> DefaultTextColorList = new List<Color>() {
    Color.FromArgb("#000000"),
    Color.FromArgb("#F9371C"),
    Color.FromArgb("#F97C1C"),
    Color.FromArgb("#F9C81C"),
    Color.FromArgb("#41D0B6"),
    Color.FromArgb("#2CADF6"),
    Color.FromArgb("#6562FC")
};

public static List<TextSize> DefaultTextSizeList = new List<TextSize>() {
    new TextSize(){Name="Large", Value=22},
    new TextSize(){Name="Middle", Value=18},
    new TextSize(){Name="Small", Value=12},
};

效果如下:

在这里插入图片描述

使用控件

在MainPage中使用RichTextEditor,代码如下


<controls:RichTextEditor  
            x:Name="MainRichTextEditor"
            Text="{Binding Content}"
            Placeholder="{Binding PlaceHolder}"></controls:RichTextEditor>

MainRichTextEditor.GetHtmlText()测试获取富文本编辑器Html序列化功能。

private async void Button_Clicked(object sender, EventArgs e)
{
    var html = this.MainRichTextEditor.GetHtmlText();
    await DisplayAlert("GetHtml()", html, "OK");
}

最终效果

在这里插入图片描述

已知问题

  • HTML样式会重复添加

项目地址

我在maui-sample项目中的一些控件,打算做成一个控件库,方便大家使用。控件库地址在下方。

maui-sample项目作为控件库孵化器,代码可能会有点乱,也没有经过严格的测试。当控件完善到一定程度,我会把控件封装起来放到控件库中。如果你有好的控件,欢迎pull request。

maui-sample:
Github:maui-samples

Mato.Maui控件库
Mato.Maui

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

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

相关文章

visual studio 2022,ADO.NET 实体数据模型添加 sqlite数据库对象

文章目录 前言前期环境博客github 文档解析文件安装说明文件下载省流版nuget环境配置成功标志sqlite连接测试 前言 我们知道ADO.NET 实体数据模型特别适合动态开发数据库。因为ADO.NET可以使用DB First 开发 我们在开发一个程序的时候&#xff0c;经常会动态更新数据库字段&a…

Python的基础语法知识

1、变量 变量是一个代号&#xff0c;它代表的是一个数据。 在Python中&#xff0c;定义一个变量的操作包含两个步骤&#xff1a; ①为变量起一个名字 ②为变量指定其所代表的数据 这两个步骤在同一行代码中完成。 1.1 变量的命名规则 变量名可以由任意数量的字母、数字、下划…

Unity 简易UI管理器

首先我们需要先定义这么一个UIManager类。 public class UIManager { } UI管理器嘛&#xff0c;顾名思义肯定是用来管理我们游戏中的UI的&#xff0c;而我们游戏当中的UI呢一般是以面板为单位来进行划分的。所以我们还需要一个UI面板类。然后通过我们的UI管理器来管理我们的U…

Linux——创建容器并将本地调试完全的前后端分离项目打包上传docker运行

前言 在上传之前需要有一个已经搭建好的前后端分离的项目&#xff0c;下面是后端的项目结构图和前端页面图 在服务器上利用准备好的docker镜像配置一个新的容器 创建容器 这里使用的docker镜像的OS是ubuntu20.04.需要自备。 注意好端口映射: 通常前端项目使用的端口号一般都…

【DeepSpeed 教程翻译】二,Megatron-LM GPT2,Zero Redundancy Optimizer 和 ZeRO-Offload

文章目录 0x0. 前言0x1. Megatron-LM GPT2使用原始的 Megatron-LM 训练 GPT2设置训练数据运行未修改的Megatron-LM GPT2模型开启DeepSpeed参数解析初始化和训练初始化使用训练API前向传播 反向传播更新模型参数损失缩放检查点保存和加载 DeepSpeed Activation Checkpoints&…

异常检测学习笔记 三、线性回归方法、主成分分析、支持向量机

一、线性回归方法 类似这样的函数是线性回归模型和支持向量机的基础,线性函数很简单,如果原始问题是非线性的,那么将其转化为线性问题更容易处理,比如下面的方程。 线性映射是主成分分析的重要组成部分。 寻找响应(因变量)和解释变量(自变量)之间的线性关系,…

python实现图片、gif转为字符样式图与gif,pyqt5、opencv、PIL

使用pyqt5将图片转换为字符样式的图片步骤如下&#xff1a; 设计pyqt5界面&#xff0c;使用Qt Designer 设计界面样式 将ui文件转换为py代码 书写相关按钮信号槽代码打开图片按钮需要一下逻辑步骤弹出选择路径的界面来选择文件保存 图片的路径&#xff0c;能在转换保存的按钮…

数字IC前端学习笔记:FIFO的Verilog实现(二)

相关文章 数字IC前端学习笔记&#xff1a;LSFR&#xff08;线性反馈移位寄存器&#xff09; 数字IC前端学习笔记&#xff1a;跨时钟域信号同步 数字IC前端学习笔记&#xff1a;信号同步和边沿检测 数字IC前端学习笔记&#xff1a;锁存器Latch的综合 数字IC前端学习笔记&am…

最新站长必备在线工具箱系统源码 含上百款工具 带后台版本

&#x1f388; 限时活动领体验会员&#xff1a;可下载程序网创项目短视频素材 &#x1f388; 最新站长必备在线工具箱系统源码 含上百款工具 带后台版本 自适应模板 优化修复版 系统一切正常可用&#xff0c;后台登录方式是QQ扫码登录的,建议有能力的可以改一改 此工具箱系统…

【LVS + Keepalived 群集】

目录 一、Keepalived 案列分析二、Keeoalived 工具介绍1、keepalived 实现原理剖析2、VRRP &#xff08;虚拟路由冗余协议&#xff09;是指对路由器的一种备份解决方案3、keepalived 案例讲解4、keepalived 的安装与启动5、Keepalived及其工作原理Keepalived体系主要模块及其作…

SQL锁总结

一、概述 介绍 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资源(CPU、RAM、I/O)的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题&#xff0c;锁…

springboot3嵌入式容器源码解析

问题分析 不同于使用springmvc,在我们使用springboot时无需配置tomcat就可以直接使用&#xff0c;这就说明springboot已经在我们启动项目时将tomcat配置好了&#xff0c;接下来我们就来看看springboot底层是怎么实现的。 源码解析 ServletWebServerFactoryAutoConfiguratio…

【Python爬虫】整站40万条房价数据并行抓取,可更换抓取城市

目录 前言一、获取索引一级位置&#xff1a;区域信息二级位置&#xff1a;板块信息三级位置&#xff1a;地铁信息&#xff08;搜索地铁周边房源信息&#xff09; 二、获取索引页最大页数三、抓取房源信息Tag四、分配任务&#xff0c;并行抓取五、将抓取结果存储到excel中&#…

go map源码探索(查找、插入、删除、扩容、遍历)

文章目录 概要一、Go map结构二、Go map初始化2.1、不带容量初始化2.2、带容量初始化 三、Go map查找四、Go map插入4.1、插入源码分析4.2、溢出桶申请策略 五、删除源码分析六、扩容与迁移源码分析6.1、扩容条件6.1.1、当前负载因子大于6.56.1.2、有过多的溢出桶 6.2、扩容6.3…

LVS+Keepalivedd

Keepalived 一、Keepalived及其工作原理二、实验非抢占模式的设置 三、脑裂现象四、Nginx高可用模式 一、Keepalived及其工作原理 keepalived是一个基于VRRP协议来实现的LVS服务高可用方案&#xff0c;可用解决静态路由出现的单点故障问题。 在一个LVS服务集群中通常有主服务器…

11.枚举和注解|Java学习笔记

文章目录 枚举 enumeration enum自定义实现枚举自定义类实现枚举总结 使用enum关键字实现枚举实现方法Enum类方法enum实现接口 注解注解的理解JDK的元Annotation&#xff08;元注解&#xff09; 枚举 enumeration enum 从一个需求引入&#xff1a; 要求创建季节(Season) 对象&…

matlab 使用预训练神经网络和SVM进行苹果分级(带图形界面)支持其他物品图片分级或者分类

目录 数据集&#xff1a; 实验代码&#xff1a;alexnet版 如果你的matlab不是正版&#xff0c;先看这里&#xff1a; 数据集结构&#xff1a; 训练代码&#xff1a; 训练结果&#xff1a; 图形界面&#xff1a; 界面展示&#xff1a; 其他&#xff1a; 输出结果: 实验…

代码规范

一 、代码规范 程序员写代码&#xff0c;不仅仅是实现功能 1. 名称 在Python开发过程中会创建文件夹/文件/变量等&#xff0c;这些在命名有一些潜规则&#xff08;编写代码时也要注意pep8规范&#xff09;。 文件夹&#xff0c;小写 & 小写下划线连接&#xff0c;例如&a…

jmeter 在linux服务器中执行性能测试、监听服务器资源指标

jmeter监控服务器资源 资源准备jmeter安装&#xff08;Windows 版&#xff09;jmeter安装&#xff08;linux 版&#xff09;ServerAgent安装&#xff08;linux 版&#xff09;配置脚本并执行测试 资源准备 下载apache-jmeter-5.5文件;下载ServerAgent-2.2.3文件; jmeter安装&…

ZooKeeper的集群部署和启动与关闭

ZooKeeper是一个分布式应用程序协调服务。一个ZooKeeper集群可以存在多个Follower和Observer服务器&#xff0c;但只允许存在一台Leader服务器。如果Leader服务器宕机&#xff0c;那么ZooKeeper集群的其它服务器会投票选举出一个新的Leader服务器&#xff0c;为防止投票数不过半…