国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

[MAUI]寫一個跨平臺富文本編輯器

這篇具有很好參考價值的文章主要介紹了[MAUI]寫一個跨平臺富文本編輯器。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

@

目錄
  • 原理
  • 創(chuàng)建編輯器
    • 定義
    • 實(shí)現(xiàn)復(fù)合樣式
      • 選擇范圍
      • 字號
      • 字體顏色與背景色
      • 字體下劃線
      • 字體加粗與斜體
  • 序列化和反序列化
    • 跨平臺實(shí)現(xiàn)
    • 集成至編輯器
  • 創(chuàng)建控件
  • 使用控件
  • 最終效果
  • 已知問題
  • 項(xiàng)目地址

富文本編輯器是一種所見即所得(what you see is what you get 簡稱 WYSIWYG)文本編輯器,用戶在編輯器中輸入內(nèi)容和所做的樣式修改,都會直接反映在編輯器中。

在Web端常見的有Quill、TinyMCE這些開源免費(fèi)的富文本編輯器,而目前.NET MAUI方面沒有類似的富文本編輯器可以免費(fèi)使用。

使用.NET MAUI實(shí)現(xiàn)一個富文本編輯器并不難,今天就來寫一個

[MAUI]寫一個跨平臺富文本編輯器

使用.NET MAU實(shí)現(xiàn)跨平臺支持,本項(xiàng)目可運(yùn)行于Android、iOS平臺。由于篇幅本文只展示Android平臺的代碼。

原理

.NET MAUI提供了編輯器控件,允許輸入和編輯多行文本,雖然提供了字號,字體,顏色等控件屬性,但我們無法為每個字符設(shè)置樣式。我們將通過原生控件提供的范圍選擇器實(shí)現(xiàn)這一功能。

.NET MAUI提供了Handler的跨平臺特性,我們將利用Handler實(shí)現(xiàn)所見即所得內(nèi)容編輯器組件。這篇博文介紹了如何用Handler實(shí)現(xiàn)自定義跨平臺控件,請閱讀[MAUI程序設(shè)計(jì)] 用Handler實(shí)現(xiàn)自定義跨平臺控件

在各平臺中,我們將使用原生控件實(shí)現(xiàn)所見即所得的內(nèi)容編輯器

  • Android使用SpannableString設(shè)置文本的復(fù)合樣式,可以查看https://www.cnblogs.com/jisheng/archive/2013/01/10/2854088.html

  • iOS使用NSAttributeString設(shè)置文本的復(fù)合樣式,可以參考https://blog.csdn.net/weixin_44544690/article/details/124154949

創(chuàng)建編輯器

新建.NET MAUI項(xiàng)目,命名RichTextEditor

在Controls目錄中創(chuàng)建WysiwygContentEditor,繼承自Editor,用于實(shí)現(xiàn)所見即所得的內(nèi)容編輯器

構(gòu)造函數(shù)中注冊HandlerChanged和HandlerChanging事件


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

}

在HandlerChanged事件中,獲取Handler對象,通過它訪問虛擬視圖和本機(jī)視圖。

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的條件編譯實(shí)現(xiàn),有關(guān)條件編譯的詳細(xì)信息,請參考官方文檔。這次實(shí)現(xiàn)的是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類,用于傳遞樣式變更請求的參數(shù)

public class StyleArgs : EventArgs
{
    public StyleType Style;

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

定義SelectionArgs類,用于傳遞選擇范圍變更請求的參數(shù)

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

定義事件用于各平臺本機(jī)代碼的調(diào)用

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

創(chuàng)建StyleChangeRequested的訂閱事件以響應(yīng)樣式變更請求,對應(yīng)不同的樣式類型,調(diào)用不同的方法實(shí)現(xiàn)樣式變更。


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;
    }


});


實(shí)現(xiàn)復(fù)合樣式

選擇范圍

android端使用SelectionStart和SelectionEnd獲取選擇范圍,iOS端使用SelectedRange獲取選擇范圍

//Android

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

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


字號

MAUI控件中字號使用FontSize屬性單位為邏輯像素,與DPI設(shè)置相關(guān)聯(lián)。
在android本機(jī)平臺中,字號通過為EditableText對象設(shè)置AbsoluteSizeSpan實(shí)現(xiàn),代碼如下


void UpdateAbsoluteSizeSpanSpans(IEditable EditableText, int size)
{

    var spanType = SpanTypes.InclusiveInclusive;

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

字體顏色與背景色

Android平臺中,字體顏色與背景色通過為EditableText對象設(shè)置ForegroundColorSpan和BackgroundColorSpan實(shí)現(xiàn)

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);
}

字體下劃線

將選擇文本選擇范圍內(nèi)若包含下劃線,則移除下劃線,否則添加下劃線

Android平臺中通過為EditableText對象設(shè)置UnderlineSpan實(shí)現(xiàn)為文本添加下劃線,通過RemoveSpan方法可以移除下劃線,

