ios - ScrollView 内的 SwiftUI 文本,无法在两个轴上滚动

标签 ios swift swiftui

我有大量文本,想在 Text() View 中显示。如果我将 View 包裹在 ScrollView 中,我可以在 .horizo​​ntal.vertical 方向上滚动。

但是如果我想在两个方向上滚动,布局就完全错误了。几乎就像有一个负偏移量。

import SwiftUI

struct ContentView: View {
    let text = """
    <?xml version="1.0"?>
    <PrettyXML>
    <root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:dlna="urn:schemas-dlna-org:device-1-0">
      <specVersion>
        <major>1</major>
        <minor>0</minor>
      </specVersion>
      <device>
        <deviceType>urn:schemas-upnp-org:device:MediaRenderer:2</deviceType>
        <friendlyName>Sample Renderer</friendlyName>
        <manufacturer></manufacturer>
        <manufacturerURL></manufacturerURL>
        <modelDescription/>
        <modelName>Test device</modelName>
        <modelNumber/>
        <modelURL></modelURL>
        <serialNumber>12354-12312789-123987129873</serialNumber>
        <UDN>uuid:12312311-1234-1234-1234-123456789011</UDN>
        <iconList>
          <icon>
            <mimetype>image/png</mimetype>
            <width>120</width>
            <height>120</height>
            <depth>24</depth>
            <url>/image-120x120x24.png</url>
          </icon>
          <icon>
            <mimetype>image/png</mimetype>
            <width>48</width>
            <height>48</height>
            <depth>24</depth>
            <url>/image-48x48x24.png</url>
          </icon>
          <icon>
            <mimetype>image/jpeg</mimetype>
            <width>120</width>
            <height>120</height>
            <depth>24</depth>
            <url>/image-120x120x24.jpg</url>
          </icon>
          <icon>
            <mimetype>image/jpeg</mimetype>
            <width>48</width>
            <height>48</height>
            <depth>24</depth>
            <url>/image-48x48x24.jpg</url>
          </icon>
        </iconList>
        <serviceList>
          <service>
            <serviceType>urn:schemas-upnp-org:service:ConnectionManager:2</serviceType>
            <serviceId>urn:upnp-org:serviceId:ConnectionManager</serviceId>
            <SCPDURL>/xml/ConnectionManager.xml</SCPDURL>
            <controlURL>/Control/ConnectionManager</controlURL>
            <eventSubURL>/Event/ConnectionManager</eventSubURL>
          </service>
          <service>
            <serviceType>urn:schemas-upnp-org:service:AVTransport:2</serviceType>
            <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId>
            <SCPDURL>/xml/AVTransport2.xml</SCPDURL>
            <controlURL>/Control/AVTransport</controlURL>
            <eventSubURL>/Event/AVTransport</eventSubURL>
          </service>
          <service>
            <serviceType>urn:schemas-upnp-org:service:RenderingControl:2</serviceType>
            <serviceId>urn:upnp-org:serviceId:RenderingControl</serviceId>
            <SCPDURL>/xml/RenderingControl2.xml</SCPDURL>
            <controlURL>/Control/Renderer/RygelRenderingControl</controlURL>
            <eventSubURL>/Event/Renderer/RygelRenderingControl</eventSubURL>
          </service>
        </serviceList>
        <presentationURL>http://10.0.0.1:80/</presentationURL>
        <dlna:X_DLNADOC>DMR-1.51</dlna:X_DLNADOC>
      </device>
    </root>
    """

    var body: some View {
//        ScrollView(.horizontal) {
//        ScrollView(.vertical) {
        ScrollView([.horizontal, .vertical]) {
            Text(text)
        }
    }
}

是否有更好的方法来解决这个问题,或者它只是一个目前没有解决方法的错误?我唯一的其他想法是使用包装的 UITextView,它只允许垂直滚动,但如果有办法手动将框架宽度设置为尽可能大,则允许 ScrollView 仅水平滚动。

解决这个问题的一个非常丑陋的方法是:

ScrollView(.horizontal, showsIndicators: false) {
  ScrollView(.vertical, showsIndicators: false) {
    Text(text)
  }
}

然而,这只允许一次向一个方向滚动,感觉不自然。

似乎这种行为也与更新 View 有关。考虑以下模拟重绘的示例:

struct ContentView: View {
    @State var labelText = "Loading"

