LiYanan2004 / MarkdownView

Rendering Markdown text natively in SwiftUI.
https://liyanan2004.github.io/MarkdownView/documentation/markdownview/
MIT License
195 stars 18 forks source link

Markdown view blink when text is short #24

Closed hugo53 closed 5 months ago

hugo53 commented 1 year ago

Hi @LiYanan2004,

I just found an issue that markdown view blink while scrolling with short text. I guess the width has been recalculated somewhere. Please check below video for more details.

To Reproduce Let use this code to reproduce:

import SwiftUI
import MarkdownView

struct ContentView: View {

    let textShort = """
    Hello 123
    """

    @State private var onHover = false
    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(0..<100, id: \.self) { i in
                    HStack {
                        MarkdownView(text: textShort)
                            .padding()
                            .background(.blue)
                            .frame(alignment: .leading)
                        Spacer()
                    }
                }
            }
        }
    }
}

Expected behavior Markdown view should not blink with short text

Screenshots

https://github.com/LiYanan2004/MarkdownView/assets/1033299/4193f1c3-0ccb-4c98-9cad-fadf5563f22e

Environment:

LiYanan2004 commented 1 year ago

This is because you’re using a LazyVStack.

When MarkdownView enters visible area, system will construct a new one, vice versa.

LiYanan2004 commented 1 year ago

Updated the implementation. Try it out by switching to main branch. @hugo53

hugo53 commented 1 year ago

Wow, super fast @LiYanan2004, let me try now.

LiYanan2004 commented 1 year ago

Is that works?

hugo53 commented 1 year ago

@LiYanan2004 I checked main branch, still have little blink with LazyVStack but much better now. Please check below video.

https://github.com/LiYanan2004/MarkdownView/assets/1033299/84ab046c-375f-40a8-8510-795682937bae

LiYanan2004 commented 1 year ago

It’s reasonable. Because MarkdownView’s rendering pipeline is asynchronous. So if the element enters, system creates MarkdownView. MarkdownView creates a placeholder view and parses content asynchronously and then renders the view.

You can fix this by using VStack instead of LazyVStack. Now, MarkdownViews will be created altogether and they’ll not be recreated again and again when scrolling.

LiYanan2004 commented 1 year ago

Tip: If you want to take up full width, you can set markdownViewRole to .editor

hugo53 commented 1 year ago

@LiYanan2004

You can fix this by using VStack instead of LazyVStack

I got it but in some cases we may need to use LazyVStack to avoid performance issue, for example when we have large amount of items.

Tip: If you want to take up full width, you can set markdownViewRole to .editor

Thank you, let me try

LiYanan2004 commented 1 year ago

I got it but in some cases we may need to use LazyVStack to avoid performance issue, for example when we have large amount of items.

You're right.

In this case, when MarkdownView has been initialized, it will start an async parser to parse and generate view. This is the cause of the "blink" which is probably the expected behavior.

In your case, you may need to specify width via .frame(maxWidth: .infinity) or .markdownViewRole(.editor) to solve this issue (Because each row has only one element on the horizontal axis)

LiYanan2004 commented 5 months ago

Hi @hugo53.

I just published a new version which added support for rendering content in main thread. Your problem should be fixed by adopting that feature (via .markdownRenderingThread(.main)).

But be careful when using that feature if the content is very complex, or it'll leads to the performance issue because very thing will run on main thread.

If that improvements helps, you should close this issue😁

LiYanan2004 commented 5 months ago

If there’s no further responses, I’ll close this issue marked as fixed.