-->

How to resize textLabel in segmented control in Sw

2019-08-30 06:18发布

问题:

In a UIViewController there is a Segmented Controller placed at the top of the view. Constraints: left: 0, right:0, top: 0, height:90.

Every time a UIApplicationDidBecomeActive notification is posted, segmented control should update it's view with the newest date by calling func updateUI()

On first load, when viewDidLoad is called the text in each segment is displayed as expected.
However, if the app goes in background, when it comes back in foreground, the label of the segmented control does not accommodate the text and shows 3 dots... after. See attachment and gif below.

Scope: update segmented control title for each segment every time .UIApplicationDidBecomeActive notification is posted. Public Github project https://github.com/bibscy/testProject

 class ViewController: UIViewController {

   var stringDates = [String]()

   var dateNow: Date {
     return Date()
   }
      @IBOutlet weak var segmentedControl: UISegmentedControl!

       func updateUI() {
    //create string dates and set the title of for each segment in segmented control
          self.getNextDays()  
     }

   override func viewDidLoad() {
      super.viewDidLoad()

      NotificationCenter.default.addObserver(self, selector: #selector(updateUI), name: .UIApplicationDidBecomeActive, object: nil)

     UILabel.appearance(whenContainedInInstancesOf: [UISegmentedControl.self]).numberOfLines = 0

      self.getNextDays()
   }
}


  extension ViewController {

//for each segment, construct a string date with the currentDate() being first, followed by 5 consecutive days
func getNextDays()  {

    stringDates.removeAll() //clear any previous data

    for i in 0...5 {
        let dateFormatter = DateFormatter()
        let today = dateNow
        let calendar = Calendar.current

        if i == 0 {
            let dayComponent = Calendar.current.component(.weekday,from: today)
            let day = Calendar.current.component(.day, from: today) //Int
            let dayString = dateFormatter.shortWeekdaySymbols[dayComponent-1] //Symbol


            let month = Calendar.current.component(.month, from: today)
            let monthSymbol = dateFormatter.shortMonthSymbols[month-1]
            let dayMonthString =  dayString + " " + String(day) + " " + monthSymbol
            stringDates.append(dayMonthString)


        } else {
            var components = DateComponents()
            components.weekday = i

            let nextDay = calendar.date(byAdding: components, to: today)
            let nextDayComponent = Calendar.current.component(.weekday,from: nextDay!)
            let day = Calendar.current.component(.day, from: nextDay!)
            let dayString = dateFormatter.shortWeekdaySymbols[nextDayComponent-1] // Symbol


            let month = Calendar.current.component(.month, from: nextDay!)
            let monthSymbol = dateFormatter.shortMonthSymbols[month-1]
            let dayMonthString = dayString + " " + String(day) + " " + monthSymbol
            stringDates.append(dayMonthString)
        }
    }


      //set the title for each segment from stringDates array
       for value in 0...5 {
         self.segmentedControl.setTitle(self.stringDates[value], forSegmentAt: value)
      }
   } //end of getNextDays()  
}

回答1:

The problem is only reproduced in 10.3 iOS version. Solution:

Store initial properties of a segmented label:

fileprivate var height: CGFloat! 
fileprivate var width: CGFloat!

Add to ViewDidLoad just before getNextDays:

let label = segmentedControl.subviews[0].subviews[0] as! UILabel 
height = label.frame.height 
width = label.frame.width

Set text :

for value in 0...5 {
   segmentedControl.setTitle(stringDates[value], forSegmentAt: value)
}

And fix frames after that:

let labels = segmentedControl.subviews.map{ $0.subviews[1] } as! [UILabel]
    labels.forEach { (label) in
        label.numberOfLines = 0
        let frame = label.frame
        label.frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: width, height: height)
    }

Sample code with some crash protection