14 Replies
      Latest reply on Apr 15, 2019 2:30 PM by ShinehahGnolaum
      ShinehahGnolaum Level 1 Level 1 (0 points)

        Why is the callback function pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? not showing the correct font.

         

        Here is my code:

         

        extension ViewController: UIPickerViewDelegate {
        
            func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {
                
                if component == 0 {
                    print(keysDataSource[row])
                    return keysDataSource[row]
                } else {
                    print(chordsDataSource[row])
                    return chordsDataSource[row]
                }
        
            }

         

        Here is the results in the debug window showing the result of the print statement when that callback function is called:

         

        vi{

            NSFont = "<UICTFont: 0x113d55700> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 30.00pt";

        }

         

        Here's the code to create the attributed strings:

         

        public let fontSizePickerView: CGFloat = 30

         

        func getFont(_ fontType: FontType, size: CGFloat) -> UIFont {
            var fontName: String
            switch fontType {
            case .timesNewRomanRegular:
                fontName = "TimesNewRomanPSMT"
            case .timesNewRomanBold:
                fontName = "TimesNewRomanPS-BoldMT"
            case .maestroWide:
                fontName = "MaestroWide"
            }
            return UIFont(name: fontName, size: size) ?? UIFont.systemFont(ofSize: size)
        }

         

        
        func makeAttributedText(_ text: String, fontSize: CGFloat) -> NSAttributedString? {
            
            print(text)
            
            let nsStringText: NSString = text as NSString
            var nsMutableAttributedText: NSMutableAttributedString = getMutableAttributedString(text, fontSize: fontSize)
            
            let fontSizeDiminished: CGFloat = fontSize * fontSizeRatioDiminished
            let fontSizeFlat: CGFloat = fontSize * fontSizeRatioFlat
            
            makeDiminishedAttribute(text: nsStringText, fontSize: fontSizeDiminished, baselineOffsetRatio: fontDiminishedBaselineOffset, mutableAttributedText: &nsMutableAttributedText)
            makeFlatAttribute(text: nsStringText, fontSize: fontSizeFlat, baselineOffsetRatio: fontFlatBaselineOffset, mutableAttributedText: &nsMutableAttributedText)
            
            return nsMutableAttributedText
            
        }
        
        func makeDiminishedAttribute(text: NSString, fontSize: CGFloat, baselineOffsetRatio: Double, mutableAttributedText: inout NSMutableAttributedString) {
            
            var nsRange: NSRange = text.range(of: "L")
            
            guard nsRange.length != 0 else {
                return
            }
            
            let baselineOffset: CGFloat = fontSize * CGFloat(baselineOffsetRatio)
            
            
            let attributesDiminished = getAttributesDiminished(fontSize: fontSize, baselineOffset: baselineOffset)
            
            repeat {
                
                mutableAttributedText.addAttributes(attributesDiminished, range: nsRange)
                if nsRange.location + 1 < text.length {
                    let nsRangeToCheck: NSRange = NSRange(location: nsRange.location + 1, length: text.length - (nsRange.location + 1))
                    nsRange = text.range(of: "L", range: nsRangeToCheck)
                    print(nsRangeToCheck)
                    print(nsRange)
                } else {
                    break
                }
                
            } while nsRange.length != 0
            
        }
        
        func makeFlatAttribute(text: NSString, fontSize: CGFloat, baselineOffsetRatio: Double, mutableAttributedText: inout NSMutableAttributedString) {
            
            var nsRange: NSRange = text.range(of: "b")
            
            guard nsRange.length != 0 else {
                return
            }
            
            let baselineOffset: CGFloat = fontSize * CGFloat(baselineOffsetRatio)
            
            let attributesFlat = getAttributesFlat(fontSize: fontSize, baselineOffset: baselineOffset)
            
            repeat {
                
                mutableAttributedText.addAttributes(attributesFlat, range: nsRange)
                if nsRange.location + 1 < text.length {
                    let nsRangeToCheck: NSRange = NSRange(location: nsRange.location + 1, length: text.length - (nsRange.location + 1))
                    nsRange = text.range(of: "b", range: nsRangeToCheck)
                    print(nsRangeToCheck)
                    print(nsRange)
                } else {
                    break
                
            } while nsRange.length != 0
            
        }
        
        
        let keysString: [String] = wheel.map() {
            item in
            item.key.name
        }
        let keysDataSource: [NSAttributedString] = {
            var arrayAttributedString = [NSAttributedString]()
            for string in keysString {
                if let attributedString = makeAttributedText(string, fontSize: fontSizePickerView) {
                    arrayAttributedString.append(attributedString)
                }
            }
            return arrayAttributedString
        }()
        let chordsString: [String] = ["I", "ii", "iii", "IV", "V", "vi", "viiL", "II (V of V)", "III (V of vi)"]
        let chordsDataSource: [NSAttributedString] = {
            var arrayAttributedString = [NSAttributedString]()
            for string in chordsString {
                if let attributedString = makeAttributedText(string, fontSize: fontSizePickerView) {
                    arrayAttributedString.append(attributedString)
                }
            }
            return arrayAttributedString
        }()
        
        
        • Re: Why is picker view not displaying attributed string?
          Claude31 Level 8 Level 8 (6,125 points)

          Do not see where you set the attributedString.

           

          Do you also use

           

          func pickerView(UIPickerView, titleForRow: Int, forComponent: Int) -> String?

           

          In that case, there may be conflict with the other delegte func.

            • Re: Why is picker view not displaying attributed string?
              ShinehahGnolaum Level 1 Level 1 (0 points)

              I am not using that function titleForRow. I didn’t include all the code, just the parts that are significant.

                • Re: Why is picker view not displaying attributed string?
                  Claude31 Level 8 Level 8 (6,125 points)

                  OK. So could you post the code where you defined and populated keysDataSource and chordsDataSource

                    • Re: Why is picker view not displaying attributed string?
                      ShinehahGnolaum Level 1 Level 1 (0 points)

                      Ok. I just added the code to the end of the original post.

                       

                      Thanks.

                        • Re: Why is picker view not displaying attributed string?
                          Claude31 Level 8 Level 8 (6,125 points)

                          I still do not see how you populate keysDataSource.

                           

                          Did you try all your functions (as makeAttributedText) in a simple UITextView (not in the picker) to check you effectively get the correct attributed String.

                           

                          I suspect you have an error there:

                           

                          func makeAttributedText(_ text: String, fontSize: CGFloat) -> NSAttributedString? {
                              
                              print(text)
                              
                              let nsStringText: NSString = text as NSString
                              var nsMutableAttributedText: NSMutableAttributedString = getMutableAttributedString(text, fontSize: fontSize)
                              
                              let fontSizeDiminished: CGFloat = fontSize * fontSizeRatioDiminished
                              let fontSizeFlat: CGFloat = fontSize * fontSizeRatioFlat
                              
                              makeDiminishedAttribute(text: nsStringText, fontSize: fontSizeDiminished, baselineOffsetRatio: fontDiminishedBaselineOffset, mutableAttributedText: &nsMutableAttributedText)
                              makeFlatAttribute(text: nsStringText, fontSize: fontSizeFlat, baselineOffsetRatio: fontFlatBaselineOffset, mutableAttributedText: &nsMutableAttributedText)
                              
                              return nsMutableAttributedText
                              
                          }

                          Line 11, you set nsMutableAttributedText as diminshed

                           

                          But at line 12 you set to flat.

                           

                          What do you really want to return ?

                            • Re: Why is picker view not displaying attributed string?
                              ShinehahGnolaum Level 1 Level 1 (0 points)

                              I tried the attributed text on a UILabel, and it worked, though I did not try it on a UITextView.

                               

                              I forgot to put the code for keyDataSource in the post. I got diverted by some technical difficulties.

                               

                              The functions makeDiminishedAttribute and makeFlatAttribute each looks at the nsStringText. The makeDiminishedAttribute looks for the character "L" in the nsStringText and assigns attributes to the attributed string at that range. The makeFlatAttribute looks for the character "b" and assigns attribute to the attributed string at that range.

                               

                              I'll put it there now. And thanks.

                                • Re: Why is picker view not displaying attributed string?
                                  Claude31 Level 8 Level 8 (6,125 points)

                                  OK, I did not look carefully enough at the code.

                                   

                                  In the original post, you wrote :

                                   

                                  Here is my code:

                                   

                                  extension ViewController: UIPickerViewDelegate { 
                                   
                                      func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? { 
                                           
                                          if component == 0 { 
                                              print(keysDataSource[row]) 
                                              return keysDataSource[row] 
                                          } else { 
                                              print(chordsDataSource[row]) 
                                              return chordsDataSource[row] 
                                          } 
                                   
                                      } 

                                  Here is the results in the debug window showing the result of the print statement when that callback function is called:

                                   

                                  vi{

                                      NSFont = "<UICTFont: 0x113d55700> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 30.00pt";

                                  }

                                   

                                  But the print should print Strings, not the style definition.

                                   

                                  Which print are you talking about ? Not sure it is the one in the picker delegate func.

                                   

                                  What are the output for the 2 components ?

                                  P¨lease report exactly what you get here.

                                    • Re: Why is picker view not displaying attributed string?
                                      ShinehahGnolaum Level 1 Level 1 (0 points)

                                      The print statements are in the pickerView(_:attributedTitleForRow:_:) callback function.

                                        • Re: Why is picker view not displaying attributed string?
                                          Claude31 Level 8 Level 8 (6,125 points)

                                          Did I miss something ?

                                           

                                          keysDataSource is an array of Strings.

                                           

                                          Does

                                                      print(keysDataSource[row])

                                           

                                          really print:

                                          vi{

                                              NSFont = "<UICTFont: 0x113d55700> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 30.00pt";

                                          }

                                           

                                          ????

                                          Surprising…

                                            • Re: Why is picker view not displaying attributed string?
                                              ShinehahGnolaum Level 1 Level 1 (0 points)

                                              Here's code from my post. keysDataSource is an array of NSAttributedString.

                                               

                                              let keysDataSource: [NSAttributedString] = {  
                                                  var arrayAttributedString = [NSAttributedString]()  
                                                  for string in keysString {  
                                                      if let attributedString = makeAttributedText(string, fontSize: fontSizePickerView) {  
                                                          arrayAttributedString.append(attributedString)  
                                                      }  
                                                  }  
                                                  return arrayAttributedString  
                                              }()
                                              
                                              

                                               

                                              I looked on Stack Overflow and aske the same question there. No one has an answer except a workaround that uses pickerView(_:viewForRow:forComponent:reusing:).

                                                • Re: Why is picker view not displaying attributed string?
                                                  Claude31 Level 8 Level 8 (6,125 points)

                                                  I want to focus on:

                                                      func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? { 
                                                           
                                                          if component == 0 { 
                                                              print(keysDataSource[row]) 
                                                              return keysDataSource[row] 
                                                          } else { 
                                                              print(chordsDataSource[row]) 
                                                              return chordsDataSource[row] 
                                                          } 

                                                  And know exactly what you get in print (the complete log, for all components).

                                                  There should be several lines of print.

                                                   

                                                  And could you tell as well what is the content of keysString and probably chordsStrings.

                                                  So, could you add somewhere in code

                                                  print("keysString", keysString)
                                                  print("keysDataSource", keysDataSource)
                                                  print("chordsStrings", chordsStrings)
                                                  print("chordsDataSource", chordsDataSource)

                                                   

                                                  and report exactly what you get.

                                                   

                                                  PLEASE, answer properly and completely if you want some help.

                                                   

                                                  NOTE: I tested witha picker example, and NSAttributedStrings ; it works perfectly well.

                                                  So, show the COMPLETE code of the class where the picker is defined, as well as a copy of the printed log.

                                                    • Re: Why is picker view not displaying attributed string?
                                                      ShinehahGnolaum Level 1 Level 1 (0 points)

                                                      Here is the new code I use based on your suggetion. I didn't follow exactly you recommendation, but I got the idea you meant to tell me.

                                                       

                                                          func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {
                                                      
                                                              print("attributedTitleForRow")
                                                              
                                                              if component == 0 {
                                                                  print("keysString[row]", keysString[row])
                                                                  print("keysDataSource[row]", keysDataSource[row])
                                                                  return keysDataSource[row]
                                                              } else {
                                                                  print("chordsString[row]", chordsString[row])
                                                                  print("chordsDataSource[row]", chordsDataSource[row])
                                                                  return chordsDataSource[row]
                                                              }
                                                      
                                                          }
                                                      
                                                      

                                                       

                                                      The picker view doesn't show the titles like they are intended for the formatting. It looks like all the attributes doesn't all show. They don't use the designated fonts. A system font is used instead. The baseline offset shows. Too bad I can't show you a screenshot. The print statements print what I expected.

                                                       

                                                      Here are the print results in the debug window when the app first launches:

                                                       

                                                      attributedTitleForRow

                                                      keysString[row] C

                                                      keysDataSource[row] C{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      keysString[row] G

                                                      keysDataSource[row] G{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      chordsString[row] I

                                                      chordsDataSource[row] I{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      chordsString[row] ii

                                                      chordsDataSource[row] ii{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      keysString[row] C

                                                      keysDataSource[row] C{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      keysString[row] G

                                                      keysDataSource[row] G{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      chordsString[row] I

                                                      chordsDataSource[row] I{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      chordsString[row] ii

                                                      chordsDataSource[row] ii{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      chordsString[row] I

                                                      chordsDataSource[row] I{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      chordsString[row] ii

                                                      chordsDataSource[row] ii{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      chordsString[row] iii

                                                      chordsDataSource[row] iii{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      chordsString[row] IV

                                                      chordsDataSource[row] IV{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      chordsString[row] V

                                                      chordsDataSource[row] V{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      chordsString[row] vi

                                                      chordsDataSource[row] vi{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      chordsString[row] I

                                                      chordsDataSource[row] I{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      keysString[row] C

                                                      keysDataSource[row] C{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      keysString[row] G

                                                      keysDataSource[row] G{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      keysString[row] D

                                                      keysDataSource[row] D{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      keysString[row] A

                                                      keysDataSource[row] A{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      keysString[row] Fb/E

                                                      keysDataSource[row] F{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }b{

                                                          NSBaselineOffset = "10.784375";

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e4b0> font-family: \"Maestro Wide\"; font-weight: normal; font-style: normal; font-size: 63.44pt";

                                                      }/E{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      keysString[row] Cb/B

                                                      keysDataSource[row] C{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }b{

                                                          NSBaselineOffset = "10.784375";

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e4b0> font-family: \"Maestro Wide\"; font-weight: normal; font-style: normal; font-size: 63.44pt";

                                                      }/B{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }

                                                      attributedTitleForRow

                                                      keysString[row] C

                                                      keysDataSource[row] C{

                                                          NSFont = "<UICTFont: 0x7fa1c6d5e170> font-family: \"Times New Roman\"; font-weight: normal; font-style: normal; font-size: 58.00pt";

                                                      }