但選擇范圍可能已包含下劃線片段的一部分,因此移除此下劃線片段后,需要重新添加下劃線片段,以實(shí)現(xiàn)部分移除的效果


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平臺中,字體粗細(xì)與斜體通過為EditableText對象設(shè)置StyleSpan實(shí)現(xiàn),與設(shè)置字體下劃線一樣,需要處理選擇范圍內(nèi)已包含StyleSpan的情況

TypefaceStyle提供了Normal、Bold、Italic、BoldItalic四種字體樣式,粗體+斜體樣式是通過組合實(shí)現(xiàn)的,因此需要處理樣式疊加問題


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);
}

序列化和反序列化

所見即所得的內(nèi)容需要被序列化和反序列化以便存儲或傳輸,我們?nèi)匀皇褂肏TML作為中間語言,好在Android和iOS平臺都有HTML互轉(zhuǎn)的對應(yīng)實(shí)現(xiàn)。

  • Android平臺中,Android.Text.Html提供了FromHtml()和Html.ToHtml(),
  • iOS中的NSAttributedStringDocumentAttributes提供了DocumentType屬性,可以設(shè)置為NSHTMLTextDocumentType,使用它初始化AttributedString或調(diào)用AttributedString.GetDataFromRange()方法實(shí)現(xiàn)HTML和NSAttributedString的互轉(zhuǎn)。

跨平臺實(shí)現(xiàn)

在Platform/Android目錄下創(chuàng)建HtmlParser.Android作為Android平臺序列化和反序列化的實(shí)現(xiàn)。

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目錄下創(chuàng)建HtmlParser.iOS作為iOS平臺序列化和反序列化的實(shí)現(xiàn)。

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;
    }
}

集成至編輯器

在所見即所得編輯器中設(shè)置兩個方法,一個用于獲取編輯器中的內(nèi)容,一個用于設(shè)置編輯器中的內(nèi)容。


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);
        }
    );

在富文本編輯器中的內(nèi)容,最終會生成一個帶有內(nèi)聯(lián)樣式的HTML字符串,如下所示:

[MAUI]寫一個跨平臺富文本編輯器

[MAUI]寫一個跨平臺富文本編輯器

創(chuàng)建控件

控件由所見即所得編輯器和工具欄組成,所見即所得編輯器用于顯示和編輯內(nèi)容,工具欄用于設(shè)置字號、顏色、加粗、斜體、下劃線

[MAUI]寫一個跨平臺富文本編輯器

創(chuàng)建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>

工具欄內(nèi)的按鈕橫向排列

<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>

[MAUI]寫一個跨平臺富文本編輯器

配置兩個選擇器:TextSizeCollectionView為字體大小選擇器,ColorCollectionView為字體顏色選擇器。

當(dāng)點(diǎn)擊字體大小選擇器時,彈出字體大小選擇器,當(dāng)點(diǎn)擊字體顏色選擇器時,彈出字體顏色選擇器。

[MAUI]寫一個跨平臺富文本編輯器

[MAUI]寫一個跨平臺富文本編輯器

<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>

后端代碼,綁定一些默認(rèn)值


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},
};

效果如下:

[MAUI]寫一個跨平臺富文本編輯器

使用控件

在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");
}

最終效果

[MAUI]寫一個跨平臺富文本編輯器

已知問題

  • HTML樣式會重復(fù)添加

項(xiàng)目地址

我在maui-sample項(xiàng)目中的一些控件,打算做成一個控件庫,方便大家使用??丶斓刂吩谙路?。

maui-sample項(xiàng)目作為控件庫孵化器,代碼可能會有點(diǎn)亂,也沒有經(jīng)過嚴(yán)格的測試。當(dāng)控件完善到一定程度,我會把控件封裝起來放到控件庫中。如果你有好的控件,歡迎pull request。

maui-sample:
Github:maui-samples

Mato.Maui控件庫
Mato.Maui文章來源地址http://www.zghlxwxcb.cn/news/detail-479369.html

