SwiftUI Текст внутри ScrollView, невозможно прокрутить по обеим осям - PullRequest
0 голосов
/ 28 октября 2019

У меня большой объем текста, который я хотел бы отобразить в виде 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)
        }
    }
}

Есть ли лучший подход к этому или это просто ошибка, которая в настоящее время не имеет обходного пути? Моя единственная другая мысль - использовать обернутый 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 Ответ

1 голос
/ 28 октября 2019

Если у вас нет умного способа, вот глупый. Вы можете добавить условия для адаптации к разным классам размеров.

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

}

Полный код метода выравнивания выглядит следующим образом:

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

                }

            }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...