    let text = """
    <?xml version="1.0"?>
    <PrettyXML>
    <root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:dlna="urn:schemas-dlna-org:device-1-0">
      <specVersion>
        <major>1</major>
        <minor>0</minor>
      </specVersion>
      <device>
        <deviceType>urn:schemas-upnp-org:device:MediaRenderer:2</deviceType>
        <friendlyName>Sample Renderer</friendlyName>
        <manufacturer></manufacturer>
        <manufacturerURL></manufacturerURL>
        <modelDescription/>
        <modelName>Test device</modelName>
        <modelNumber/>
        <modelURL></modelURL>
        <serialNumber>12354-12312789-123987129873</serialNumber>
        <UDN>uuid:12312311-1234-1234-1234-123456789011</UDN>
        <iconList>
          <icon>
            <mimetype>image/png</mimetype>
            <width>120</width>
            <height>120</height>
            <depth>24</depth>
            <url>/image-120x120x24.png</url>
          </icon>
          <icon>
            <mimetype>image/png</mimetype>
            <width>48</width>
            <height>48</height>
            <depth>24</depth>
            <url>/image-48x48x24.png</url>
          </icon>
          <icon>
            <mimetype>image/jpeg</mimetype>
            <width>120</width>
            <height>120</height>
            <depth>24</depth>
            <url>/image-120x120x24.jpg</url>
          </icon>
          <icon>
            <mimetype>image/jpeg</mimetype>
            <width>48</width>
            <height>48</height>
            <depth>24</depth>
            <url>/image-48x48x24.jpg</url>
          </icon>
        </iconList>
        <serviceList>
          <service>
            <serviceType>urn:schemas-upnp-org:service:ConnectionManager:2</serviceType>
            <serviceId>urn:upnp-org:serviceId:ConnectionManager</serviceId>
            <SCPDURL>/xml/ConnectionManager.xml</SCPDURL>
            <controlURL>/Control/ConnectionManager</controlURL>
            <eventSubURL>/Event/ConnectionManager</eventSubURL>
          </service>
          <service>
            <serviceType>urn:schemas-upnp-org:service:AVTransport:2</serviceType>
            <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId>
            <SCPDURL>/xml/AVTransport2.xml</SCPDURL>
            <controlURL>/Control/AVTransport</controlURL>
            <eventSubURL>/Event/AVTransport</eventSubURL>
          </service>
          <service>
            <serviceType>urn:schemas-upnp-org:service:RenderingControl:2</serviceType>
            <serviceId>urn:upnp-org:serviceId:RenderingControl</serviceId>
            <SCPDURL>/xml/RenderingControl2.xml</SCPDURL>
            <controlURL>/Control/Renderer/RygelRenderingControl</controlURL>
            <eventSubURL>/Event/Renderer/RygelRenderingControl</eventSubURL>
          </service>
        </serviceList>
        <presentationURL>http://10.0.0.1:80/</presentationURL>
        <dlna:X_DLNADOC>DMR-1.51</dlna:X_DLNADOC>
      </device>
    </root>
    """


    var body: some View {
         ScrollView([.horizontal, .vertical]) {
            Text(self.labelText)
         }
         .onAppear() {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
                self.labelText = self.text
            }
        }
    }
}

最佳答案

如果您没有聪明的方法,这里有一个愚蠢的方法。您可以添加条件以适应不同的尺寸等级。

struct ContentView: View {
  let text = "" /// Your long multiline text

  var body: some View {
    GeometryReader { (geometry: GeometryProxy) in
      ScrollView([.horizontal, .vertical]) {
        VStack {
          Spacer(minLength: geometry.size.height)
          HStack {
            Spacer(minLength: geometry.size.width)
            Text(self.text)
          }
        }
      }
    }
  }
}

更好的方法是添加一个 viewModifier,它使事情自动化。

struct ContentView: View {
  let text = "" // Your multiline text 

  var body: some View {
    GeometryReader { p in
      ScrollView([.horizontal, .vertical]) {
        Text(self.text)
          .modifier(SimpleOffset(frameSize: p.size))
      }
    }
  }
}

struct SimpleOffset: GeometryEffect {
  var frameSize: CGSize
  func effectValue(size: CGSize) -> ProjectionTransform {
    ProjectionTransform(CGAffineTransform(translationX: (size.width - frameSize.width) / 2, y: (size.height - frameSize.height) / 2))
  }
}

这是纯对齐的解决方案。

 var body: some View {

     ScrollView([.horizontal, .vertical]) {
        Text(self.text).alignmentGuide(HorizontalAlignment.center) { (v) -> CGFloat in
            return (v[HorizontalAlignment.center] + v[.leading]) / 2
        }.alignmentGuide(VerticalAlignment.center) { (v) -> CGFloat in
            return (v[VerticalAlignment.center] + v[.top]) / 2
        }.frame(alignment: .center )
     }

}

