danielsaidi / RichTextKit

RichTextKit is a Swift SDK that helps you use rich text in Swift and SwiftUI.
MIT License
944 stars 126 forks source link

How do I get content, including text and images #72

Closed chinaTLJ closed 1 year ago

chinaTLJ commented 1 year ago

I want to put them in the database so I can show them next time My code is : RichTextEditor(text: $text,context: richTextContext) richTextContext.pasteImage(x,x,x)

How do I get content, including text and images?

danielsaidi commented 1 year ago

Hi @chinaTLJ

I'd say you'd be better off just storing the attributed string.

NateLaw86 commented 1 year ago

Hi,

I'm running into the same issue as @chinaTLJ. I'm still fairly new to swift, so can you explain how we'd store the attributed string and still be able to read the text with its associated formatting elsewhere in the code? Would we store it as a struct?

Also, thanks @danielsaidi for the awesome kit! Everything else is looking and working great so far in my app.

danielsaidi commented 1 year ago

Hi @NateLaw86

The attributed string is the text binding that is passed into the text field when you create it, and updates as you edit the text in the text field.

The library has ways to let you access the string as a native NSAttributedString, or get it as raw data in various formats (an archive with the images included, RTF with just the formatting, plain text etc.).

If you want to parse the content of the string, you can iterate over it and get the various attributes, attachments etc. But rich text is (in my opinion) a nightmare, so I tend to only store the string as is :)

NateLaw86 commented 1 year ago

Thanks @danielsaidi, for the insight. Could you elaborate on how to access the string as a native NSAttributedString? I've tried accessing the text using "RichTextWindow.editor" but that hasn't been working. Should I be calling the "EditorScreen" struct instead?

Also is there a way to access a specific string if I'm using multiple instances of the rich text editor? For example, I'd like to use the rich text editor on multiple pages of my app and save the text that was input into those textboxes so I can display that text in another view.

danielsaidi commented 1 year ago

Sure, I'll try :) The binding actually doesn't update all the time, since that causes SwiftUI to update the view, which resets things like cursor position and kills performance.

However, the underlying view has a text property that you can access at any time. I think I'll try to expose that property somehow, to make this easier.

chinaTLJ commented 1 year ago

Hi @danielsaidi ,I want to save textNS,but it didn't work,help me ,thanks!textNS contains the inserted picture,mybe richTextContext contains the inserted picture,I use this:richTextContext.pasteImage() how to save textNS into database Realm? RichTextEditor(text: $textNS,context: richTextContext) .onChange(of: textNS) { newValue in //把text转成attributedStringData if let attributedStringData:Data = try? textNS.data(from: NSRange(location: 0, length: textNS.length), documentAttributes: [.documentType: NSAttributedString.DocumentType.rtf]) { //初始化数据库 let realm = try! Realm() var cs=String(data: attributedStringData, encoding: .utf8) print("存的cs=(cs)") item.content=cs ?? "默认" try! realm.write { realm.add(item) } }
}

chinaTLJ commented 1 year ago

Hi @danielsaidi ,why textNS changed in onAppear,but UI do not refresh

@State private var textNS = NSAttributedString(string: "") RichTextEditor(text: $textNS,context: richTextContext) .onAppear(perform: { let realm = try! Realm() let items = realm.objects(ItemNoteBean.self) let data = item.contentData//contentData is a Data type if let attributedString = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? NSAttributedString { textNS = attributedString //why textNS changed here,but UI do not refresh }else{

            }
                        })
DavidAlvarezDev commented 1 year ago

