SwiftUI - 自动滚动水平滚动视图以显示全文标签

Posted

技术标签:

【中文标题】SwiftUI - 自动滚动水平滚动视图以显示全文标签【英文标题】:SwiftUI - Autoscroll horizontal scrollview to show full text label 【发布时间】:2020-04-15 02:28:16 【问题描述】:

我有以下完美运行的代码。但是如果Titles 在滚动视图中特别可见并且用户单击可见的文本部分时,我无法解决的一个问题,我不仅想要选择标题我会就像 scollview 一样“自动滚动”,以便完整标题显示在滚动视图中,而仅显示部分文本。

import SwiftUI

struct CustomSegmentedPickerView: View 

  @State private var selectedIndex = 0
  private var titles = ["Round Trip", "One Way", "Multi-City", "Other"]
  private var colors = [Color.red, Color.green, Color.blue, Color.yellow]
  @State private var frames = Array<CGRect>(repeating: .zero, count: 4)

  var body: some View 

    VStack 

      ScrollView(.horizontal, showsIndicators: false) 

          ZStack 

            HStack(spacing: 10) 

              ForEach(self.titles.indices, id: \.self)  index in

                Button(action:  self.selectedIndex = index ) 

                    Text(self.titles[index])

                .padding(EdgeInsets(top: 16, leading: 20, bottom: 16, trailing: 20)).background(

                  GeometryReader  geo in

                    Color.clear.onAppear  self.setFrame(index: index, frame: geo.frame(in: .global)) 

                 )

             

          
          .background(

              Capsule().fill(self.colors[self.selectedIndex].opacity(0.4))
                  .frame(width: self.frames[self.selectedIndex].width,
                   height: self.frames[self.selectedIndex].height, alignment: .topLeading)
                  .offset(x: self.frames[self.selectedIndex].minX - self.frames[0].minX)
          , alignment: .leading

            )

         
         .animation(.default)
         .background(Capsule().stroke(Color.gray, lineWidth: 3))

         Picker(selection: self.$selectedIndex, label: Text("What is your favorite color?")) 

            ForEach(0..<self.titles.count)  index in

              Text(self.titles[index]).tag(index)

            

          .pickerStyle(SegmentedPickerStyle())

          Text("Value: \(self.titles[self.selectedIndex])")
          Spacer()

       

    

  

  func setFrame(index: Int, frame: CGRect) 

    self.frames[index] = frame

  




struct CustomSegmentedPickerView_Previews: PreviewProvider 

    static var previews: some View 

        CustomSegmentedPickerView()

    


【问题讨论】:

您可以尝试类似于SwiftUI: How to scroll List programmatically?中提供的方法 【参考方案1】:

试试这个:

struct ScrollText: View

    @State var scrollText: Bool = false

    var body: some View
    
        let textWidth: CGFloat = 460
        let titleWidth: CGFloat = 240.0
        let titleHeight: CGFloat = 70.0

        HStack
        
            ScrollView(.horizontal)
            
                Text("13. This is my very long text title for a tv show")
                    .frame(minWidth: titleWidth, minHeight: titleHeight, alignment: .center)
                    .offset(x: (titleWidth < textWidth) ? (scrollText ? (textWidth * -1) - (titleWidth / 2) : titleWidth ) : 0, y: 0)
                    .animation(Animation.linear(duration: 10).repeatForever(autoreverses: false), value: scrollText)
                    .onAppear 
                        self.scrollText.toggle()
                    
            
        
        .frame(maxWidth: titleWidth, alignment: .center)
    

可选:

如果您想计算文本宽度(而不是使用常量),那么您可以使用 GeometryReader(实时读取渲染对象的实际尺寸)

或者你可以使用UIKit来计算宽度(我使用这种方法,它非常依赖,可以在渲染发生之前实现计算)

将此扩展添加到您的代码中:

// String+sizeUsingFont.swift

import Foundation
import UIKit
import SwiftUI

extension String

    func sizeUsingFont(fontSize: CGFloat, weight: Font.Weight) -> CGSize
    
        var uiFontWeight = UIFont.Weight.regular
        
        switch weight 
        case Font.Weight.heavy:
            uiFontWeight = UIFont.Weight.heavy
        case Font.Weight.bold:
            uiFontWeight = UIFont.Weight.bold
        case Font.Weight.light:
            uiFontWeight = UIFont.Weight.light
        case Font.Weight.medium:
            uiFontWeight = UIFont.Weight.medium
        case Font.Weight.semibold:
            uiFontWeight = UIFont.Weight.semibold
        case Font.Weight.thin:
            uiFontWeight = UIFont.Weight.thin
        case Font.Weight.ultraLight:
            uiFontWeight = UIFont.Weight.ultraLight
        case Font.Weight.black:
            uiFontWeight = UIFont.Weight.black
        default:
            uiFontWeight = UIFont.Weight.regular
        
        
        let font = UIFont.systemFont(ofSize: fontSize, weight: uiFontWeight)
        let fontAttributes = [NSAttributedString.Key.font: font]
        return self.size(withAttributes: fontAttributes)
    

并像这样使用它:

let textWidth: CGFloat = "13. This is my very long text title for a tv show".sizeUsingFont(fontSize: 24, weight: Font.Weight.regular).width

当然把文本放在一个 var 中,改变字体大小和粗细来满足你的需要

如果您打算在 按钮的标签中使用此解决方案,我建议将 onAppear() 代码放入异步调用中,请参阅此答案:

aheze spot-on answer

【讨论】:

以上是关于SwiftUI - 自动滚动水平滚动视图以显示全文标签的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI/UIKit:水平滚动视图缩放视图

SwiftUI:水平滚动视图我能够上下拉图像

SwiftUI URLImage 水平滚动视图

在 SwiftUi 中水平组合和打破垂直滚动视图?

SwiftUi 水平滚动视图,带有来自 Api 的数据

如何以任何文本长度自动水平滚动文本视图?