XLPagerTabStrip
XLPagerTabStrip copied to clipboard
Is it possible to use autolayout for buttonBarItem width?
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
HI phillipp, did you manage to solve the issue?
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()
}
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
}
}
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
})