I think you need to set a property on the context for the view to updateSent from my iPhoneOn Aug 30, 2023, at 10:21 AM, xiaohuanxiong @.***> wrote: Hi @danielsaidi ,why textNS changed in onAppear,but UI do not refresh @State private var textNS = NSAttributedString(string: "") RichTextEditor(text: $textNS,context: richTextContext) .onAppear(perform: { let realm = try! Realm() let items = realm.objects(ItemNoteBean.self) let data = item.contentData//contentData is a Data type if let attributedString = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? NSAttributedString { textNS = attributedString //why textNS changed here,but UI do not refresh }else{ } })

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you are subscribed to this thread.Message ID: @.***>

NateLaw86 commented 1 year ago

Thanks for the feedback @danielsaidi. I found the text and context properties in the underlying "EditorScreen" view but still can't figure out how to get the "text" property itself. I see that it's set to a private var, which means we're unable to access this variable outside of the view, right? Is there still a way to get the text property from another view?

From my understanding this is the property you're intending to expose to make the it more accessible, but can you show how to access the text without this added feature/the "original" way?

danielsaidi commented 1 year ago

Hey @NateLaw86 and @chinaTLJ - sorry for the late reply regarding this and thanks @DavidAlvarezDev for helping.

Can't you just use the raw binding that you pass into the TextEditor?

I tried adding a Text element to the demo app, that just shows the current text binding's (an NSAttributedString) raw string value:

image

And it seems to update properly:

image

So you should be able to just use the raw NSAttributedString binding that you set up the editor with, and do what you want with the value.

chinaTLJ commented 1 year ago

@danielsaidi You may not understand what I mean, Look at my code down ,Once on the page, I assign textNS a value in the onAppear method, but the page renders with no value. My scenario is that as soon as I enter the page, I will fetch the data in the database and display it on the RichTextEditor.

@State private var textNS = NSAttributedString(string: "") RichTextEditor(text: $textNS, context: richTextContext) .onChange(of: textNS) { newValue in let data = try! NSKeyedArchiver.archivedData(withRootObject: textNS, requiringSecureCoding: false)

                            let realm = try! Realm()

                            if item.title.isEmpty&&item.contentData.isEmpty{

                                item.contentData=data
                                try! realm.write {
                                    realm.add(item)//save in to db
                                }
                            }else{
                                try! realm.write {
                                    item.contentData=data//update db 
                                }
                            }

} .onAppear(perform: { let realm = try! Realm() let items = realm.objects(ItemNoteBean.self) let data = item.contentData//contentData is a Data type if let attributedString = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? NSAttributedString { textNS = attributedString //why textNS changed here, but UI do not refresh,This will be executed before the page is rendered // If I test it in Text, it's fine, So I don't know if I'm having a problem assigning values here } })

danielsaidi commented 1 year ago

Ooooh, I see! Yes, one current limitation is that the text editor won't sync if the text binding value changes after setting up the editor.

Here, I've tapped the button to update the text binding, but only the text element updates:

The reason why changing the binding won't affect the text UI is that it killed performance, and caused the editor to reset every time text changes...which means even when typing in the editor.

I guess it would be nice to have a context function to replace the text and update the editor.

chinaTLJ commented 1 year ago

Ooooh, I see! Yes, one current limitation is that the text editor won't sync if the text binding value changes after setting up the editor.

Here, I've tapped the button to update the text binding, but only the text element updates:

The reason why changing the binding won't affect the text UI is that it killed performance, and caused the editor to reset every time text changes...which means even when typing in the editor.

I guess it would be nice to have a context function to replace the text and update the editor.

Yes,How to solve this problem? I really need this feature, please, How to write code in the function .

danielsaidi commented 1 year ago

@chinaTLJ

There is a function in the context, that lets you do this:

context.setAttributedString(to: "Something else")

I am adding an attributedString to the context as well, so you can always read it from there as well.

danielsaidi commented 1 year ago

This has been pushed to the main branch.

minhtien1403 commented 1 year ago

@danielsaidi, I have a string have multi font size, I'm use context.attributedString to get the string then I use context.setAttributedString(), the font size of text now change. Do you have any solution to keep the font size Here is my code func get() { temp = context.attributedString } func set() { context.setAttributedString(to: temp) } | | |

danielsaidi commented 1 year ago

Hi @minhtien1403

Font sizes currently behave quite flaky. I'd love help on this, since I don't have a lot of time to focus on this library atm.

Since this issue is closed, would you mind opening a new issue with the same information?