ios 获取特定标签栏项目的框架

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6325457/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 20:19:10  来源:igfitidea点击:

Getting the frame of a particular tab bar item

iphoneiosuitabbarcontrolleruitabbaritem

提问by Daniel Dickison

Is there a way to find the frame of a particular UITabBarItemin a UITabBar?

有没有办法找到特定的框架UITabBarItemUITabBar

Specifically, I want to create an animation of an image "falling" into one of the tabs, similar to e.g. deleting an email in the Mail, or buying a track in the iTunes app. So I need the target coordinates for the animation.

具体来说,我想创建一个图像“落入”其中一个选项卡的动画,类似于例如删除邮件中的电子邮件,或在 iTunes 应用程序中购买曲目。所以我需要动画的目标坐标。

As far as I can tell, there's no public API to get the coordinates, but would love to be wrong about that. Short of that, I'll have to guesstimate the coordinates using the index of the given tab relative to the tab bar frame.

据我所知,没有公共 API 来获取坐标,但很想犯错。除此之外,我将不得不使用给定标签相对于标签栏框架的索引来猜测坐标。

回答by Matthias Bauch

Imre's implementation is missing a couple of imho important details.

Imre 的实现缺少一些恕我直言的重要细节。

  1. The UITabBarButton views are not necessarily in order. For example, if you have more than 5 tabs on iPhone and rearranged tabs, the views might be out of order.
  2. If you use more than 5 tabs the out of bounds index only means that the tab is behind the "more" tab. In this case there is no reason to fail with an assert, just use the frame of the last tab.
  1. UITabBarButton 视图不一定按顺序排列。例如,如果您在 iPhone 上有 5 个以上的选项卡并且重新排列了选项卡,则视图可能会乱序。
  2. 如果您使用超过 5 个选项卡,越界索引仅表示该选项卡位于“更多”选项卡后面。在这种情况下,没有理由因断言而失败,只需使用最后一个选项卡的框架即可。

So I changed his code a little bit and I came up with this:

所以我稍微改变了他的代码,我想出了这个:

+ (CGRect)frameForTabInTabBar:(UITabBar*)tabBar withIndex:(NSUInteger)index
{
    NSMutableArray *tabBarItems = [NSMutableArray arrayWithCapacity:[tabBar.items count]];
    for (UIView *view in tabBar.subviews) {
        if ([view isKindOfClass:NSClassFromString(@"UITabBarButton")] && [view respondsToSelector:@selector(frame)]) {
            // check for the selector -frame to prevent crashes in the very unlikely case that in the future
            // objects thar don't implement -frame can be subViews of an UIView
            [tabBarItems addObject:view];
        }
    }
    if ([tabBarItems count] == 0) {
        // no tabBarItems means either no UITabBarButtons were in the subView, or none responded to -frame
        // return CGRectZero to indicate that we couldn't figure out the frame
        return CGRectZero;
    }

    // sort by origin.x of the frame because the items are not necessarily in the correct order
    [tabBarItems sortUsingComparator:^NSComparisonResult(UIView *view1, UIView *view2) {
        if (view1.frame.origin.x < view2.frame.origin.x) {
            return NSOrderedAscending;
        }
        if (view1.frame.origin.x > view2.frame.origin.x) {
            return NSOrderedDescending;
        }
        NSAssert(NO, @"%@ and %@ share the same origin.x. This should never happen and indicates a substantial change in the framework that renders this method useless.", view1, view2);
        return NSOrderedSame;
    }];

    CGRect frame = CGRectZero;
    if (index < [tabBarItems count]) {
        // viewController is in a regular tab
        UIView *tabView = tabBarItems[index];
        if ([tabView respondsToSelector:@selector(frame)]) {
            frame = tabView.frame;
        }
    }
    else {
        // our target viewController is inside the "more" tab
        UIView *tabView = [tabBarItems lastObject];
        if ([tabView respondsToSelector:@selector(frame)]) {
            frame = tabView.frame;
        }
    }
    return frame;
}

回答by Imre Kelényi

The subviews associated with the tab bar items in a UITabBar are of class UITabBarButton. By logging the subviews of a UITabBar with two tabs:

与 UITabBar 中的选项卡栏项关联的子视图属于 UITabBarButton 类。通过使用两个选项卡记录 UITabBar 的子视图:

for (UIView* view in self.tabBar.subviews)
{
    NSLog(view.description);
}

you get:

你得到:

<_UITabBarBackgroundView: 0x6a91e00; frame = (0 0; 320 49); opaque = NO; autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x6a91e90>> - (null)
<UITabBarButton: 0x6a8d900; frame = (2 1; 156 48); opaque = NO; layer = <CALayer: 0x6a8db10>>
<UITabBarButton: 0x6a91b70; frame = (162 1; 156 48); opaque = NO; layer = <CALayer: 0x6a8db40>>

Based on this the solution is kind of trivial. The method I wrote for trying this out is as follows:

基于此,解决方案有点微不足道。我写的尝试这个方法如下:

+ (CGRect)frameForTabInTabBar:(UITabBar*)tabBar withIndex:(NSUInteger)index
{
    NSUInteger currentTabIndex = 0;

    for (UIView* subView in tabBar.subviews)
    {
        if ([subView isKindOfClass:NSClassFromString(@"UITabBarButton")])
        {
            if (currentTabIndex == index)
                return subView.frame;
            else
                currentTabIndex++;
        }
    }

    NSAssert(NO, @"Index is out of bounds");
    return CGRectNull;
}

It should be noted that the structure (subviews) of UITabBar and the class UITabBarButton itself are not part of the public API, so in theory it can change in any new iOS version without prior notification. Nevertheless it is unlikely that they would change such detail, and it works fine with iOS 5-6 and prior versions.

