web-dev-qa-db-ja.com

特定のタブバーアイテムのフレームを取得する

UITabBarItemで特定のUITabBarのフレームを見つける方法はありますか?

具体的には、タブの1つに「落ちる」画像のアニメーションを作成します。メールでメールを削除するか、iTunesアプリでトラックを購入する。したがって、アニメーションのターゲット座標が必要です。

私の知る限りでは、座標を取得するためのパブリックAPIはありませんが、それについて誤解したいと思います。その前に、タブバーフレームに対する特定のタブのインデックスを使用して座標を推測する必要があります。

35
Daniel Dickison

Imreの実装には、2つの重要な詳細が欠けています。

  1. UITabBarButtonビューは必ずしも順序付けられていません。たとえば、iPhoneに5つ以上のタブがあり、タブが再配置されている場合、ビューが乱れる可能性があります。
  2. 5つを超えるタブを使用する場合、範囲外インデックスは、タブが「詳細」タブの背後にあることを意味します。この場合、アサートで失敗する理由はありません。最後のタブのフレームを使用してください。

だから私は彼のコードを少し変更し、これを思いつきました:

+ (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;
}
25
Matthias Bauch

UITabBarのタブバー項目に関連付けられているサブビューは、UITabBarButtonクラスです。 2つのタブを持つUITabBarのサブビューをログに記録することにより:

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

あなたが得る:

<_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>>

これに基づくと、解決策は簡単なものです。これを試すために私が書いた方法は次のとおりです。

+ (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;
}

UITabBarの構造(サブビュー)とクラスUITabBarButton自体はパブリックAPIの一部ではないため、理論的には事前通知なしに新しいiOSバージョンで変更される可能性があることに注意してください。それでも、そのような詳細が変更される可能性は低く、iOS 5-6以前のバージョンでは問題なく機能します。

17
Imre Kelényi

別の可能ながずさんな解決策は次のようになります:

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

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 { $0.Origin.x < $1.Origin.x }
    if frames.count > index {
        return frames[index]
    }
    return frames.last ?? CGRect.zero
}
10
buildsucceeded

UITabBarを拡張する

extension UITabBar {

    func getFrameForTabAt(index: Int) -> CGRect? {
        var frames = self.subviews.compactMap { return $0 is UIControl ? $0.frame : nil }
        frames.sort { $0.Origin.x < $1.Origin.x }
        return frames[safe: index]
    }

}

extension Collection {

    subscript (safe index: Index) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }

}
7
Lausbert

タブバーボタンは、ユーザー操作が有効になっている唯一のサブビューです。非表示のAPIに違反しないようにするには、UITabBarButtonの代わりにこれを確認してください。

for (UIView* view in self.tabBar.subviews)
    {
        if( [view isUserInteractionEnabled] )
        {
            [myMutableArray addObject:view];
        }
}

配列に入ると、Origin xに基づいて並べ替えると、タブバーボタンが正しい順序で配置されます。

5
TigerCoding

私の単純なUITabBarControllerシナリオで機能したものを追加します。すべてが合法ですが、項目の間隔が等しいことが前提となっています。 iOS7では、UITabBarButtonのインスタンスを返しますが、UIView *として使用する場合は、それが何であるかを気にせず、クラスを明示的に指定していません。返されたビューのフレームは、探しているフレームです。

-(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 ];
}

それが行うことは、ボタンが存在するUITabBarで四角形を計算し、この四角形の中心を見つけ、その時点でビューをhitTest:withEventを介して掘り下げることです。

3
maksa

Swift + iOS 11

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)
}
2
Phil

Swift 5:

これを、タブバーを処理するビューコントローラーに配置するだけです。

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

次にそのように使用します:

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

お役に立てば幸いです。

他のタブからパラメータを参照する場合は、インデックスを[0]から好きなものに変更してください

1
MFK

タブバーを初期化するとき、それにタグを付けます:

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

次に、以下を使用してタブバーを取得できます。

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

0
Rush B

プライベートAPIは必要ありません。UITabbarプロパティitemWidthおよびitemSpacingを使用してください。これらの2つの値を次のように設定します。

NSInteger tabBar.itemSpacing = 10; tabBar.itemWidth = ([UIScreen mainScreen].bounds.size.width - self.tabBarController.tabBar.itemSpacing * (itemsCount - 1)) /itemsCount;

これは、UITabBarItemに使用される画像とタイトルのサイズまたは位置には影響しません。

そして、次のようにithアイテムの中心xを取得できます。

CGFloat itemCenterX = (tabBar.itemWidth + tabBar.itemSpacing) * ith + tabBar.itemWidth / 2;

0
Bigyelow