How do I enable UILargeContentViewerInteraction on UITabBar outside of UITabBarController?

UILargeContentViewerInteraction, added in iOS 13, works out of the box on the tab bar in a UITabBarController, and it's easy to set up on a custom view using the UILargeContentViewerItem properties on UIView. But how do I set it up on a UITabBar that's not connected to a UITabBarController? There don't appear to be any relevant properties on UITabBarItem.

To try this, I made a sample app, added a tab bar, set up some items, set their largeContentSizeImage properties for good measure, ran the app, set text size to a large accessibility value, and long-pressed on the items, and I get no large content viewer.

I also tried adding a UILargeContentViewerInteraction to the tab bar, and implemented the viewControllerForInteraction method in the delegate.

Thanks for posting about your experience using UILargeContentViewer with UITabBar, could you please file a report using Feedback Assistant and upload your sample project? https://developer.apple.com/bug-reporting/

Please post your feedback ID here when you get the chance so we can take a closer look. Thanks!

Unfortunately, UILargeContentViewerInteraction is not currently supported on tab bar items in a standalone UITabBar. Thank you for the feedback report, and sorry to disappoint!

For what it's worth, here's my implementation to add a UILargeContentViewerInteraction to a UITabBar without using UITabBarController but inside a custom UIViewController.

Interaction

First, add the interaction to the view of the view controller with the view controller as the interaction delegate.

view.showsLargeContentViewer = true
view.scalesLargeContentImage = true
view.addInteraction(UILargeContentViewerInteraction(delegate: self))

Delegate

It's needed to implement tow function of the UILargeContentViewerInteractionDelegate protocol:

Retrieve Item

Both functions have to get the index of the tab bar item for the point parameter so here's a function to do that:

private func tabItemIndex(for point: CGPoint) -> Int? {
  let convertedPoint = view.convert(point, to: tabBar)
  guard
    tabBar.point(inside: convertedPoint, with: nil),
    let numberOfItems = tabBar.items?.count,
    numberOfItems > 0
  else { return nil }

  let itemWidth = tabBar.bounds.width / CGFloat(numberOfItems)
  return Int(convertedPoint.x / itemWidth)
}

The function converts the point from the view to the tabBar and ensures the point is inside the tabBar. Then the point x member is divided by the width of an item so that every point targets an item.

Large Content Item

For the large content item, the view itself is used. It is configured using the retrieved UITabBarItem:

func largeContentViewerInteraction(
  _: UILargeContentViewerInteraction, 
  itemAt point: CGPoint
) -> (any UILargeContentViewerItem)? {
  guard
    let tabItemIndex = tabItemIndex(for: point),
    let item = tabBar.items?[tabItemIndex]
  else { return nil }

  view.largeContentTitle = item.title
  view.largeContentImage = item.image
  return view
}

Selecting Item

The item is then selected when the interaction ends.

func largeContentViewerInteraction(
  _: UILargeContentViewerInteraction, 
  didEndOn _: (any UILargeContentViewerItem)?, 
  at point: CGPoint
) {
  guard
    let tabItemIndex = tabItemIndex(for: point),
    let item = tabBar.items?[tabItemIndex]
  else { return }

  tabBar.selectedItem = item
  tabBar(tabBar, didSelect: item) // call of UITabBarDelegate
}
How do I enable UILargeContentViewerInteraction on UITabBar outside of UITabBarController?
 
 
Q