XLPagerTabStrip icon indicating copy to clipboard operation
XLPagerTabStrip copied to clipboard

Is it possible to use autolayout for buttonBarItem width?

Open phillippbertram opened this issue 6 years ago • 4 comments

Hi!

I'm trying out your lib, and I was wondering if it is possible to use auto layout to calculate the width of the current buttonBarItem. Currently I am using BaseButtonBarPagerTabStripViewController and specify buttonBarItemSpec with my custom nib file like following example:

buttonBarItemSpec = .nibFile(nibName: MyTabCell.reuseIdentifier, bundle: Bundle(for: MyTabCell.self)) { itemInfo in
            return 120
}

Unfortunately the width of my bar items will change while using the app, because I want provide some dynamic data to these items. Is there a way, to auto calculate and update the width using autolayout in the nib file?

Thanks in advance, phillipp

phillippbertram avatar Dec 18 '17 15:12 phillippbertram

HI phillipp, did you manage to solve the issue?

ahsanaasim avatar Apr 17 '18 14:04 ahsanaasim

Hi @ahsanaasim!

Yes more or less with an ugly workaround working for my suppose. I changed the visibility of cachedCellWidths and calculateWidths() in BaseButtonBarPagerTabStripViewController and write a layoutTabItems() method, that I have to call every time, any of these cells content is updated:

    /// Workaround for dynamic tab item width
    ///
    /// BaseButtonBarPagerTabStripViewController was modified to make
    /// `cachedCellWidths` and `calculateWidths` accessible
    /// This modification has to be made again after pod updates.
    fileprivate func layoutTabItems() {
        cachedCellWidths = calculateWidths()
        buttonBarView.reloadData()
    }

phillippbertram avatar Apr 20 '18 13:04 phillippbertram

I have used this extension to easily get the estimated width of a given string depending on the font :

extension UIFont {
    func sizeOfString(string: String, constrainedToHeight height: Double) -> CGSize {
        return NSString(string: string).boundingRect(
            with: CGSize(width: .greatestFiniteMagnitude, height: height),
            options: .usesLineFragmentOrigin,
            attributes: [.font: self],
            context: nil).size
    }   
}

Then, in my BaseButtonBarPagerTabStripViewController subclass :

    init() {
        super.init(nibName: nil, bundle: nil)
        buttonBarItemSpec = ButtonBarItemSpec.cellClass(width: { info in
            let title: String = info.title ?? ""
            let maxHeight: CGFloat = 60.0
            let font: UIFont = UIFont.customFont(forTextStyle: .body)
            let size: CGSize = font.sizeOfString(string: title, constrainedToHeight: maxHeight)
            return size.width + (12 * 2)
        })
    }

In case anyone is curious, the UIFont.customFont(forTextStyle: .body) part is defined as such to handle Accessibility size changes within all our app - just make sure to replace it with a UIFont configured like your custom ButtonBarItem label will be :

let customFonts: [UIFont.TextStyle: UIFont] = [
    .largeTitle: R.font.interBold(size: 32)!,
    .title1: R.font.interBold(size: 24)!,
    .title2: R.font.interSemiBold(size: 20)!,
    .title3: R.font.interRegular(size: 20)!,
    .headline: R.font.interBold(size: 16)!,
    .body: R.font.interRegular(size: 16)!,
    .callout: R.font.interBold(size: 14)!,
    .subheadline: R.font.interBold(size: 12)!,
    .footnote: R.font.interRegular(size: 13)!,
    .caption1: R.font.interSemiBold(size: 12)!,
    .caption2: R.font.interRegular(size: 12)!
]

extension UIFont {
    class func customFont(forTextStyle style: UIFont.TextStyle) -> UIFont {
        let customFont = customFonts[style]!
        let metrics = UIFontMetrics(forTextStyle: style)
        let scaledFont = metrics.scaledFont(for: customFont)
        return scaledFont
    }
}

jeannustre avatar Feb 14 '22 15:02 jeannustre

I made my workaround to calculate width for button bar items based on title content


// Calcualtion dynamic width through title



extension string { 
 func width(usingFont font: UIFont) -> CGFloat { let fontAttributes = [NSAttributedString.Key.font: font] let size = self.size(withAttributes: fontAttributes) return size.width } 
 
}
 
 
 // Usage buttonBarItemSpec = ButtonBarItemSpec.nibFile(nibName: Cell.identifier, bundle: Bundle(for: Cell.self), width: { info in guard let title = info.title else { return 0 } // Handle nil title if necessary // get width and add your padding if you want let dynamicWidth: CGFloat = title.width(usingFont: UIFont.bodySMedium()) + 50 return dynamicWidth

    })

ahmedMaher3 avatar Dec 03 '23 14:12 ahmedMaher3