到了這里,關(guān)于[MAUI]寫一個跨平臺富文本編輯器的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 一個基于.NET Core開源、跨平臺的倉儲管理系統(tǒng)

    一個基于.NET Core開源、跨平臺的倉儲管理系統(tǒng)

    今天給大家推薦一個基于.NET Core開源、跨平臺的倉儲管理系統(tǒng),數(shù)據(jù)庫支持MSSQL/MySQL:ZEQP.WMS。 倉儲管理系統(tǒng)(Warehouse Management System,WMS)是一種用于管理和控制倉庫操作的軟件系統(tǒng),它可以幫助企業(yè)實(shí)現(xiàn)對倉庫內(nèi)物品的跟蹤、存儲、揀選、包裝和發(fā)運(yùn)等全過程管理,提高倉

    2024年02月21日
    瀏覽(912)
  • 3 天,入門 TAURI 并開發(fā)一個跨平臺 ChatGPT 客戶端

    3 天,入門 TAURI 并開發(fā)一個跨平臺 ChatGPT 客戶端

    ? TAURI 是一個使用 Rust 編寫的程序框架,它允許我們使用 Web 技術(shù)和 Rust 語言構(gòu)建跨端應(yīng)用。它提供了大量特性,例如系統(tǒng)通知、網(wǎng)絡(luò)請求、全局快捷鍵、本地文件處理等,它們都可以在前端通過 JavaScript 便捷的調(diào)用。 TAURI 應(yīng)用的后端基于 Rust,這是一種內(nèi)存安全、性能出色

    2024年02月13日
    瀏覽(21)
  • C#一個開源跨平臺的 HTTP 客戶端庫——RestSharp

    C#一個開源跨平臺的 HTTP 客戶端庫——RestSharp

    GitHub - restsharp/RestSharp: Simple REST and HTTP API Client for .NET Simple REST and HTTP API Client for .NET. Contribute to restsharp/RestSharp development by creating an account on GitHub. https://github.com/restsharp/RestSharp ?????????在進(jìn)行軟件開發(fā)的時侯,你可能經(jīng)常需要使用一些公共的Web Api接口執(zhí)行 CRUD 操作;要

    2024年02月13日
    瀏覽(87)
  • 一個現(xiàn)代化輕量級的跨平臺Redis桌面客戶端

    大家好,我是 Java陳序員 。 Redis 作為一款高性能的非關(guān)系型數(shù)據(jù)庫,可是深受開發(fā)者的喜愛,無論是什么開發(fā),都能看到 Redis 的身影。 今天,給大家介紹一款跨平臺的 Redis 客戶端連接工具,功能強(qiáng)大,界面美觀! 關(guān)注微信公眾號:【Java陳序員】,獲取開源項(xiàng)目分享、AI副

    2024年04月08日
    瀏覽(90)
  • 一個基于.NET Core構(gòu)建的簡單、跨平臺、模塊化的商城系統(tǒng)

    一個基于.NET Core構(gòu)建的簡單、跨平臺、模塊化的商城系統(tǒng)

    今天大姚給大家分享一個基于.NET Core構(gòu)建的簡單、跨平臺、模塊化、完全開源免費(fèi)(MIT License)的商城系統(tǒng):Module Shop。 商品:分類、品牌、單位、選項(xiàng)(銷售屬性)、屬性、屬性模板、屬性組。 銷售:訂單、物流。 內(nèi)容:首頁配置、評論、回復(fù)。 配置:國家、用戶、倉庫

    2024年03月27日
    瀏覽(1132)
  • 探索 Vim:一個強(qiáng)大的文本編輯器

    探索 Vim:一個強(qiáng)大的文本編輯器

    引言: Vim(Vi IMproved)是一款備受推崇的文本編輯器,擁有強(qiáng)大的功能和高度可定制性,提供豐富的編輯和編程體驗(yàn)。本文將探討 Vim 的基本概念、使用技巧以及為用戶帶來的獨(dú)特優(yōu)勢。 1. Vim 的簡介和歷史 Vim(Vi Improved)是一個備受歡迎的文本編輯器,它是 Vi 編輯器的改進(jìn)

    2024年02月04日
    瀏覽(24)
  • 用QT/C++寫一個簡易文本編輯器

    用QT/C++寫一個簡易文本編輯器

    學(xué)習(xí)QT的小練習(xí),先看一下目前實(shí)現(xiàn)的效果。 ? 功能: 編輯文本保存為txt。 打開一個txt文本文件,可編輯可保存。 文本編輯功能:剪切,復(fù)制,粘貼,加粗,斜體,下劃線,設(shè)置顏色,字體。 要點(diǎn): QT Designer的UI可視化設(shè)計(jì):基本控件布局,資源導(dǎo)入,菜單動作,信號槽的

    2024年02月05日
    瀏覽(18)
  • 高級JavaScript。如何用JavaScript手?jǐn)]一個富文本編輯器?

    高級JavaScript。如何用JavaScript手?jǐn)]一個富文本編輯器?

    要素過多建議收藏 基本的技術(shù)就是在空白 HTML 文件中嵌入一個 iframe 。通過 designMode 屬性,可以將這個空白文檔變成可以編輯的,實(shí)際編輯的則是 body 元素 的 HTML 。 designMode 屬性有兩個可能的值: \\\"off\\\" (默認(rèn)值)和 \\\"on\\\" 。設(shè)置為 \\\"on\\\" 時,整個文檔 都會變成可以編輯的(顯示

    2024年01月21日
    瀏覽(27)
  • 【QT+QGIS跨平臺編譯】之七:【libjpeg+Qt跨平臺編譯】(一套代碼、一套框架,跨平臺編譯)

    【QT+QGIS跨平臺編譯】之七:【libjpeg+Qt跨平臺編譯】(一套代碼、一套框架,跨平臺編譯)

    libjpeg是一個廣泛使用的jpeg圖像壓縮和解壓的函數(shù)庫,采用 C 語言開發(fā)。 2013年1月,Independent JPEG Group發(fā)布了版本9,對新引入的無損編碼模式進(jìn)行了改進(jìn)。2022年1月,發(fā)布了版本9e,是唯一真正的源參考JPEG編解碼器。 【libjpeg跨平臺編譯】:Windows環(huán)境下編譯成果(支撐QGIS跨平臺

    2024年01月25日
    瀏覽(97)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包