align方法的完整代码如下:

            struct ContentView: View {


                let text = """
                <?xml version="1.0"?>
                <PrettyXML>
                <root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:dlna="urn:schemas-dlna-org:device-1-0">
                  <specVersion>
                    <major>1</major>
                    <minor>0</minor>
                  </specVersion>
                  <device>
                    <deviceType>urn:schemas-upnp-org:device:MediaRenderer:2</deviceType>
                    <friendlyName>Sample Renderer</friendlyName>
                    <manufacturer></manufacturer>
                    <manufacturerURL></manufacturerURL>
                    <modelDescription/>
                    <modelName>Test device</modelName>
                    <modelNumber/>
                    <modelURL></modelURL>
                    <serialNumber>12354-12312789-123987129873</serialNumber>
                    <UDN>uuid:12312311-1234-1234-1234-123456789011</UDN>
                    <iconList>
                      <icon>
                        <mimetype>image/png</mimetype>
                        <width>120</width>
                        <height>120</height>
                        <depth>24</depth>
                        <url>/image-120x120x24.png</url>
                      </icon>
                      <icon>
                        <mimetype>image/png</mimetype>
                        <width>48</width>
                        <height>48</height>
                        <depth>24</depth>
                        <url>/image-48x48x24.png</url>
                      </icon>
                      <icon>
                        <mimetype>image/jpeg</mimetype>
                        <width>120</width>
                        <height>120</height>
                        <depth>24</depth>
                        <url>/image-120x120x24.jpg</url>
                      </icon>
                      <icon>
                        <mimetype>image/jpeg</mimetype>
                        <width>48</width>
                        <height>48</height>
                        <depth>24</depth>
                        <url>/image-48x48x24.jpg</url>
                      </icon>
                    </iconList>
                    <serviceList>
                      <service>
                        <serviceType>urn:schemas-upnp-org:service:ConnectionManager:2</serviceType>
                        <serviceId>urn:upnp-org:serviceId:ConnectionManager</serviceId>
                        <SCPDURL>/xml/ConnectionManager.xml</SCPDURL>
                        <controlURL>/Control/ConnectionManager</controlURL>
                        <eventSubURL>/Event/ConnectionManager</eventSubURL>
                      </service>
                      <service>
                        <serviceType>urn:schemas-upnp-org:service:AVTransport:2</serviceType>
                        <serviceId>urn:upnp-org:serviceId:AVTransport</serviceId>
                        <SCPDURL>/xml/AVTransport2.xml</SCPDURL>
                        <controlURL>/Control/AVTransport</controlURL>
                        <eventSubURL>/Event/AVTransport</eventSubURL>
                      </service>
                      <service>
                        <serviceType>urn:schemas-upnp-org:service:RenderingControl:2</serviceType>
                        <serviceId>urn:upnp-org:serviceId:RenderingControl</serviceId>
                        <SCPDURL>/xml/RenderingControl2.xml</SCPDURL>
                        <controlURL>/Control/Renderer/RygelRenderingControl</controlURL>
                        <eventSubURL>/Event/Renderer/RygelRenderingControl</eventSubURL>
                      </service>
                    </serviceList>
                    <presentationURL>http://10.0.0.1:80/</presentationURL>
                    <dlna:X_DLNADOC>DMR-1.51</dlna:X_DLNADOC>
                  </device>
                </root>
                """


                var body: some View {

                     ScrollView([.horizontal, .vertical]) {
                        Text(self.text).alignmentGuide(HorizontalAlignment.center) { (v) -> CGFloat in
                            return (v[HorizontalAlignment.center] + v[.leading]) / 2
                        }.alignmentGuide(VerticalAlignment.center) { (v) -> CGFloat in
                            return (v[VerticalAlignment.center] + v[.top]) / 2
                        }.frame(alignment: .center )
                     }

                }

            }

关于ios - ScrollView 内的 SwiftUI 文本,无法在两个轴上滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58593267/

相关文章:

arrays - UITableViewCell 如何知道要从数组或字典加载什么 JSON

ios - 在 SwiftUI 中推送新 View 时隐藏 TabBar

ios - 具有多个 bundle ID 的 FaSTLane 匹配与多个团队

ios - 故意造成 CPU 使用率过高

swift - 奇怪的编译器错误 : 'expectation' produces 'XCTestExpectation' , 不是预期的上下文结果类型 'XCTestExpectation'

swift - 如何从其他自定义 UICollectionViewCell 引用 UICollectionView

ios - 我的 iPhone 应用程序使用 Facebook SDK for iOS v2.0。我的应用程序会在 2013 年 6 月损坏吗?

ios - RedPark 串行电缆部分数据

Swiftui:@environmentObject - 不能在属性初始值设定项中使用实例成员;属性初始值设定项在 'self' 可用之前运行

ios - 防止 SwiftUI NavigationLink 继承重写的 preferredColorScheme