ScrollView中的SwiftUI文本,无法在两个轴上滚动

时间:2019-10-28 14:58:06

标签: ios swift swiftui

我有大量的文本,希望在Text()视图中显示。如果将视图包装在ScrollView中,则可以向.horizontal.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)
        }
    }
}

是否有更好的方法来解决这个问题,还是仅仅是目前没有解决方法的bug?我唯一的其他想法是使用包装的UITextView,该包装仅允许垂直滚动,但是如果有一种方法可以手动将帧宽度设置为必要的大小,则允许ScrollView只能水平滚动。

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

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

但是,这只能允许一次感觉不自然的方向滚动。

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

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

1 个答案:

答案 0 :(得分:1)

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

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

                }

            }