需要注意的是,UITabBar 的结构(子视图)和类 UITabBarButton 本身不是公共 API 的一部分,因此理论上它可以在任何新的 iOS 版本中更改而无需事先通知。尽管如此,他们不太可能改变这样的细节,而且它在 iOS 5-6 和之前的版本中运行良好。

回答by redead

Another possible but sloppy solution would be the following:

另一种可能但草率的解决方案如下:

guard let view = self.tabBarVC?.tabBar.items?[0].valueForKey("view") as? UIView else 
{
    return
}
let frame = view.frame

回答by buildsucceeded

In Swift 4.2:

在 Swift 4.2 中:

private func frameForTab(atIndex index: Int) -> CGRect {
    var frames = view.subviews.compactMap { (view:UIView) -> CGRect? in
        if let view = view as? UIControl {
            return view.frame
        }
        return nil
    }
    frames.sort { 
extension UITabBar {

    func getFrameForTabAt(index: Int) -> CGRect? {
        var frames = self.subviews.compactMap { return 
for (UIView* view in self.tabBar.subviews)
    {
        if( [view isUserInteractionEnabled] )
        {
            [myMutableArray addObject:view];
        }
}
is UIControl ?
-(UIView*)viewForTabBarItemAtIndex:(NSInteger)index {

    CGRect tabBarRect = self.tabBarController.tabBar.frame;
    NSInteger buttonCount = self.tabBarController.tabBar.items.count;
    CGFloat containingWidth = tabBarRect.size.width/buttonCount;
    CGFloat originX = containingWidth * index ;
    CGRect containingRect = CGRectMake( originX, 0, containingWidth, self.tabBarController.tabBar.frame.size.height );
    CGPoint center = CGPointMake( CGRectGetMidX(containingRect), CGRectGetMidY(containingRect));
    return [ self.tabBarController.tabBar hitTest:center withEvent:nil ];
}
.frame : nil } frames.sort {
private func frameForTabAtIndex(index: Int) -> CGRect {
    guard let tabBarSubviews = tabBarController?.tabBar.subviews else {
        return CGRect.zero
    }
    var allItems = [UIView]()
    for tabBarItem in tabBarSubviews {
        if tabBarItem.isKind(of: NSClassFromString("UITabBarButton")!) {
            allItems.append(tabBarItem)
        }
    }
    let item = allItems[index]
    return item.superview!.convert(item.frame, to: view)
}
.origin.x < .origin.x } return frames[safe: index] } } extension Collection { subscript (safe index: Index) -> Element? { return indices.contains(index) ? self[index] : nil } }
.origin.x < .origin.x } if frames.count > index { return frames[index] } return frames.last ?? CGRect.zero }

回答by Lausbert

By Extending UITabBar

通过扩展 UITabBar

guard let tab1frame = self.tabBar.items![0].value(forKey: "view") as? UIView else {return}

回答by TigerCoding

Tab bar buttons are the only sub views that have user interaction enabled. Check for this instead of UITabBarButton to avoid violating hidden API's.

标签栏按钮是唯一启用了用户交互的子视图。检查这个而不是 UITabBarButton 以避免违反隐藏的 API。

let tab1CentreXanc = tab1frame.centerXAnchor
let tab1CentreY = tab1frame.centerYAnchor
let tab1FRAME = tab1frame (centerX and Y and other parameters such as ".origins.x or y"

Once in the array, sort it based on the origin x, and you will have the tab bar buttons in their true order.

进入数组后,根据原点 x 对其进行排序,您将获得按其真实顺序排列的选项卡栏按钮。

回答by maksa

I'll add what worked for me in my simple UITabBarController scenario, everything is legit but it has an assumption that items are spaced equally. Under iOS7 it returns an instance of an UITabBarButton, but if you'll be using it as UIView* you really don't care what it is and you aren't stating the class explicitly. The frame of the returned view is the frame you're looking for:

我将在我的简单 UITabBarController 场景中添加对我有用的东西,一切都是合法的,但它假设项目间隔相等。在 iOS7 下,它返回一个 UITabBarButton 的实例,但如果你将它用作 UIView*,你真的不关心它是什么,而且你没有明确说明类。返回视图的框架是您要查找的框架:

##代码##

What it does is calculate the rect in the UITabBar where the button resides, finds the center of this rect and digs out the view at that point via hitTest:withEvent.

它的作用是计算按钮所在的 UITabBar 中的矩形,找到该矩形的中心并通过 hitTest:withEvent 挖掘出该点的视图。

回答by Phil

Swift + iOS 11

斯威夫特 + iOS 11

##代码##

回答by MFK

Swift 5:

斯威夫特 5:

Just put this in your View Controller that handles your tabBar.

只需将它放在处理 tabBar 的视图控制器中。

##代码##

then use like so:

然后像这样使用:

##代码##

Hope that helps.

希望有帮助。

If you want to reference the parameters from other tabs, just change the index from [0] to whatever you want

如果您想从其他选项卡中引用参数,只需将索引从 [0] 更改为您想要的任何值

回答by Rush B

When initializing a tab bar, give it a tag:

当初始化标签栏,给它一个标签:

let tabItem = UITabBarItem(title: "my title", image: nil, tag: 1000)

let tabItem = UITabBarItem(title: "my title", image: nil, tag: 1000)

Then you can fetch the tab bar using:

然后您可以使用以下方法获取标签栏:

let myTabItem = tabBarController?.tabBar.viewWithTag(1000)

let myTabItem = tabBarController?.tabBar.viewWithTag(1000)